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_construction,[reset_bmachine_construction/0,
6 check_machine/4,
7 type_in_machine_l/6,
8 type_open_predicate_with_quantifier/6,
9 get_constructed_machine_name/2, get_constructed_machine_name_and_filenumber/3,
10 type_open_formula/8,
11 filter_linking_invariant/3,
12 machine_promotes_operations/2,
13 external_procedure_used/1,
14 dummy_machine_name/2]).
15
16 :- use_module(module_information,[module_info/2]).
17 :- module_info(group,typechecker).
18 :- module_info(description,'This module contains the rules for loading, including, seeing, etc. B machines, scope of constants, variables, parameters, etc.').
19
20 :- use_module(library(lists)).
21 :- use_module(library(avl)).
22
23 :- use_module(self_check).
24 :- use_module(tools).
25 :- use_module(error_manager).
26 :- use_module(debug).
27 :- use_module(preferences).
28
29 :- use_module(btypechecker).
30 :- use_module(b_ast_cleanup).
31 :- use_module(bsyntaxtree).
32 :- use_module(bmachine_structure).
33 :- use_module(pragmas).
34 :- use_module(b_global_sets,[register_enumerated_sets/2]).
35
36 :- use_module(bmachine_static_checks).
37 :- use_module(tools_lists,[ord_member_nonvar_chk/2, remove_dups_keep_order/2]).
38
39 :- use_module(translate,[print_machine/1]).
40
41
42 :- set_prolog_flag(double_quotes, codes).
43
44 %maximum_type_errors(100).
45
46 :- dynamic debug_machine/0.
47
48 :- use_module(pref_definitions,[b_get_important_preferences_from_raw_machine/2]).
49 set_important_prefs_from_machine(Main,Machines) :-
50 find_machine(Main,Machines,_MType,_Header,RawMachine),
51 ? get_raw_model_type(Main,Machines,RawModelType),
52 b_get_important_preferences_from_raw_machine(RawMachine,RawModelType).
53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
54
55 :- use_module(preferences,[temporary_set_preference/3,reset_temporary_preference/2]).
56
57 % typecheck complete machines (incl. includes)
58 check_machine(MainName,MachinesMayContainGenerated,Result,FinalErrors) :-
59 clear_warnings,
60 debug_println(9,checking_machine(MainName)),
61 temporary_set_preference(perform_stricter_static_checks,true,CHNG),
62 strip_global_pragmas(MachinesMayContainGenerated,Machines,_WasGenerated), % TODO: is generated still used?
63 ? set_important_prefs_from_machine(MainName,Machines), % set important prefs before type-checking,...
64 check_main_machine_file_origin(MainName,Machines),
65 % we need to find all SEES/USES declarations, because all references
66 % refer to the same machine and that has to be included exactly once.
67 ? find_uses(Machines,Uses,NotIncluded,Errors,E1),
68 % if a seen/used machine was not included, we include it by constructing
69 % a dummy machine that extends the seen/used machine and the origional
70 % main machine
71 extend_not_included_uses(NotIncluded,MainName,NewMainName,Machines,IMachines),
72 % figure out the right order of machines, so that each machine is
73 % type-checked before a dependend machine is loaded
74 machine_order(IMachines,Order),
75 assert_machine_order(Order),
76 % expand (= type-check + includes) machines in the given order
77 expand_machines(Order,IMachines,Uses,[],Results1,E1,E2),
78 % until now, the initialisation section consists of a list of init(MachineName,Substitution)
79 % fold_initialisation merges those to one substitution, respecting the dependencies
80 % between the machines
81 ? maplist(fold_initialisation(Order),Results1,Results),
82 % find main machine
83 memberchk(machine(NewMainName,MainMachine),Results), %nl,print('MAIN:'),nl,print_machine(MainMachine),
84 % if the main machine has parameters, we convert them to global sets resp. constants
85 convert_parameters_to_global_sets(E2,[],MainMachine,Result1),
86 % add some additional informations about the machine
87 ? add_machine_infos(MainName,Machines,Results,Result1,Result),
88 ( debug_machine -> print_machine(Result); true),
89 %% comment in to pretty print all machines:
90 %( member(machine(Name,Mchx),Results), format('~n*** Machine ~w~n',[Name]), print_machine(Mchx),nl,fail ; true),
91 % finalize the list of errors, remove duplicates
92 sort(Errors,FinalErrors),
93 % output warnings
94 show_warnings,
95 % run static checks on the resulting machine
96 static_check_main_machine(Result),
97 reset_temporary_preference(perform_stricter_static_checks,CHNG).
98 check_machine(Main,_,Result,FinalErrors) :-
99 add_internal_error('Internal error: Checking the machine failed: ',
100 check_machine(Main,_,Result,FinalErrors)),
101 fail.
102
103 strip_global_pragmas([],[],false).
104 strip_global_pragmas([generated(POS,M)|Ms],MachinesOut,true) :- !, % @generated pragma used at top of file
105 assertz(pragmas:global_pragma(generated,POS)),
106 strip_global_pragmas([M|Ms],MachinesOut,_).
107 strip_global_pragmas([unit_alias(_,Alias,Content,M)|Ms],MachinesOut,true) :- !,
108 assertz(pragmas:global_pragma(unit_alias,[Alias|Content])),
109 strip_global_pragmas([M|Ms],MachinesOut,_).
110 strip_global_pragmas([M|Ms],[M|SMs],WasGenerated) :-
111 strip_global_pragmas(Ms,SMs,WasGenerated).
112
113 fold_initialisation(Order,machine(Name,Sections),machine(Name,NewSections)) :-
114 select_section(initialisation,List,Subst,Sections,NewSections),
115 maplist(extract_init_substitutions(List),Order,LSubstitutions),
116 append(LSubstitutions,Substitutions),
117 ? create_sequence(Substitutions,Subst).
118 extract_init_substitutions(Unsorted,Name,Substitutions) :-
119 convlist(unzip_init(Name),Unsorted,Substitutions).
120 unzip_init(Name,init(Name,Subst),Subst).
121 create_sequence([],Subst) :- create_texpr(skip,subst,[generated],Subst).
122 create_sequence([I],I) :- !.
123 create_sequence(L,Sequence) :-
124 (L = [First|_], get_texpr_info(First,AllInfos), extract_pos_infos(AllInfos,Pos) -> true ; Pos=[]),
125 % TODO: try and merge first and last position info
126 create_texpr(sequence(L),subst,[initial_sequence|Pos],Sequence).
127
128 add_machine_infos(MainName,Machines,CheckedMachines,Old,New) :-
129 ? get_raw_model_type(MainName,Machines,RawModelType), functor(RawModelType,ModelType,_), % argument is position
130 % model type could be machine or system (or model ?)
131 append_to_section(meta,[model_type/ModelType,hierarchy/Hierarchy,header_pos/HeaderPosList],Old,NewT),
132 get_refinement_hierarchy(MainName,Machines,Hierarchy),
133 find_machine_header_positions(Machines,HeaderPosList),
134 ? add_refined_machine(Hierarchy,CheckedMachines,NewT,New).
135 get_refinement_hierarchy(Main,Machines,[Main|Abstractions]) :-
136 ( find_refinement(Machines,Main,Abstract) ->
137 get_refinement_hierarchy(Abstract,Machines,Abstractions)
138 ;
139 Abstractions = []).
140 find_refinement([M|Rest],Name,Abstract) :-
141 ( get_constructed_machine_name(M,Name) ->
142 refines(M,Abstract)
143 ;
144 find_refinement(Rest,Name,Abstract)).
145
146 find_machine_header_positions(Machines,SRes) :-
147 Header = machine_header(Pos,_Nm,_Paras),
148 findall(Name/Pos,find_machine(Name,Machines,_Type,Header,_Sections),Res),
149 sort(Res,SRes).
150
151 :- use_module(specfile,[animation_minor_mode/1]).
152 % check whether the main machine has filenumber 1; if not something strange is going on.
153 % an example can be found in prob_examples/public_examples/B/ErrorMachines/IllegalSeesIncludes/WrongNameM1.mch
154 check_main_machine_file_origin(MainName,Machines) :-
155 ? member(M,Machines), get_machine_parameters(M,MainName,_,Position),
156 !,
157 (Position = none -> true
158 ; get_nr_name(Position,Number,Name)
159 -> (Number=1 -> true
160 ; ajoin(['Main machine name ',MainName,' overriden by machine in file ',Number,' :'],Msg),
161 add_error(bmachine_construction,Msg,Name,Position))
162 ; add_error(bmachine_construction,'Could not extract file number and name:',Position)
163 ).
164 check_main_machine_file_origin(MainName,_) :-
165 add_error(bmachine_construction,'Could not extract file number and name for main machine:',MainName).
166 get_nr_name(none,Nr,Name) :- !, Nr=1,Name=none.
167 get_nr_name(1,Nr,Name) :- !, Nr=1,Name=none. % TLA mode, animation_minor_mode(tla) not yet set and positions are numbers
168 get_nr_name(Position,Number,Name) :- extract_file_number_and_name(Position,Number,Name).
169
170 add_refined_machine([_Main,Refined|_],Machines,Old,New) :-
171 ? member(machine(Refined,Body),Machines),
172 append_to_section(meta,[refined_machine/Body],Old,New).
173 add_refined_machine(_,_,M,M). % not refining
174
175 convert_parameters_to_global_sets(Ein,Eout) -->
176 % extract and remove parameters and constraints
177 select_section(parameters,PP,[]),
178 select_section(internal_parameters,IP,[]),
179 {create_texpr(truth,pred,[],Truth)},
180 select_section(constraints,C,Truth),
181 % split parameters into sets and scalars
182 { split_list(is_set_parameter,PP,Sets,Scalars),
183 foldl(type_set_parameter,Sets,Ein,Eout) },
184 % put the sets to the deferred sets
185 append_to_section(deferred_sets,Sets),
186 % and the scalars to the constants
187 append_to_section(concrete_constants,Scalars),
188 append_to_section(concrete_constants,IP),
189 % the scalars should be typed by constraints,
190 % so move the constraints to the properties
191 select_section(properties,OldProps,NewProps),
192 {conjunct_predicates([C,OldProps],NewProps)}.
193 is_set_parameter(TExpr) :-
194 % upper case identifiers denote set parameters, otherwise scalars
195 get_texpr_id(TExpr,Name),is_upper_case(Name).
196 type_set_parameter(TExpr,Ein,Eout) :-
197 get_texpr_id(TExpr,Name),
198 get_texpr_type(TExpr,Type),
199 get_texpr_pos(TExpr,Pos),
200 % we directly type the deferred set
201 unify_types_werrors(set(global(Name)),Type,Pos,'PARAMETER',Ein,Eout).
202
203
204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205 % included machines
206
207 expand_machines([],_,_,M,M,Errors,Errors).
208 expand_machines([M|Rest],Machines,Uses,Typed,Result,Ein,Eout) :-
209 ? ( expand_machine(M,Machines,Uses,Typed,New,Ein,E1) -> true
210 ; add_error(bmachine_construction,'Expansion of machine failed:',M),fail),
211 expand_machines(Rest,Machines,Uses,[machine(M,New)|Typed],Result,E1,Eout).
212
213 % resolve all includes and typecheck the machine
214 % expand_machine(Name,Machines,TypeChecked,Expanded) :
215 % Name of the Machine to expand
216 % Machines contains the list of all loaded machines
217 % TypeChecked contains the list of all expanded machines so far
218 % Expanded is the resulting machine
219 expand_machine(Name,Machines,GlobalUses,TypeChecked,Expanded,Ein,Eout) :-
220 % find the machine in the list
221 find_machine(Name,Machines,MType,Header,RawMachineWithPragmas),
222 % remove pragmas for later reattachment
223 strip_machine_section_pragmas(RawMachineWithPragmas,RawMachine,_Pragmas),
224 % look for abstract machine
225 get_abstractions(Name,Machines,TypeChecked,Abstractions),
226 % merge all used and seen machines
227 ? use_and_see_machines(RawMachine,TypeChecked,SeenRefs),
228 % merge all included machines into one machine
229 ? include_machines(RawMachine, TypeChecked, GlobalUses, Includes, Parameters, Included, Promotes),
230 % Parameters contains now a list of parameters for each included machine
231 % Included contains now a machine that represents all included machines
232 % their parameters are renamed to internal_parameters
233 append([Abstractions,Included,SeenRefs],RefMachines),
234 % typecheck this machine
235 debug_stats(type_machine(Name)),
236 ? type_machine(Header,Name,MType,RawMachine,RefMachines,TypedLocal,RefMachines2,Ein,Err1),
237 % merge included and including machine
238 debug_stats(merge_included_machines(Name)),
239 merge_included_machines(Name,TypedLocal,Included,Promotes,Expanded2,Err1,Err2),
240 % add some predicates that state the equivalence between arguments
241 % in the include statement and the parameters of the included machine
242 add_link_constraints(Includes,MType,Parameters,RefMachines2,Expanded2,Expanded3,Err2,Err3),
243 % put together refinement and abstraction.
244 ? merge_refinement_and_abstraction(Expanded3,[ref(local,TypedLocal)|RefMachines2],Expanded4,Err3,Eout),
245 % merge used machines, will also prefix
246 debug_stats(merge_used_machines(Name)),
247 merge_used_machines(Included,Expanded4,Expanded5),
248 % clean up the syntax tree
249 debug_stats(clean_up_machine(Name)),
250 clean_up_machine(Expanded5,RefMachines2,Expanded),
251 debug_stats(finished_clean_up_and_expand_machine(Name)).
252
253 strip_machine_section_pragmas(RawMachineWithPragmas,RawMachine,Pragmas) :-
254 selectchk(units(_Pos,RealVariables,Pragmas),RawMachineWithPragmas,TRawMachine), !,
255 RawMachine = [RealVariables|TRawMachine].
256 strip_machine_section_pragmas(Machine,Machine,[]).
257
258 merge_included_machines(Name, TypedLocal, RefMachines, Promotes, Merged, Ein, Eout) :-
259 (Promotes=[] -> true ; assertz(machine_promotes_operations(Name,Promotes))),
260 include(is_included_ref,RefMachines,Included),
261 create_machine(Name,Empty),
262 % move the included operations into the promoted or unpromoted section
263 move_operations(Included,Promotes,Included2,Ein,Eout),
264 LocalAndIncluded = [ref(local,TypedLocal)|Included2],
265 % TODO: make sure that the constants of two instances of the same machine do not repeat (check what should be done for distinct machines with same identifiers)
266 concat_sections_of_refs([identifiers,initialisation,operation_bodies,
267 assertions,used,values],LocalAndIncluded,Empty,Merged1),
268 conjunct_sections_of_refs([constraints,properties,invariant],LocalAndIncluded,Merged1,Merged2),
269 concat_section_of_simple_lists(freetypes,LocalAndIncluded,Merged2,Merged3),
270 get_section(definitions,TypedLocal,Defs),
271 write_section(definitions,Defs,Merged3,Merged).
272 is_included_ref(ref(included,_)).
273
274 concat_section_of_simple_lists(Sec,References,In,Out) :-
275 maplist(extract_machine_from_ref,References,Machines),
276 sort_machines_by_global_order(Machines,OMachines),
277 foldl(concat_section_of_simple_lists2(Sec),OMachines,In,Out).
278 concat_section_of_simple_lists2(Sec,Machine,In,Out) :-
279 get_section(Sec,In,Orig),
280 get_section(Sec,Machine,List),
281 append(Orig,List,NewList),
282 write_section(Sec,NewList,In,Out).
283
284 merge_used_machines(RefMachines,Old,New) :-
285 % get all included machines from the references
286 convlist(ref_to_included_machine,RefMachines,Included),
287 foldl(merge_used_machines2,Included,Old,New).
288 merge_used_machines2(Included,Old,New) :-
289 get_section(used,Included,IncludedUse),
290 (IncludedUse = [] -> New = Old ; rename_used(IncludedUse,Old,New)).
291 ref_to_included_machine(ref(included,Inc),Inc).
292
293 % will add prefixes to identifiers
294 rename_used(IncludedUse,Old,New) :-
295 %print(renaming(IncludedUse)),nl,
296 expand_shortcuts([properties,invariant, assertions,
297 initialisation,operation_bodies],Sections), % TO DO: also traverse GOAL ? should we later apply this at the REPL level as well ? should we apply it to other DEFINITIONS ?
298 foldl(rename_used_sec(IncludedUse),Sections,Old,New).
299 rename_used_sec(IncludedUse,Sec,Old,New) :-
300 select_section_texprs(Sec,TExprs,NewTExprs,Old,New),
301 rename_used2_l(TExprs,IncludedUse,NewTExprs).
302
303 rename_used2(TExpr,IncludedUse,NewTExpr) :-
304 get_texpr_expr(TExpr,operation(Id,Params,Results,Subst)),!,
305 rename_used2_l(Params,IncludedUse,NParams),
306 rename_used2_l(Results,IncludedUse,NResults),
307 rename_used2(Subst,IncludedUse,NSubst),
308 get_texpr_type(TExpr,Type),
309 get_texpr_info(TExpr,Info),
310 selectchk(modifies(MIn),Info,Info1),selectchk(reads(RIn),Info1,RestInfo),
311 rename_used_ids(MIn,IncludedUse,MOut),
312 rename_used_ids(RIn,IncludedUse,ROut),
313 create_texpr(operation(Id,NParams,NResults,NSubst),Type,[modifies(MOut),reads(ROut)|RestInfo],
314 NewTExpr).
315 rename_used2(TExpr,IncludedUse,NewTExpr) :-
316 % rename identifier by adding machine prefix M.id
317 get_texpr_id(TExpr,_), % result is also Id (always ??)
318 get_texpr_info(TExpr,Info),
319 ? member(usesee(Name,Id,_Mode),Info),
320 ? member(includeduse(Name,Id,NewTExpr),IncludedUse), % This seems to reuse position information from includeduse list for all identifiers !! TO DO: check this
321 % we now rename Id to Name.Id
322 !. %, print(ren_id(Name,Id)),nl.
323 rename_used2(TExpr,IncludedUse,NTExpr1) :-
324 remove_bt(TExpr,Expr,NExpr,NTExpr),
325 ? syntaxtransformation(Expr,Subs,_,NSubs,NExpr),!,
326 rename_used2_l(Subs,IncludedUse,NSubs),
327 rename_infos(NTExpr,IncludedUse,NTExpr1).
328 rename_used2(TExpr,IncludedUse,NTExpr) :-
329 add_internal_error('Rename failed: ',rename_used2(TExpr,IncludedUse,NTExpr)),
330 NTExpr = TExpr.
331
332 % update infos, e.g., read/modifies for while loops
333 rename_infos(b(E,T,I),List,b(E,T,NI)) :- maplist(rename_info(List),I,NI).
334
335 rename_info(IncludeUseList,Info,NewInfo) :- info_field_contains_ids(Info,I,NewInfo,SNI),!,
336 maplist(rename_usage_info(IncludeUseList),I,NI), sort(NI,SNI).
337 rename_info(_,I,I).
338
339 info_field_contains_ids(reads(I),I,reads(SNI),SNI).
340 info_field_contains_ids(modifies(I),I,modifies(SNI),SNI).
341 info_field_contains_ids(non_det_modifies(I),I,non_det_modifies(SNI),SNI).
342 info_field_contains_ids(modifies_locals(I),I,modifies_locals(SNI),SNI).
343 info_field_contains_ids(reads_locals(I),I,reads_locals(SNI),SNI).
344 info_field_contains_ids(used_ids(I),I,used_ids(SNI),SNI).
345
346 rename_usage_info(IncludeUseList,ID,NewID) :-
347 ? (member(includeduse(_,ID,NewTExpr),IncludeUseList) -> get_texpr_id(NewTExpr,NewID) ; NewID = ID).
348
349
350 rename_used2_l([],_,R) :- !, R=[].
351 rename_used2_l([T|Rest],IncludedUse,[NT|NRest]) :-
352 rename_used2(T,IncludedUse,NT), !,
353 rename_used2_l(Rest,IncludedUse,NRest).
354 rename_used2_l(X,Y,Z) :- add_internal_error('Rename failed: ', rename_used2_l(X,Y,Z)),Z=X.
355
356 rename_used_ids(InIds,IncludedUse,OutIds) :-
357 maplist(rename_used_ids2(IncludedUse),InIds,OutIds).
358 rename_used_ids2(IncludedUse,InId,OutId) :-
359 memberchk(includeduse(_,InId,TOutId),IncludedUse),!,
360 get_texpr_id(TOutId,OutId).
361 rename_used_ids2(_IncludedUse,Id,Id).
362
363 get_abstractions(CName,Machines,TypedMachines,[ref(abstraction,Abstraction)]) :-
364 ? refines(M,AName),
365 get_constructed_machine_name(M,CName),
366 memberchk(M,Machines),!,
367 memberchk(machine(AName,Abstraction),TypedMachines).
368 get_abstractions(_,_,_,[]).
369
370 get_includes_and_promotes(Sections,M,Includes,Promotes) :-
371 optional_rawmachine_section(includes,Sections,[],Includes1),
372 optional_rawmachine_section(imports,Sections,[],Imports),
373 optional_rawmachine_section(extends,Sections,[],Extends),
374 optional_rawmachine_section(promotes,Sections,[],Promotes1),
375 append([Includes1,Extends,Imports],Includes),
376 ? maplist(expand_extends(M),Extends,Promotes2),
377 append([Promotes1|Promotes2],Promotes).
378 expand_extends(Machines,machine_reference(_,Ref,_),Promotes) :-
379 split_prefix(Ref,Prefix,Name),
380 memberchk(machine(Name,Body),Machines),
381 get_section(promoted,Body,Promoted),
382 prefix_identifiers(Promoted,Prefix,Renamings),
383 ? rename_bt_l(Promoted,Renamings,TPromotes),
384 maplist(add_nonpos,TPromotes,Promotes).
385 add_nonpos(TId,identifier(none,Id)) :-
386 get_texpr_id(TId,op(Id)).
387
388 move_operations([],Promotes,[],Ein,Eout) :-
389 foldl(add_promotes_not_found_error,Promotes,Ein,Eout).
390 move_operations([ref(_,IncMachine)|IncRest],Promotes,[ref(included,NewIncMachine)|RefRest],Ein,Eout) :-
391 move_operations2(IncMachine,Promotes,NewIncMachine,RestPromotes),
392 move_operations(IncRest,RestPromotes,RefRest,Ein,Eout).
393 move_operations2(Included,Promotes,Result,RestPromotes) :-
394 select_section(promoted,IncOperations,Promoted,Included,Included1),
395 select_section(unpromoted,OldUnpromoted,Unpromoted,Included1,Result),
396 filter_promoted(IncOperations,Promotes,Promoted,NewUnpromoted,RestPromotes),
397 append(OldUnpromoted,NewUnpromoted,Unpromoted).
398 filter_promoted([],Promotes,[],[],Promotes).
399 filter_promoted([TExpr|OpsRest],Promotes,Promoted,Unpromoted,RestPromotes) :-
400 get_texpr_id(TExpr,op(P)),
401 ? ( select(identifier(_,P),Promotes,RestPromotes1) ->
402 !,Promoted = [TExpr|RestPromoted],
403 Unpromoted = RestUnpromoted
404 ;
405 RestPromotes1 = Promotes,
406 Promoted = RestPromoted,
407 Unpromoted = [TExpr|RestUnpromoted]),
408 filter_promoted(OpsRest,RestPromotes1,RestPromoted,RestUnpromoted,RestPromotes).
409 add_promotes_not_found_error(identifier(Pos,Id),[error(Msg,Pos)|E],E) :-
410 ajoin(['Promoted operation ',Id,' not found'],Msg).
411
412 find_machine(Name,Machines,Type,Header,Sections) :-
413 Header = machine_header(_,Name,_),
414 ? ( (member(abstract_machine(_,_ModelType,Header,Sections),Machines),
415 Type=machine)
416 ? ; (member(refinement_machine(_,Header,_Abstract,Sections),Machines),
417 Type=refinement)
418 ? ; (member(implementation_machine(_,Header,_Abstract,Sections),Machines),
419 Type=implementation)),
420 !.
421
422 include_machines(RawMachine, TypeChecked, GlobalUses, Includes, Parameters, Included, Promotes) :-
423 ? get_includes_and_promotes(RawMachine,TypeChecked,Includes,Promotes),
424 ? maplist(include_machine(TypeChecked, GlobalUses), Includes, Parameters, Singles),
425 remove_duplicate_set_inclusions(Singles,Singles1),
426 % duplicate constants inclusion is handled currently in concat_section_contents via section_can_have_duplicates
427 % create refs
428 maplist(create_ref,Singles1,Included).
429 create_ref(IncMachine,ref(included,IncMachine)).
430
431 % it is possible that a deferred or enumerated set is declared in an included machine
432 % that is included more than once. We remove all but one occurrences.
433 remove_duplicate_set_inclusions([],[]).
434 remove_duplicate_set_inclusions([M],[M]) :- !.
435 remove_duplicate_set_inclusions([M|Rest],[M|CleanedRest]) :-
436 get_section(deferred_sets,M,DSets),
437 get_section(enumerated_sets,M,ESets),
438 get_section(enumerated_elements,M,EElements),
439 append([DSets,ESets,EElements],Identifiers),
440 sort(Identifiers,SortedIds),
441 maplist(remove_duplicate_sets2(SortedIds),Rest,Rest2),
442 remove_duplicate_set_inclusions(Rest2,CleanedRest).
443 remove_duplicate_sets2(Identifiers,M,Cleaned) :-
444 remove_duplicate_sets_section(deferred_sets,Identifiers,M,M1),
445 remove_duplicate_sets_section(enumerated_sets,Identifiers,M1,M2),
446 remove_duplicate_sets_section(enumerated_elements,Identifiers,M2,Cleaned).
447 remove_duplicate_sets_section(Section,Identifiers,In,Out) :-
448 select_section(Section,Old,New,In,Out),
449 %get_texpr_ids(Identifiers,II),format('Removing duplicates ~w = ~w~n',[Section,II]),
450 exclude(element_is_duplicate(Identifiers),Old,New).
451
452 element_is_duplicate(Identifiers,TId) :-
453 get_texpr_id(TId,Name),
454 get_texpr_type(TId,Type),
455 get_texpr_id(ToRemove,Name),
456 get_texpr_type(ToRemove,Type),
457 ord_member_nonvar_chk(ToRemove,Identifiers),
458 get_texpr_info(TId,InfosA),
459 get_texpr_info(ToRemove,InfosB),
460 member(def(Sec,File),InfosA),
461 member(def(Sec,File),InfosB),
462 debug_format(5,'Removed duplicate included identifier: ~w~n',[Name]),
463 !.
464
465 include_machine(TypeChecked,Used,machine_reference(_Pos,FullRef,_Args),
466 parameters(FullRef,Parameters), TM) :-
467 split_prefix(FullRef,Prefix,Name),
468 % TM1 is the already typechecked included machine:
469 ? member(machine(Name,TM1),TypeChecked),!,
470 debug_println(9,including_machine(Name)),
471 % TM2 is a fresh copy, so we prevent unification of the parameter types:
472 (get_section(parameters,TM1,[]) -> TM2=TM1
473 ; copy_term(TM1,TM2) % this can be expensive; only copy if there are parameters
474 ),
475 % If the included machine is used somewhere, we store the identifiers
476 % to enable joining the different references later:
477 include_usings(Name,Used,TM2,TM3),
478 % TM3 is typechecked and all internal variables are renamed with a prefix
479 ? hide_private_information(FullRef,TM3,TM4),
480 % TM4 is typechecked, and if it was referenced with a prefix (e.g. INCLUDES p.M2)
481 % all variables are prefixed
482 %print(prefixing(Prefix)),nl,
483 prefix_machine(Prefix,TM4,TM5),
484 % We need the parameters later to state their equivilance to the arguments
485 get_section(parameters,TM5,Parameters),
486 % We move the parameters to the internal parameters, because the resulting
487 % machine has only the parameters of the including machine.
488 parameters_to_internal(TM5,TM).
489
490 include_usings(Name,Uses,Old,New) :-
491 ? ( member(Name,Uses) ->
492 store_usage_info(Old,Name,UsedInfo),
493 append_to_section(used,UsedInfo,Old,New)
494 ;
495 Old = New).
496 % returns a list of which identifiers are used in the machine
497 % for each identifier, we have a trible includeuse(Name,Id,TExpr)
498 % where Name is the name of the used machine, Id is the
499 % original ID and TExpr is the currently used reference to this
500 % identifier
501 store_usage_info(Machine,Name,UsedInfo) :-
502 expand_shortcuts([identifiers],IdSections),
503 foldl(store_usage_info2(Machine,Name),IdSections,UsedInfo,[]).
504 store_usage_info2(Machine,Name,Sec,I,O) :-
505 get_section(Sec,Machine,Content),
506 foldl(store_usage_info3(Name),Content,I,O).
507 store_usage_info3(Name,TId,[includeduse(Name,Id,TId)|L],L) :-
508 get_texpr_id(TId,Id).
509
510 % conjunct sections that contain predicates (CONSTRAINTS, PROPERTIES, INVARIANT)
511 conjunct_sections_of_refs(Sections1,References,Old,New) :-
512 expand_shortcuts(Sections1,Sections),
513 maplist(extract_machine_from_ref,References,Machines),
514 sort_machines_by_global_order(Machines,OMachines),
515 foldl(conjunct_sections2(OMachines),Sections,Old,New).
516 conjunct_sections2(Machines,Section,Old,New) :-
517 % Section is constraints,properties,invariant, ...
518 write_section(Section,NewContent,Old,New), % prepare new section
519 get_section_of_machines(Machines,Section,Preds),
520 %maplist(get_machine_name,Machines,Ns),print(got_sections(Section,Ns)),nl,
521 %translate:l_print_bexpr_or_subst(Preds),nl,
522 conjunct_predicates(Preds,NewContent).
523
524
525 % merge sections that contain a list of expressions/formulas like identifiers, assertions, ...
526 concat_sections_of_refs(Sections1,References,Old,New) :-
527 maplist(extract_machine_from_ref,References,Machines),
528 maplist(create_tag_by_reference,References,Tags),
529 sort_machines_by_global_order(Machines,Tags,OMachines,STags),
530 % should we only sort for some sections, e.g., assertions
531 % for each machine, create a tag where the expression comes from
532 concat_sections(Sections1,OMachines,STags,Old,New).
533
534 extract_machine_from_ref(ref(_,M),M).
535
536 create_tag_by_reference(ref(local,_Machine),[]) :- !.
537 create_tag_by_reference(ref(RefType,Machine),[RefType/Name]) :-
538 get_machine_name(Machine,Name).
539
540 concat_sections(Sections1,Machines,Tags,Old,New) :-
541 expand_shortcuts(Sections1,Sections),
542 foldl(concat_section2(Machines,Tags),Sections,Old,New).
543 concat_section2(Machines,Tags,Section,Old,New) :-
544 write_section(Section,NewContent,Old,New),
545 maplist(get_tagged_lsection_of_machine(Section),Machines,Tags,Contents),
546 concat_section_contents(Section,Contents,NewContent).
547
548 concat_section_contents(_,[SingleContent],Res) :- !, Res=SingleContent. % no need to remove_dups
549 concat_section_contents(Section,Contents,NewContent) :-
550 append(Contents,ConcContents),
551 (section_can_have_duplicates(Section)
552 -> remove_dups_keep_order(ConcContents,NewContent)
553 ; NewContent=ConcContents).
554
555 % see issue PROB-403
556 section_can_have_duplicates(X) :- section_can_be_included_multiple_times_nonprefixed(X).
557 % should we also remove duplicates in PROPERTIES section ? cf. machines used in test 1857
558
559
560 get_tagged_lsection_of_machine(Section,Machine,Tags,TaggedContent) :-
561 get_section(Section,Machine,Content),
562 (Tags=[] -> TaggedContent=Content ; maplist(tag_with_origin(Tags),Content,TaggedContent)).
563
564 tag_with_origin(Origins,TExpr,TaggedExpr) :-
565 change_info_of_expression_or_init(TExpr,Info,TaggedInfo,TaggedExpr),
566 % add a new origin to the old tag or if not existent, add a new info field
567 ( Origins = [] -> TaggedInfo = Info
568 ; selectchk(origin(Orest),Info,origin(Onew),TaggedInfo) -> append(Origins,Orest,Onew)
569 ; TaggedInfo = [origin(Origins)|Info]).
570 % the substitutions in the initialisation are additionally wrapped by an init/2 term
571 % a small hack to work with those too.
572 % TODO: this became a very ugly hack -- redo!
573 change_info_of_expression_or_init(init(A,OExpr),Old,New,init(A,NExpr)) :-
574 !,change_info_of_expression_or_init(OExpr,Old,New,NExpr).
575 % ignore the info for includeduse/3 completely
576 change_info_of_expression_or_init(includeduse(A,B,C),[],_,includeduse(A,B,C)) :- !.
577 change_info_of_expression_or_init(freetype(FTypeId,Cases),[],_,freetype(FTypeId,Cases)) :- !.
578 change_info_of_expression_or_init(OExpr,Old,New,NExpr) :-
579 create_texpr(Expr,Type,Old,OExpr),!,
580 create_texpr(Expr,Type,New,NExpr).
581 change_info_of_expression_or_init(OExpr,Old,New,NExpr) :-
582 add_internal_error('Illegal typed expression:',change_info_of_expression_or_init(OExpr,Old,New,NExpr)),
583 Old=[], NExpr=OExpr.
584
585 % adds a prefix to all variables and promoted operations
586 prefix_machine('',TM,TM) :- !.
587 prefix_machine(Prefix,Old,New) :-
588 debug_println(5,prefixing_machine(Prefix)),
589 expand_shortcuts([variables,promoted], RenamedIdentiferSections),
590 get_all_identifiers(RenamedIdentiferSections,Old,Identifiers),
591 prefix_identifiers(Identifiers,Prefix,Renamings),
592 find_relevant_sections(RenamedIdentiferSections,[machine],Sections1),
593 append(RenamedIdentiferSections,Sections1,Sections),
594 rename_in_sections(Sections,Renamings,Old,M),
595 rename_includeduse(M,Renamings,New).
596 rename_includeduse(Old,Renamings,New) :-
597 select_section(used,OldContent,NewContent,Old,New),
598 maplist(rename_includeduse2(Renamings),OldContent,NewContent).
599 rename_includeduse2(Renamings,includeduse(M,N,TExpr),includeduse(M,N,NExpr)) :-
600 rename_bt(TExpr,Renamings,NExpr).
601
602 get_all_identifiers(Sections1,M,Identifiers) :-
603 expand_shortcuts(Sections1,Sections),
604 maplist(get_all_identifiers2(M),Sections,LIdentifiers),
605 append(LIdentifiers,Identifiers).
606 get_all_identifiers2(M,Sec,Identifiers) :-
607 get_section(Sec,M,Identifiers).
608
609 % hide all parameters and unpromoted operations
610 hide_private_information(Prefix,Machine,NewMachine) :-
611 get_section(parameters,Machine,Params),
612 get_section(unpromoted,Machine,UnPromoted),
613 append(Params,UnPromoted,ToHide),
614 %debug_println(9,hide_private(Prefix,ToHide)),
615 ( ToHide = [] -> NewMachine=Machine
616 ;
617 prefix_identifiers(ToHide,Prefix,Renamings),
618 % we have to do the renaming in promoted operations, too, because
619 % those operations might use the renamed parameters and their reads/modifies
620 % info must be updated
621 rename_in_sections([parameters,promoted,unpromoted],Renamings,Machine,Machine1),
622 rename_includeduse(Machine1,Renamings,Machine2),
623 ? rename_relevant_sections([parameters,operations],Renamings,Machine2,NewMachine)).
624
625 prefix_identifiers(Identifiers,'',Identifiers) :- !.
626 prefix_identifiers(Old,Prefix,New) :-
627 maplist(prefix_identifier(Prefix),Old,New).
628 prefix_identifier(Prefix,TExpr,rename(Old,New)) :-
629 get_texpr_expr(TExpr,identifier(Old)),
630 (Old=op(OI) -> New=op(NI) ; OI=Old,NI=New),
631 ajoin([Prefix,'.',OI],NI). % , print(rename(Old,New)),nl.
632
633 parameters_to_internal(M1,M2) :-
634 select_section(internal_parameters,OldParams,Params,M1,M3),
635 select_section(parameters,NewParams,[],M3,M2),
636 append(OldParams,NewParams,Params).
637
638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
639 % uses and sees relations
640 find_uses(Machines,Uses,NotIncluded,Ein,Eout) :-
641 findall(U, use_usage(Machines,_,U), UnsortedUses),
642 sort(UnsortedUses,Uses),
643 ? check_include_use(Uses,Machines,NotIncluded,Ein,Eout).
644
645 % check_include_use/5 checks if the used machines are included in any machine
646 % check_include_use(+Uses,+Machines,-NotIncluded,Ein,Eout)
647 % Uses: The list of machine names that are used
648 % Machines: The list of machines
649 % NotIncluded: The list of used machines (their names) that are not included
650 % Ein/Eout: The errors (as difference-list)
651 check_include_use([],_,[],Errors,Errors).
652 check_include_use([U|Rest],Machines,NotIncluded,Ein,Eout) :-
653 findall(I,include_usage(Machines,U,I),Inc),
654 ( Inc=[] -> NotIncluded = [U|RestNotIncluded], Ein=E1
655 ; Inc=[_] -> NotIncluded = RestNotIncluded, Ein=E1
656 ;
657 NotIncluded = RestNotIncluded,
658 ? use_usage(Machines,Pos,U),
659 Ein = [error('used machine is included more than once',Pos)|E1]
660 ),
661 check_include_use(Rest,Machines,RestNotIncluded,E1,Eout).
662 % extend_not_included_uses(+Uses,+Main,-Name,+Machines,-AllMachines):
663 % Create a dummy machine that extends the main machine and extends or includes
664 % all seen/used machines that are not included if such machines exist.
665 % In case of refinement this is done for the whole refinement chain.
666 % Uses: List of machine names of the machines that are used/seen but not included
667 % Main: The name of the main machine
668 % Name: The name of the generated dummy machine (or Main if no dummy machine is generated)
669 % Machines: List of all specified Machines
670 % AllMachines: List of all Machines + the new dummy machine(s)
671 extend_not_included_uses([],Main,Main,Machines,Machines) :- !.
672 extend_not_included_uses(Uses,Main,NewMainName,Machines,AllMachines) :-
673 get_refinement_hierarchy(Main,Machines,RefChain),
674 maplist(extend_not_included_uses2(Uses,Machines),RefChain,NewMachines),
675 append(NewMachines,Machines,AllMachines),
676 dummy_machine_name(Main,NewMainName),
677 debug_format(19,'Creating dummy machine called ~w for main machine~n',[NewMainName]).
678 extend_not_included_uses2(Uses,Machines,Name,DummyMachine) :-
679 debug_format(19,'Creating dummy subsidiary machine for refined machine ~w~n',[Name]),
680 create_dummy_machine(Name,Machines,Parameters,DummyParameters,Sections,DummyMachine),
681 IncludeMain = machine_reference(none,Name,Parameters),
682 ( get_preference(seen_machines_included,true) ->
683 % extend just the main machine, include the used/seen machines
684 References = [extends(none,[IncludeMain]),includes(none,UReferences)]
685 ;
686 % extends the main machine and all used/seen machines
687 References = [extends(none,[IncludeMain|UReferences])]),
688 maplist(find_using(Machines),Uses,UReferences,LUParameters),
689 append([Parameters|LUParameters],DummyParameters),
690 copy_raw_definitions(Name,Machines,OptDefs),
691 % we store a flag "is_dummy" in the machine because we have a special case
692 % later, see type_constraints/7.
693 append([References,[is_dummy],OptDefs],Sections).
694 create_dummy_machine(Name,Machines,Parameters,DummyParameters,Sections,DummyMachine) :-
695 dummy_machine_name(Name,DummyName),
696 ? get_raw_model_type(Name,Machines,ModelType),
697 Header = machine_header(_,Name,Parameters),
698 DummyHeader = machine_header(none,DummyName,DummyParameters),
699 ? member(Machine,Machines),
700 ? generate_raw_machine(Header,DummyHeader,ModelType,Sections,Machine,DummyMachine),!.
701
702 generate_raw_machine(OldHeader,NewHeader,_,NewSections,
703 abstract_machine(_, ModelType,OldHeader,_),
704 abstract_machine(none,ModelType,NewHeader,NewSections)).
705 generate_raw_machine(OldHeader,NewHeader,ModelType,NewSections,
706 refinement_machine(_, OldHeader,_Abstract, _),
707 abstract_machine(none,ModelType,NewHeader,NewSections)).
708 generate_raw_machine(OldHeader,NewHeader,ModelType,NewSections,
709 implementation_machine(_, OldHeader,_Abstract, _),
710 abstract_machine(none,ModelType,NewHeader,NewSections)).
711
712 dummy_machine_name(Name,DummyName) :-
713 atom_concat('MAIN_MACHINE_FOR_',Name,DummyName).
714
715 find_using(Machines,U,machine_reference(none,Name,Arguments),Arguments) :-
716 % was using(U).U
717 ajoin([U,'.',U],Name),
718 ? member(M,Machines), get_machine_parameters(M,U,Params,_),!,
719 maplist(add_use_param,Params,Arguments).
720 add_use_param(identifier(_,Param),identifier(none,Name)) :-
721 ( is_upper_case(Param) ->
722 ajoin(['Useparam(',Param,')'],Name)
723 ;
724 ajoin(['useparam(',Param,')'],Name)).
725
726 % copy_raw_definitions(+Name,+Machines,-OptDefs):
727 % Get the definitions section from a raw (untyped) machine
728 % Name: Name of the machine
729 % Machines: List of Machines
730 % OptDefs: [] if no definitions are present or [Def] if a definition section Def is present
731 copy_raw_definitions(Name,Machines,OptDefs) :-
732 ? get_constructed_machine_name_and_body(M,Name,_,Sections),
733 memberchk(M,Machines),!,
734 Def = definitions(_,_),
735 ( memberchk(Def,Sections) ->
736 OptDefs = [Def]
737 ;
738 OptDefs = []).
739
740 add_def_dependency_information(DefsIn,DefsOut,Ein,Eout) :-
741 extract_def_name_set(DefsIn,DefNames,DN),
742 maplist(add_def_dep(DN),DefsIn,Defs1),
743 check_for_cyclic_def_dependency(Defs1,DefNames,DefsOut,Ein,Eout).
744
745 extract_def_name_set(Defs,DefNames,DN) :-
746 maplist(get_def_name,Defs,DefNames),
747 maplist(to_mapset_entry,DefNames,DN1),
748 list_to_avl(DN1,DN).
749
750 get_def_name(Def,Name) :- arg(1,Def,Name).
751 get_def_pos(Def,Pos) :- arg(3,Def,Pos).
752 get_def_dependencies(Def,Dependencies) :- arg(6,Def,Dependencies).
753 to_mapset_entry(Name,Name-true).
754
755 add_def_dep(DN,In,Out) :-
756 analyse_definition_dependencies(In,DN,Deps),
757 In = definition_decl(Name,DefType,Pos,Args,RawExpr),
758 Out = definition_decl(Name,DefType,Pos,Args,RawExpr,Deps).
759
760 check_for_cyclic_def_dependency(Defs,DefNames,DefsOut,Ein,Eout) :-
761 % check if we have a cyclic definition:
762 create_definitions_avl(Defs,DefsAvl),
763 search_for_cyclic_definition(DefNames,DefsAvl,[],Pos,RCycle),!,
764 % if we have found a cyclic definition, generate an error message, ...
765 reverse(RCycle,Cycle),add_arrows(Cycle,Msg0),
766 ajoin(['Found cyclic definitions: '|Msg0],Msg),
767 Ein = [error(Msg,Pos)|E1],
768 % ... remove the definitions in the cycle (to prevent later infinite loops) ...
769 exclude(definition_in_list(Cycle),Defs,Defs1),
770 % ... and check the remaining definitions.
771 check_for_cyclic_def_dependency(Defs1,DefNames,DefsOut,E1,Eout).
772 check_for_cyclic_def_dependency(Defs,_DefNames,Defs,E,E).
773 add_arrows([E],[E]) :- !.
774 add_arrows([E|Erest],[E,'->'|Arest]) :- add_arrows(Erest,Arest).
775 definition_in_list(List,Def) :-
776 get_def_name(Def,Name),memberchk(Name,List).
777
778 create_definitions_avl(Defs,DefsAvl) :-
779 maplist(split_def_name,Defs,Entries),
780 list_to_avl(Entries,DefsAvl).
781 split_def_name(Def,Name-Def) :- get_def_name(Def,Name).
782
783
784 % just a depth-first search to find a cycle
785 search_for_cyclic_definition(DefNames,Definitions,Visited,Pos,Cycle) :-
786 ? member(Name,DefNames),avl_fetch(Name,Definitions,Definition),
787 get_def_pos(Definition,Pos),
788 ( memberchk(Name,Visited) ->
789 Cycle = [Name|Visited]
790 ;
791 get_def_dependencies(Definition,Dependencies),
792 search_for_cyclic_definition(Dependencies,Definitions,[Name|Visited],_,Cycle)
793 ).
794
795 :- assert_must_succeed((
796 list_to_avl([def1-true,def2-true,def3-true,def4-true],DefNames),
797 analyse_definition_dependencies(
798 conjunct(none,
799 equals(none,
800 identifier(none,x),
801 identifier(none,def1)),
802 equals(none,
803 definition(none,def4,
804 [function(none,
805 identifier(none,def3),
806 integer(none,5))]),
807 identifier(y))),DefNames,Defs),
808 Defs==[def1,def3,def4]
809 )).
810 % analyse_definition_dependencies(+Expr,+DefinitionNames,Deps):
811 % Expr: raw (i.e. untyped) expression to analyse
812 % DN: AVL set (i.e. mapping from elements to 'true') of the names of the definitions
813 % This is needed to decide if an identifier is a reference to a definition
814 % Deps: A list of used definitions (a list of their names)
815 analyse_definition_dependencies(Expr,DN,Deps) :-
816 analyse_definition_dependencies2(Expr,DN,Unsorted,[]),
817 sort(Unsorted,Deps).
818 analyse_definition_dependencies2(VAR,_DN) --> {var(VAR)},!,
819 {add_internal_error('Variable DEFINITION expression in',analyse_definition_dependencies)}.
820 analyse_definition_dependencies2([Expr|Rest],DN) -->
821 !, analyse_definition_dependencies2(Expr,DN),
822 analyse_definition_dependencies2(Rest,DN).
823 analyse_definition_dependencies2(definition(_Pos,Name,Args),DN) -->
824 !,[Name],analyse_definition_dependencies2(Args,DN).
825 analyse_definition_dependencies2(identifier(_Pos,Name),DN) -->
826 {avl_fetch(Name,DN),!},[Name].
827 analyse_definition_dependencies2(Expr,DN) -->
828 { compound(Expr),functor(Expr,_Functor,Arity),!},
829 analyse_definition_dependencies_arg(2,Arity,Expr,DN).
830 analyse_definition_dependencies2(_Expr,_DN) --> [].
831
832 analyse_definition_dependencies_arg(I,Arity,Expr,DN) -->
833 { I =< Arity,!,arg(I,Expr,Arg),I2 is I+1 },
834 analyse_definition_dependencies2(Arg,DN),
835 analyse_definition_dependencies_arg(I2,Arity,Expr,DN).
836 analyse_definition_dependencies_arg(_I,_Arity,_Expr,_DN) --> [].
837
838
839 :- use_module(tools_positions, [get_position_filenumber/2]).
840
841 get_constructed_machine_name(MachineTerm,Name) :- get_constructed_machine_name_and_body(MachineTerm,Name,_Pos,_).
842 % name and pos; pos can be used for filenumber
843 get_constructed_machine_name_and_filenumber(MachineTerm,Name,Filenumber) :-
844 get_constructed_machine_name_and_body(MachineTerm,Name,Pos,_),
845 (get_position_filenumber(Pos,FN) -> Filenumber=FN ; Filenumber=unknown).
846 get_constructed_machine_name_and_body(abstract_machine(_,_ModelType,machine_header(Pos,Name,_),Body),Name,Pos,Body).
847 get_constructed_machine_name_and_body(refinement_machine(_,machine_header(Pos,Name,_),_Abstract,Body),Name,Pos,Body).
848 get_constructed_machine_name_and_body(implementation_machine(_,machine_header(Pos,Name,_),_Abstract,Body),Name,Pos,Body).
849
850 refines(refinement_machine(_,machine_header(_,_Name,_),Abstract,_Body),Abstract).
851 refines(implementation_machine(_,machine_header(_,_Name,_),Abstract,_Body),Abstract).
852
853 get_machine_parameters(abstract_machine(Pos,_ModelType,machine_header(_,Name,Parameters),_),Name,Parameters,Pos).
854 get_machine_parameters(refinement_machine(Pos,machine_header(_,Name,Parameters),_,_),Name,Parameters,Pos).
855 get_machine_parameters(implementation_machine(Pos,machine_header(_,Name,Parameters),_,_),Name,Parameters,Pos).
856
857 get_raw_model_type(Main,Machines,ModelType) :-
858 ? get_constructed_machine_name_and_body(M,Main,_,_),
859 memberchk(M,Machines),
860 ( refines(M,RefName) ->
861 ? get_raw_model_type(RefName,Machines,ModelType)
862 ;
863 M = abstract_machine(_,ModelType,_,_)).
864
865 some_machine_name_body(Machines,M,Name,Body) :-
866 ? member(M,Machines),
867 get_constructed_machine_name_and_body(M,Name,_,Body).
868
869 use_usage(Machines,Pos,Use) :-
870 ? some_machine_name_body(Machines,_,_,Body),
871 ? ( member(sees(Pos,R),Body)
872 ? ; member(uses(Pos,R),Body)),
873 ? member(identifier(_,PrefixUse),R),
874 split_prefix(PrefixUse,_,Use).
875 % include_usage/3 checks if there is any machine in Machines that
876 % includes/extends/imports the used machine
877 % include_usage(+Machines,+Use,-Name):
878 % Machines: The list of machines
879 % Use: The name of the used machine
880 % Name: The name of the machine that imports the used machine
881 % include_usage/3 fails if there is not such an import
882 include_usage(Machines,Use,Name) :-
883 ? some_machine_name_body(Machines,_,Name,Body),
884 ? ( member(includes(_,R),Body)
885 ? ; member(extends(_,R), Body)
886 ? ; member(imports(_,R), Body)),
887 ? member(machine_reference(_Pos,PrefixRef,_),R),
888 % The name could be prefixed, we need it without prefix:
889 split_prefix(PrefixRef,_,Use).
890
891 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
892 % uses and sees clauses
893
894 % returns a list of references to used and seen machines
895 % the machines contain only identifier sections and
896 % the identifier are prefixed accordingly
897 % all identifier are marked as coming from a seen/used machine
898 use_and_see_machines(Sections,Machines,References) :-
899 get_uses_and_sees(Sections,Uses,Sees),
900 ? maplist(use_or_see_machine(used,Machines),Uses,Used),
901 ? maplist(use_or_see_machine(seen,Machines),Sees,Seen),
902 append(Used,Seen,References).
903
904 % get uses and sees sections from the untyped machines
905 get_uses_and_sees(Sections,Uses,Sees) :-
906 get_uses_or_sees2(sees,Sections,Sees),
907 get_uses_or_sees2(uses,Sections,Uses).
908 get_uses_or_sees2(Mode,Sections,US) :-
909 optional_rawmachine_section(Mode,Sections,[],US1),
910 findall(I,member(identifier(_,I),US1),US).
911
912 use_or_see_machine(Mode,TypedMachines,Ref,ref(Mode,Result)) :-
913 split_prefix(Ref,Prefix,Name),
914 memberchk(machine(Name,Typed),TypedMachines),
915 create_machine(Name,Empty),
916 ? use_sections([sets],Mode,'',Name,Typed,Empty,M1),
917 ? use_sections([constants,variables,promoted],Mode,Prefix,Name,Typed,M1,Result).
918 use_sections(Sections,Mode,Prefix,MName,Typed,Old,New) :-
919 expand_shortcuts(Sections,AllSections),
920 ? foldl(use_section(Mode,Prefix,MName,Typed),AllSections,Old,New).
921 use_section(Mode,Prefix,MName,Machine,Section,OldM,NewM) :-
922 ? get_section_texprs(Section,Machine,Identifiers),
923 write_section(Section,NewIds,OldM,NewM),
924 ( Prefix='' ->
925 Ids1=Identifiers
926 ;
927 prefix_identifiers(Identifiers,Prefix,Renamings),
928 rename_bt_l(Identifiers,Renamings,Ids1)),
929 maplist(add_use_info_to_identifier(Mode,MName),Ids1,NewIds).
930 add_use_info_to_identifier(Mode,Name,TExpr,New) :-
931 get_texpr_id(TExpr,PId), get_texpr_type(TExpr,Type),
932 get_texpr_id(New,PId), get_texpr_type(New,Type),
933 split_prefix(PId,_Prefix,Id),
934 get_texpr_info(TExpr,Info),
935 get_texpr_info(New,[usesee(Name,Id,Mode)|Info]).
936
937
938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
939 % add a section to the machine that describes the linking of
940 % parameters and arguments
941 add_link_constraints(Includes,MType,Parameters,RefMachines,Old,New,Ein,Eout) :-
942 AllRefMachines = [ref(local,Old)|RefMachines],
943 extract_parameter_types(RefMachines,NonGroundExceptions),
944 foldl(add_link_section(MType,Parameters,AllRefMachines,NonGroundExceptions),
945 Includes,Links/Ein,[]/Eout), % TO DO: Daniel check if [] is correct here
946 %print(conjunct_predicates(Links,Link)),nl,
947 conjunct_predicates(Links,Link),
948 select_section(constraints,OConstraints,NConstraints,Old,New),
949 conjunct_predicates([Link,OConstraints],NConstraints).
950 add_link_section(MType,Parameters,RefMachines,NonGroundExceptions,
951 machine_reference(Pos,Ref,Args),Links/Ein,RLinks/Eout) :-
952 visible_env(MType,includes,RefMachines,Env,Ein,E1),
953 memberchk(parameters(Ref,TParameters),Parameters),
954 ( same_length(TParameters, Args) ->
955 get_texpr_types(TParameters,Types),
956 btype_ground_dl(Args,Env,NonGroundExceptions,Types,TArgs,E1,Eout),
957 maplist(create_plink_equality,TParameters,TArgs,LLinks)
958 ;
959 E1 = [error('wrong number of machine arguments',Pos)|Eout],
960 LLinks = []),
961 append(LLinks,RLinks,Links).
962 create_plink_equality(P,A,E) :-
963 create_texpr(equal(P,A),pred,[parameterlink],E).
964
965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
966 % type machines
967
968 type_machine(Header,Name,MType,RawMachine,RefMachines,TypedMachine,NewRefMachines,Ein,Eout) :-
969 Header = machine_header(_,Name,_),
970 create_machine(Name,Empty),
971 % (optional) definitions
972 extract_definitions(RawMachine,Empty,DefsOnly,Ein,E0),
973 debug_stats(extracted_definitions(Name)),
974 % create the identifiers that will be typed,
975 % Local will contain the identifier sections
976 create_id_sections(Header,RawMachine,Name,DefsOnly,Local),
977 debug_stats(created_identifier_sections(Name)),
978 ? create_freetypes(RawMachine,MType,RefMachines,Local,Local1,E0,E1),
979 % in case of a refinement, check if all newly defined operations are refinements
980 link_to_refinement(MType,RawMachine,RefMachines,Local1,Local2,E1,E2),
981 % extract types that can be variables
982 debug_stats(created_link_to_refinement(Name)),
983 extract_parameter_types([ref(local,Local2)|RefMachines],NonGroundExceptions),
984 % check for a VALUES clause. They are a little bit tricky because they can replace
985 % already defined deferred sets by integers or other deferred sets
986 process_values_section(MType,RawMachine,NonGroundExceptions,
987 Local2/E2/RefMachines,Local3/E3/NewRefMachines),
988 % type-check the other sections (properties, invariant, operation_bodies, etc)
989 ? type_sections(RawMachine,MType,[ref(local,Local3)|NewRefMachines],NonGroundExceptions,
990 Name,E3,Eout,Local3,TypedMachine).
991
992 extract_definitions(RawMachine,In,Out,Ein,Eout) :-
993 optional_rawmachine_section(definitions,RawMachine,[],AllDefinitions),
994 write_section(definitions,Definitions,In,Out),
995 % remove all references to definition files from definitions
996 exclude(is_file_definition,AllDefinitions,Definitions1),
997 % replace expression_definition(...) by defintion(expression,...), etc.
998 change_definition_style(Definitions1,Definitions2),
999 % analyse dependencies
1000 add_def_dependency_information(Definitions2,Definitions3,Ein,Eout),
1001 % replace external function definitions by calls to the external function
1002 replace_external_declarations(Definitions3,Definitions).
1003
1004 is_file_definition(file_definition(_Pos,_Filename)).
1005
1006 change_definition_style(DefsIn,DefsOut) :-
1007 maplist(change_definition_style2,DefsIn,DefsOut).
1008 change_definition_style2(conversion(Pos,InnerDef),definition_decl(Name,DefType,InnerPos,Args,conversion(Pos,RawExpr))) :-
1009 change_definition_style2(InnerDef,definition_decl(Name,DefType,InnerPos,Args,RawExpr)).
1010 change_definition_style2(Def,definition_decl(Name,DefType,Pos,Args,RawExpr)) :-
1011 Def =.. [Functor,Pos,Name,Args,RawExpr],
1012 maplist(check_def_argument(Name,Pos),Args),
1013 map_def_functor(Functor,DefType).
1014 map_def_functor(expression_definition,expression).
1015 map_def_functor(substitution_definition,substitution).
1016 map_def_functor(predicate_definition,predicate).
1017
1018 % check formal arguments of definitions , e.g., here xx in square2 is not an identifier: xx == 20; square2(xx) == xx*xx
1019 check_def_argument(_,_,identifier(_,_)) :- !.
1020 check_def_argument(DefName,DefPos,definition(_,ID,_)) :- !,
1021 tools:ajoin(['Formal parameter ', ID, ' is a definition call in Definition: '],Msg),
1022 add_error(bmachine_construction,Msg,DefName,DefPos).
1023 check_def_argument(DefName,DefPos,FP) :- !,
1024 tools:ajoin(['Formal parameter ', FP, ' is not an identifier in Definition: '],Msg),
1025 add_error(bmachine_construction,Msg,DefName,DefPos).
1026
1027 replace_external_declarations(Definitions,NewDefs) :-
1028 split_list(is_external_declaration,Definitions,ExtFunctionDecls,RestDefs),
1029 foldl(replace_external_declaration,ExtFunctionDecls,RestDefs,NewDefs).
1030 is_external_declaration(definition_decl(DefName,expression,_Pos,_Params,_Def,_Dependencies)) :-
1031 ? external_name(DefName,ExtType,_ExpectedDefType,_ExtCall,FunName),
1032 debug_format(4,'external ~w declared: ~w~n', [ExtType,FunName]).
1033 external_name(DefName,_,_,_,_) :-
1034 \+ atom(DefName),!,
1035 add_internal_error('Non-atomic DEFINITION id:',DefName),fail.
1036 external_name(DefName,function,expression,external_function_call,FunName) :-
1037 atom_concat('EXTERNAL_FUNCTION_',FunName,DefName).
1038 external_name(DefName,predicate,predicate,external_pred_call,FunName) :-
1039 atom_concat('EXTERNAL_PREDICATE_',FunName,DefName).
1040 external_name(DefName,substitution,substitution,external_subst_call,FunName) :-
1041 atom_concat('EXTERNAL_SUBSTITUTION_',FunName,DefName).
1042 replace_external_declaration(definition_decl(DefName,expression,DefPos,TypeParams,Decl,_Deps),In,Out) :-
1043 OldDefinition = definition_decl(FunName,ExpectedDefType,Pos,FunParams,FunDef,Deps),
1044 NewDefinition = definition_decl(FunName,ExpectedDefType,Pos,FunParams,ExtCall,Deps),
1045 ? ( external_name(DefName,_ExtType,ExpectedDefType,ExtCallFunctor,FunName),
1046 ExtCall =.. [ExtCallFunctor,Pos,FunName,FunParams,FunDef,
1047 rewrite_protected(TypeParams),rewrite_protected(Decl)],
1048 selectchk(OldDefinition,In,NewDefinition,Out) ->
1049 assert_external_procedure_used(FunName)
1050 ;
1051 % no definition found for external function
1052 add_error(replace_external_declaration,'No DEFINITION associated with: ',DefName,DefPos),
1053 Out=In).
1054
1055 :- use_module(external_function_declarations,
1056 [external_function_library/2, safe_external_function_library/2,
1057 get_external_function_definition/3]).
1058 % store external definitions of a given library in the type environment, e.g. for debugging in Repl or VisB
1059 % Library could be "LibraryStrings.def"
1060
1061 store_ext_defs(Library,In,Out) :-
1062 (Library = all_available_libraries
1063 -> findall(extfun(Id,Lib),external_function_library(Id,Lib),Ids)
1064 ; Library = safe_available_libraries
1065 -> findall(extfun(Id,Lib),safe_external_function_library(Id,Lib),Ids)
1066 ; findall(extfun(Id,Library),external_function_library(Id,Library),Ids)
1067 ),
1068 (Ids=[] -> add_warning(store_ext_defs,'No external functions found for library: ',Library) ; true),
1069 foldl(store_ext_def,Ids,In,Out).
1070
1071 store_ext_def(extfun(Id,Library),In,Out) :- env_lookup_type(Id,In,_),!,
1072 debug_println(4,not_storing_ext_def(Id,Library)), % already imported from stdlib or user has other definition
1073 Out=In.
1074 store_ext_def(extfun(FunName,Library),In,Out) :-
1075 ? get_external_function_definition(FunName,Library,DEFINITION),!,
1076 debug_println(4,storing_ext_def(FunName,Library)),
1077 env_store(FunName,DEFINITION,[loc('automatically included',Library,definitions)],In,Out).
1078 store_ext_def(extfun(Id,_),In,Out) :-
1079 add_internal_error('Cannot add external definition: ',Id),
1080 Out=In.
1081
1082
1083 % store which machine promotes which operations
1084 :- dynamic machine_promotes_operations/2, machine_global_order/1.
1085
1086 reset_bmachine_construction :-
1087 retractall(machine_promotes_operations(_,_)),
1088 retractall(machine_global_order(_)),
1089 reset_external_procedure_used.
1090
1091
1092 % maybe this information should be stored somewhere else ??
1093 :- dynamic external_procedure_used/1.
1094 reset_external_procedure_used :- retractall(external_procedure_used(_)).
1095 assert_external_procedure_used(FunName) :-
1096 (external_procedure_used(FunName) -> true ; assertz(external_procedure_used(FunName))).
1097
1098 link_to_refinement(machine,_RawMachine,_RefMachines,Local,Local,Errors,Errors).
1099 link_to_refinement(refinement,RawMachine,RefMachines,Local,NewLocal,Ein,Eout) :-
1100 link_to_refinement(implementation,RawMachine,RefMachines,Local,NewLocal,Ein,Eout).
1101 link_to_refinement(implementation,RawMachine,RefMachines,Local,NewLocal,Ein,Eout) :-
1102 link_to_refinement2(implementation,RawMachine,RefMachines,Local,NewLocal,Ein,Eout).
1103 link_to_refinement2(_MType,RawMachine,RefMachines,Local,NewLocal,Ein,Eout) :-
1104 memberchk(ref(abstraction,AbstractMachine),RefMachines),
1105 copy_constraints(Local,AbstractMachine,NewLocal,Ein,E1),
1106 type_vars_in_refinement(AbstractMachine,NewLocal),
1107 type_refinement_operations(RawMachine,AbstractMachine,NewLocal,E1,Eout).
1108
1109 copy_constraints(Local,AbstractMachine,NewLocal,Ein,Eout) :-
1110 get_section(parameters,Local,LocalParameters),
1111 get_section(parameters,AbstractMachine,AbstractParameters),
1112 check_if_equal_identifiers(LocalParameters,AbstractParameters,Ein,Eout,Local),
1113 get_section(constraints,AbstractMachine,Constraints),
1114 write_section(constraints,Constraints,Local,NewLocal).
1115 check_if_equal_identifiers(Local,Abstract,Ein,Eout,LocalMachine) :-
1116 ( same_length(Local,Abstract) ->
1117 foldl(check_if_equal_identifiers2,Local,Abstract,Ein,Eout)
1118 ;
1119 get_texpr_ids(Abstract,AIDs),
1120 get_machine_name(LocalMachine,MachName),
1121 ajoin(['Refinement ',MachName,' must have same Parameters ', AIDs,' as abstract Machine'],Msg),
1122 Ein = [error(Msg,none)|Eout]
1123 ).
1124 check_if_equal_identifiers2(LParam,AParam,Ein,Eout) :-
1125 get_texpr_id(LParam,LName),
1126 get_texpr_id(AParam,AName),
1127 ( LName = AName ->
1128 % type in refinement is the same as in the abstraction
1129 get_texpr_type(LParam,Type),
1130 get_texpr_type(AParam,Type),
1131 Ein=Eout
1132 ;
1133 get_texpr_pos(LParam,Pos),
1134 ajoin(['Parameter ',LName,' of refinement machine must be ',
1135 AName,' like in the abstract machine'],Msg),
1136 Ein = [error(Msg,Pos)|Eout]
1137 ).
1138
1139 % in case of a refinement, give variables the same type as in the abstract machine
1140 % the same for constants
1141 type_vars_in_refinement(AbstractMachine,ConcreteMachine) :-
1142 pass_type(AbstractMachine,[abstract_variables,concrete_variables],
1143 ConcreteMachine,[abstract_variables,concrete_variables]),
1144 pass_type(AbstractMachine,[abstract_constants,concrete_constants],
1145 ConcreteMachine,[abstract_constants,concrete_constants]).
1146
1147 % pass the type from variables in Sections1 of Machine1 to
1148 % the variables of the same name in Sections2 of Machine2
1149 % Machine1,Machine2: a machine
1150 % Sections1, Sections2: a list of section names
1151 pass_type(Machine1,Sections1,Machine2,Sections2) :-
1152 get_sections_and_append(Sections1,Machine1,Vars1),
1153 get_sections_and_append(Sections2,Machine2,Vars2),
1154 maplist(pass_type2(Vars2),Vars1).
1155 get_sections_and_append([],_M,[]).
1156 get_sections_and_append([Sec|RestSections],M,R) :-
1157 get_section(Sec,M,L), append(L,Rest,R),
1158 get_sections_and_append(RestSections,M,Rest).
1159 pass_type2(DstVariables,SrcVariable) :-
1160 get_texpr_id(SrcVariable,Id),
1161 get_texpr_id(DstVariable,Id),
1162 ( memberchk(DstVariable,DstVariables) ->
1163 get_texpr_type(DstVariable,Type),
1164 get_texpr_type(SrcVariable,Type)
1165 ;
1166 true).
1167
1168
1169 % in case of a refinement, check if the defined operations are already defined
1170 % in the abstract machine and copy that type.
1171 type_refinement_operations(RawMachine,AbstractMachine,Local,Ein,Eout) :-
1172 get_operation_identifiers(RawMachine,Operations),
1173 type_refinement_operations2(Operations,Local,AbstractMachine,Ein,Eout).
1174 type_refinement_operations2([],_,_AbstractMachine,Errors,Errors).
1175 type_refinement_operations2([Op|Rest],M,AbstractMachine,Ein,Eout) :-
1176 get_abstract_operation_name_wo_infos(Op,AOp),
1177 %print(treating_refines_operation(Op,AOp)),nl,
1178 get_texpr_pos(Op,Pos),
1179 % look up the abstract definition
1180 get_abstract_op(AOp,AbstractMachine,Pos,Ein,E1),
1181 % store the type in the identifier section
1182 copy_texpr_wo_info(Op,SOp),
1183 get_section(promoted,M,Operations),
1184 memberchk(SOp, Operations),
1185 % do the rest
1186 type_refinement_operations2(Rest,M,AbstractMachine,E1,Eout).
1187 % looks up the type of the operator in an abstract machine
1188 get_abstract_op(Op,Abstraction,_,Errors,Errors) :-
1189 % look for the operation in promoted and unpromoted
1190 ? ( get_section(promoted,Abstraction,AbstractOps), member(Op,AbstractOps)
1191 ; get_section(unpromoted,Abstraction,AbstractOps), member(Op,AbstractOps) ),
1192 % forget alternatives
1193 !.
1194 get_abstract_op(Op,_Abstraction,_Pos,Errors,Errors) :-
1195 % we might allow new operations
1196 get_preference(allow_new_ops_in_refinement,true),!,
1197 get_texpr_type(Op,op(_,_)).
1198 get_abstract_op(Op,_,Pos,[error(Msg,Pos)|Eout],Eout) :-
1199 % in case we do not find the operation, store an error
1200 get_texpr_id(Op,op(Id)),
1201 ajoin(['operation ', Id, ' is not defined in the abstract machine'], Msg).
1202 % copy a typed expression without the additional information (just expression and type)
1203 copy_texpr_wo_info(A,B) :-
1204 % copy the expression and type, the additional information may be different
1205 get_texpr_expr(A,Expr),get_texpr_expr(B,Expr),
1206 get_texpr_type(A,Type),get_texpr_type(B,Type).
1207
1208 get_abstract_operation_name_wo_infos(b(_,Type,Infos),Res) :-
1209 memberchk(refines_operation(RefID),Infos),!, % renaming occurs:
1210 Res = b(identifier(op(RefID)),Type,_).
1211 get_abstract_operation_name_wo_infos(ID,Copy) :- copy_texpr_wo_info(ID,Copy).
1212
1213 create_id_sections(Header,RawMachine,Name) -->
1214 create_id_sections_header(Header),
1215 %{print(created_header(Name)),nl},
1216 create_set_sections(RawMachine,Name),
1217 %{print(created_set(Name)),nl},
1218 create_constants_sections(RawMachine),
1219 %{print(created_constants(Name)),nl},
1220 create_variables_sections(RawMachine),
1221 %{print(created_variables(Name)),nl},
1222 create_operations_sections(RawMachine).
1223
1224 extract_parameter_types(MachineRefs,ParameterTypes) :-
1225 maplist(extract_parameter_types2,MachineRefs,ParameterTypesL),
1226 append(ParameterTypesL,ParameterTypes).
1227 extract_parameter_types2(ref(_,Machine),ParameterTypes) :-
1228 get_section(parameters,Machine,VisibleParams),
1229 get_section(internal_parameters,Machine,InternalParams),
1230 append(VisibleParams,InternalParams,Params),
1231 include(is_a_parameter_set,Params,ParameterSets),
1232 maplist(get_texpr_set_type,ParameterSets,ParameterTypes).
1233 is_a_parameter_set(TExpr) :-
1234 get_texpr_info(TExpr,Info),
1235 memberchk(parameter_set,Info).
1236
1237 type_sections(RawMachine,MachineType,RefMachines,NonGroundExceptions,Name,Ein,Eout) -->
1238 {debug_stats('TYPING CONSTRAINTS'(Name))},
1239 type_constraints(MachineType,Name,RawMachine,RefMachines,NonGroundExceptions,Ein,E1),
1240 % Maybe the VALUES section must be moved up later because it may be used to
1241 % substitute types (e.g. deferred sets to integers) for later use
1242 {debug_stats('TYPING PROPERTIES'(Name))},
1243 type_section_with_single_predicate(properties,Name,[constants],MachineType,RawMachine,RefMachines,NonGroundExceptions,E1,E2),
1244 {debug_stats('TYPING INVARIANT'(Name))},
1245 type_section_with_single_predicate(invariant,Name,[variables],MachineType,RawMachine,RefMachines,NonGroundExceptions,E2,E3),
1246 {debug_stats('TYPING ASSERTIONS'(Name))},
1247 type_section_with_predicate_list(assertions,[],MachineType,RawMachine,RefMachines,NonGroundExceptions,E3,E4),
1248 {debug_stats('TYPING INITIALISATION'(Name))},
1249 ? type_initialisation_section(RawMachine,Name,MachineType,RefMachines,NonGroundExceptions,E4,E5),
1250 {debug_stats('TYPING OPERATIONS'(Name))},
1251 type_operations_section(RawMachine,MachineType,RefMachines,NonGroundExceptions,E5,Eout),
1252 {debug_stats('FINISHED TYPING SECTIONS'(Name))}.
1253
1254 % skip this section, it is copied from the abstract machine and
1255 % does not need to be typed again
1256 type_constraints(refinement,_,_RawMachine,_RefMachines,_NonGroundExceptions,Errors,Errors) --> !.
1257 type_constraints(implementation,_,_RawMachine,_RefMachines,_NonGroundExceptions,Errors,Errors) --> !.
1258 type_constraints(machine,Name,RawMachine,RefMachines,NonGroundExceptions,Ein,Eout) -->
1259 % if the machine is a dummy machine (in presence of a not included seen or used
1260 % machine), we must omit the check that the (lower case) parameters are all typed.
1261 % We can assume that they are properly typed by the included machine.
1262 {(is_dummy_machine(RawMachine) -> IdsToType = [] ; IdsToType = [parameters])},
1263 type_section_with_single_predicate(constraints,Name,IdsToType,machine,
1264 RawMachine,RefMachines,NonGroundExceptions,Ein,Eout).
1265
1266 ?is_dummy_machine(RawMachine) :- member(is_dummy,RawMachine),!.
1267
1268 % Header: Parameters
1269 create_id_sections_header(machine_header(_,_,Parameters),Old,New) :-
1270 write_section(parameters,TParams,Old,New),
1271 maplist(create_id_section_parameter,Parameters,TParams).
1272 create_id_section_parameter(Param,TParam) :-
1273 Expr=identifier(Name),
1274 ext2int_with_pragma(Param,Expr,_,Type,Expr,[ParameterType],TParam),
1275 ( is_upper_case(Name) ->
1276 ParameterType = parameter_set,
1277 Type = set(_)
1278 ;
1279 ParameterType = parameter_scalar).
1280 is_upper_case(Name) :- \+ atom(Name),!, add_internal_error('Illegal call:', is_upper_case(Name)),fail.
1281 is_upper_case(Name) :- atom_codes(Name,[C|_]),
1282 memberchk(C,"ABCDEFGHIJKLMNOPQRSTUVWXYZ").
1283
1284 % Body: Sets
1285 create_set_sections(Sections,MachineName) -->
1286 write_section(deferred_sets,DeferredSets),
1287 write_section(enumerated_sets,EnumeratedSets),
1288 write_section(enumerated_elements,EnumeratedElements),
1289 {optional_rawmachine_section(sets,Sections,[],Sets),
1290 split_list(is_deferred_set_element,Sets,RawDeferredSets,RawEnumeratedSets),
1291 maplist(create_deferred_set_section(MachineName),RawDeferredSets,DeferredSets),
1292 maplist(create_enumerated_set_section(Sections,MachineName),
1293 RawEnumeratedSets,EnumeratedSets,LEnumeratedElements),
1294 append(LEnumeratedElements,EnumeratedElements)}.
1295 is_deferred_set_element(AstElem) :- has_functor(AstElem,deferred_set,_).
1296 create_deferred_set_section(MachineName,DS,TExpr) :-
1297 unwrap_opt_description(DS,deferred_set(Pos,I),TInfos),
1298 Infos = [given_set,def(deferred_set,MachineName)|TInfos],
1299 create_global_id(I,Pos,Infos,TExpr).
1300 create_enumerated_set_section(Sections,MachineName,ES,TExpr,Elements) :-
1301 unwrap_opt_description(ES,EnumSetList,TInfos),
1302 create_enum_set_aux(EnumSetList,Sections,MachineName,TInfos,TExpr,Elements).
1303
1304 create_global_id(identifier(_,Id),Pos,Infos,TExpr) :- !,
1305 add_warning(bmachine_construction,'Identifier unexpectedly not atomic: ',Id,Pos), % happened e.g. in ANTLR parser
1306 create_identifier(Id,Pos,set(global(Id)),Infos,TExpr).
1307 create_global_id(Id,Pos,Infos,TExpr) :- !,
1308 create_identifier(Id,Pos,set(global(Id)),Infos,TExpr).
1309
1310 create_enum_set_aux(enumerated_set(Pos,I,Elems),_,MachineName,TInfos,TExpr,Elements) :- !,
1311 % regular case I = {Elems1, ...}
1312 Infos = [given_set,def(enumerated_set,MachineName)|TInfos],
1313 create_global_id(I,Pos,Infos,TExpr),
1314 maplist(create_enum_set_element(I,MachineName),Elems,Elements).
1315 create_enum_set_aux(enumerated_set_via_def(Pos,I,ElemsDEF),Sections,MachineName,TInfos,TExpr,Elements) :- !,
1316 % we have the case I = ElemsDEF and DEFINITIONS ElemsDEF == {Elems1, ...}
1317 Infos = [given_set,def(enumerated_set,MachineName)|TInfos],
1318 create_global_id(I,Pos,Infos,TExpr),
1319 (optional_rawmachine_section(definitions,Sections,[],Defs),
1320 member(expression_definition(DPos,ElemsDEF,Paras,DefBody),Defs)
1321 -> (Paras \= []
1322 -> add_error(bmachine_construction,
1323 'DEFINITION for enumerated set elements must not have parameters:',ElemsDEF,DPos),
1324 Elements=[]
1325 ; DefBody = set_extension(_,Elems),
1326 maplist(create_enum_set_element(I,MachineName),Elems,Elements)
1327 -> true
1328 ; add_error(bmachine_construction,
1329 'DEFINITION for enumerated set elements must be of the form {El1,El2,...}:',ElemsDEF,DPos),
1330 Elements=[]
1331 )
1332 ; add_error(bmachine_construction,'No DEFINITION for enumerated set elements found:',ElemsDEF,Pos),
1333 Elements=[]
1334 ).
1335 create_enum_set_aux(E,_,_,_,_,_) :- add_internal_error('Illegal enumerated set:',E),fail.
1336
1337
1338 % deal with optional description(Pos,Desc,A) wrapper
1339 has_functor(description(_,_Desc,A),Functor,Arity) :- !, functor(A,Functor,Arity).
1340 has_functor(A,Functor,Arity) :- functor(A,Functor,Arity).
1341
1342 % remove description wrapper and generate info field
1343 unwrap_opt_description(description(_,Desc,A),Res,Infos) :- !, Res=A, Infos=[description(Desc)].
1344 unwrap_opt_description(A,A,[]).
1345
1346
1347 create_enum_set_element(Id,MachineName,Ext,Elem) :-
1348 (Id=identifier(none,RID)
1349 -> Type=global(RID), add_warning(bmachine_construction,'Unexpected non-atomic global set id: ',RID)
1350 ; Type=global(Id)),
1351 ext2int_with_pragma(Ext,Expr,_Pos,Type,Expr,[enumerated_set_element,def(enumerated_element,MachineName)],Elem).
1352
1353 create_identifier(Id,Pos,Type,Infos,TExpr) :-
1354 create_texpr(identifier(Id),Type,[nodeid(Pos)|Infos],TExpr).
1355
1356 % Constants
1357 create_constants_sections(RawMachine) -->
1358 create_section_identifiers(constants,concrete_constants,RawMachine),
1359 create_section_identifiers(abstract_constants,abstract_constants,RawMachine).
1360 % Variables
1361 create_variables_sections(RawMachine) -->
1362 create_section_identifiers(concrete_variables,concrete_variables,RawMachine),
1363 create_section_identifiers(variables,abstract_variables,RawMachine).
1364
1365 % Freetypes: Treat them as additional constants, plus add entries in the "freetypes"
1366 % section of the resulting machine
1367 create_freetypes(RawMachine,MType,RefMachines,Old,New,Ein,Eout) :-
1368 optional_rawmachine_section(freetypes,RawMachine,[],RawFreetypes),
1369 ? create_freetypes2(RawFreetypes,MType,[ref(local,Old)|RefMachines],Old,New,Ein,Eout).
1370 create_freetypes2([],_MType,_RefMachines,M,M,E,E) :- !.
1371 create_freetypes2(RawFreetypes,MType,RefMachines,Old,New,Ein,Eout) :-
1372 % we need the NonGroundExceptions for type checking
1373 extract_parameter_types(RefMachines,NonGroundExceptions),
1374 % create identifiers in the constants section
1375 ? maplist(create_ids_for_freetype,RawFreetypes,IdsFreetypes),
1376 % we just combined the results to keep the numbers of arguments low (too much for maplist)
1377 maplist(split_ft,IdsFreetypes,IdentifiersL,Freetypes),
1378 append(IdentifiersL,Identifiers),
1379 % create properties for each freetype
1380 foldl(create_properties_for_freetype(MType,RefMachines,NonGroundExceptions,Identifiers),
1381 RawFreetypes,IdsFreetypes,PropertiesL,Ein,Eout),
1382 conjunct_predicates(PropertiesL,Properties),
1383 (debug_mode(off) -> true
1384 ; format('Created PROPERTIES for FREETYPES:~n',[]), translate:nested_print_bexpr(Properties),nl),
1385 append_to_section(abstract_constants,Identifiers,Old,Inter),
1386 conjunct_to_section(properties,Properties,Inter,Inter2),
1387 write_section(freetypes,Freetypes,Inter2,New).
1388
1389 split_ft(ft(Ids,Freetype),Ids,Freetype).
1390
1391
1392 create_ids_for_freetype(FT,ft([TId|TCons],freetype(Id,Cases))) :-
1393 is_freetype_declaration(FT,_Pos,Id,_TypeParams,Constructors),
1394 !,
1395 create_typed_id(Id,set(freetype(Id)),TId),
1396 ? maplist(create_ids_for_constructor(Id),Constructors,TCons,Cases).
1397 create_ids_for_freetype(FT,_) :-
1398 add_internal_error('Illegal freetype term:',create_ids_for_freetype(FT,_)),fail.
1399
1400 % deconstruct a .prob Prolog encoding of a freetype declaration
1401 % new versions of parser generate freetype parameters
1402 is_freetype_declaration(freetype(Pos,Id,Constructors),Pos,Id,[],Constructors).
1403 is_freetype_declaration(freetype(Pos,Id,TypeParams,Constructors),Pos,Id,TypeParams,Constructors) :-
1404 (TypeParams=[] -> true ; add_warning(bmachine_construction,'Not yet supporting freetype parameters:',Id,Pos)).
1405
1406 create_ids_for_constructor(Id,constructor(_Pos,Name,_Arg),TCons,case(Name,Type)) :-
1407 create_typed_id(Name,set(couple(Type,freetype(Id))),TCons).
1408 create_ids_for_constructor(Id,element(_Pos,Name),TCons,case(Name,constant([Name]))) :-
1409 create_typed_id(Name,freetype(Id),TCons).
1410
1411 create_properties_for_freetype(MType,RefMachines,NonGroundExceptions, AllFTIdentifiers,
1412 FREETYPE,ft(Ids,_Freetypes),Properties,Ein,Eout) :-
1413 is_freetype_declaration(FREETYPE,_Pos,Id,_TypeParams,Constructors),
1414 debug_format(9,'Processing freetype ~w (one of ~w)~n',[Id,AllFTIdentifiers]),
1415 % The freetype type
1416 FType = freetype(Id),
1417 % We use the standard type environment of properties...
1418 visible_env(MType,properties,RefMachines,CEnv,Ein,E1),
1419 % ...plus the identifiers of the free type (type name and constructor names)
1420 add_identifiers_to_environment(Ids,CEnv,FEnv0),
1421 % ...plus the identifiers of all free type names (will overwrite Id, but not a problem)
1422 % Note: instead of adding all freetype ids, we could just add the ones preceding Id
1423 add_identifiers_to_environment(AllFTIdentifiers,FEnv0,FEnv),
1424 % We generate a comprehension set for all elements
1425 create_typed_id(Id,set(FType),TId),
1426 create_texpr(equal(TId,TComp),pred,[],FDef),
1427 unique_typed_id("_freetype_arg",FType,Element),
1428 create_recursive_compset([Element],ECond,set(FType),[],RecId,TComp),
1429 create_typed_id(RecId,set(FType),TRecId),
1430 % For each constructor, we generate a definition and a condition for the
1431 % comprehension set above
1432 foldl(create_properties_for_constructor(Id,FEnv,Element,TRecId,NonGroundExceptions),
1433 Constructors,Defs,Conds,E1,Eout),
1434 conjunct_predicates(Conds,ECond),
1435 conjunct_predicates([FDef|Defs],Properties).
1436
1437 /* create_properties_for_constructor(+Env,+Element,+RecId,+NGE,+Constructor,-Def,-Cond,Ein,Eout)
1438 Env: Type environment
1439 Element: A typed identifier "e" that is used in the definition of the freetype set:
1440 ft = {e | e has_freetype_constructor x => e:...}
1441 RecId: The typed identifier that can be used to refer to the freetype set (ft in the
1442 example above
1443 NGE: "Non ground exceptions", needed for type checking when having a parametrized machine
1444 Constructor: The constructor expression as it comes from the parser
1445 (constructor(Pos,Name,ArgSet) or element(Pos,Name))
1446 Def: The predicate that defines the constant for the constructor,
1447 e.g. "cons = {i,o | i:NAT & o = freetype(cons,i)}"
1448 Cond: The predicate that checks the argument of a freetype in the freetype set
1449 (That would be the part "e:..." in the example above.
1450 Ein,Eout: Used for type checker errors
1451 */
1452 create_properties_for_constructor(FID,Env,Element,RecId,NonGroundExceptions,
1453 Constructor,Def,Cond,Ein,Eout) :-
1454 constructor_name(Constructor,Name),
1455 env_lookup_type(Name,Env,CType),
1456 create_properties_for_constructor2(Constructor,Env,NonGroundExceptions,FID,
1457 Element,RecId,CDef,Cond,Ein,Eout),
1458 get_texpr_type(CDef,CType),
1459 create_typed_id(Name,CType,CId),
1460 create_texpr(equal(CId,CDef),pred,[],Def).
1461 constructor_name(element(_Pos,Name),Name).
1462 constructor_name(constructor(_Pos,Name,_Domain),Name).
1463 create_properties_for_constructor2(element(_Pos,Name),_Env,_NonGroundExceptions,FID,
1464 _Element,_RecId,CDef,Cond,Ein,Ein) :-
1465 create_texpr(value(freeval(FID,Name,term(Name))),freetype(FID),[],CDef),
1466 create_texpr(truth,pred,[],Cond).
1467 create_properties_for_constructor2(constructor(_Pos,Name,RArg),Env,NonGroundExceptions,
1468 FID,Element,RecId,CDef,Cond,Ein,Eout) :-
1469 % First, type check the given set of the domain:
1470 btype_ground_dl([RArg],Env,NonGroundExceptions,[set(DType)],[TDomain],Ein,Eout),
1471 % then create the RHS of "c = {i,o | i:Domain & o=freetype_constructor(Name,i)}"
1472 create_definition_for_constructor(Name,TDomain,FID,CDef),
1473 % The check in the freetype comprehension set is of the form
1474 % e "of_freetype_case" Name => "content_of"(e) : Domain
1475 create_texpr(implication(IsCase,DomainTest),pred,[],Cond),
1476 create_texpr(freetype_case(FID,Name,Element),pred,[],IsCase),
1477 create_texpr(freetype_destructor(FID,Name,Element),DType,[],Content),
1478 % all references to the freetype itself are replaced by the recursive reference
1479 replace_id_by_expr(TDomain,FID,RecId,TDomain2),
1480 create_texpr(member(Content,TDomain2),pred,[],DomainTest).
1481
1482 :- use_module(bsyntaxtree,[get_texpr_set_type/2]).
1483
1484 /* The constructor is a function to the freetype, defined with a comprehension set:
1485 The general form is "c = {i,o | i:Domain & o=freetype_constructor(Name,i)}"
1486 create_definition_for_constructor(+Name,+DType,+FID,-CType,-CDef) :-
1487 Name: Name of the constructor
1488 TDomain: The user-specified domain
1489 FID: The name of the free type
1490 CDef: The RHS of the definition "Name = CDef"
1491 */
1492 create_definition_for_constructor(Name,TDomain,FID,CDef) :-
1493 % get the type of the domain:
1494 get_texpr_set_type(TDomain,DType),
1495 % create argument and result identifiers:
1496 unique_typed_id("_constr_arg",DType,TArgId), % was constructor_arg and constructor_res
1497 unique_typed_id("_constr_res",freetype(FID),TResId),
1498 % The comprehension set as a whole
1499 CType = set(couple(DType,freetype(FID))),
1500 create_texpr(comprehension_set([TArgId,TResId],Pred),CType,
1501 [prob_annotation('SYMBOLIC')],CDef),
1502 create_texpr(conjunct(DomainCheck,Construction),pred,[],Pred),
1503 % "i:Domain"
1504 create_texpr(member(TArgId,TDomain),pred,[],DomainCheck),
1505 % "o=freetype_constructor(i)
1506 create_texpr(freetype_constructor(FID,Name,TArgId),freetype(FID),[],FreetypeCons),
1507 create_texpr(equal(TResId,FreetypeCons),pred,[],Construction).
1508
1509 % Operations
1510 create_operations_sections(RawMachine,Old,New) :-
1511 write_section(promoted,OperationIdentifiers,Old,New0),
1512 get_operation_identifiers(RawMachine,operations,OperationIdentifiers),
1513 (allow_local_or_expr_op_calls,
1514 get_operation_identifiers(RawMachine,local_operations,LocOpIDs),
1515 LocOpIDs \= []
1516 -> append_to_section(unpromoted,LocOpIDs,New0,New) % TODO: check that it does not yet exist
1517 ; New = New0
1518 ).
1519
1520 get_operation_identifiers(RawMachine,OperationIdentifiers) :-
1521 get_operation_identifiers(RawMachine,operations,OperationIdentifiers).
1522 get_operation_identifiers(RawMachine,SECTION,OperationIdentifiers) :-
1523 optional_rawmachine_section(SECTION,RawMachine,[],Ops),
1524 maplist(extract_operation_identifier,Ops,OperationIdentifiers).
1525 extract_operation_identifier(Ext,TId) :-
1526 remove_pos(Ext, operation(ExtId,_,_,_)),!,
1527 ext2int_with_pragma(ExtId,identifier(I),_,op(_,_),identifier(op(I)),Infos,TId),
1528 operation_infos(Infos).
1529 extract_operation_identifier(Ext,TId) :-
1530 remove_pos(Ext, refined_operation(ExtId,_,_,RefinesOp,_)),!,
1531 ext2int_with_pragma(ExtId,identifier(I),_,op(_,_),identifier(op(I)),[refines_operation(RefinesOp)|Infos],TId),
1532 operation_infos(Infos).
1533 extract_operation_identifier(Ext,TId) :-
1534 remove_pos(Ext, description_operation(_Desc,RealOp)),!,
1535 extract_operation_identifier(RealOp,TId).
1536 extract_operation_identifier(Ext,_) :- add_internal_error('Unknown operation node:',Ext),fail.
1537
1538 % VALUES section:
1539 % process_values_section(MachineType,RawMachine,NonGroundExceptions,Min/Ein/RefMIn,Mout/Eout/RefMOut):
1540 % Type-check the VALUES section and change the type of valuated deferred sets, if necessary
1541 % MachineType, RawMachine, NonGroundExceptions: as usual, see other comments
1542 % Min/Mout: The currently constructed machine
1543 % Ein/Eout: The difference list of errors
1544 % RefMin/RefMout: The list of already typechecked machines. These typechecked machines can be
1545 % altered by this predicate because if a deferred set is valuated by an integer set or
1546 % other deferred set, all occurrences of the original type are replaced by the new type,
1547 % even for the already typed machines.
1548 process_values_section(MachineType,RawMachine,NonGroundExceptions,Min/Ein/RefMIn,Mout/Eout/RefMOut) :-
1549 optional_rawmachine_section(values,RawMachine,[],RawValues),
1550 process_values_section_aux(RawValues,MachineType,NonGroundExceptions,
1551 Min/Ein/RefMIn,Mout/Eout/RefMOut).
1552 process_values_section_aux([],_MachineType,_NonGroundExceptions,In,Out) :- !,In=Out.
1553 process_values_section_aux(RawValues,MachineType,NonGroundExceptions,
1554 Min/Ein/RefMin,Mout/Eout/RefMout) :-
1555 debug_stats('TYPING VALUES'),
1556 type_values_section(MachineType,RawValues,RefMin,NonGroundExceptions,Min/Ein,Mout/Eout),
1557 % will be added as additional_property in bmachine
1558 RefMin=RefMout.
1559
1560 type_values_section(MachineType,RawValues,RefMachines,NonGroundExceptions,Min/Ein,Mout/Eout) :-
1561 write_section(values,Values,Min,Mout),
1562 visible_env(MachineType,values_expression,RefMachines,Env,Ein,E1),
1563 % We have to pass an environment that can be modified because in each
1564 % valuation the previously valuated constants can be used.
1565 foldl(extract_values_entry(NonGroundExceptions),RawValues,Values,Env/E1,_ResultingEnv/Eout).
1566
1567 extract_values_entry(NonGroundExceptions, values_entry(POS,ValueID,ValueExpr), Entry,
1568 EnvIn/Ein,EnvOut/Eout) :-
1569 % TODO: There seem to be a lot of additional constraints for valuations in VALUES that are not
1570 % yet handled here
1571 btype_ground_dl([ValueExpr],EnvIn,NonGroundExceptions,[Type],[TExpr],Ein,Eout),
1572 clean_up(TExpr,[],CTExpr), % ensure we remove things like mult_or_cart/2
1573 create_identifier(ValueID,POS,Type,[valuated_constant],TypedID),
1574 create_texpr(values_entry(TypedID,CTExpr),values_entry,[nodeid(POS)],Entry),
1575 debug_println(9,valued_constant(ValueID)),
1576 EnvOut=EnvIn.
1577 %add_identifiers_to_environment([TypedID],EnvIn,EnvOut). % ideally we should register the new type of TypedID
1578 % However: ProB can currently only process VALUES clauses where the type does not change
1579
1580 % type_section_with_single_predicate(+Sec,+Name,+SectionsToType,+MachineType,+Sections,
1581 % +RefMachines,+NonGroundExceptions,+Ein,-Eout,+Old,-New):
1582 % Type a section such as INVARIANT, PROPERTIES, CONSTRAINTS with a single predicate
1583 % Sec: section name in the raw (untyped) machine (e.g. invariant)
1584 % Name: name of machine from which this section comes
1585 % SectionsToType: list of section names that contain identifiers that must be typed
1586 % by this predicate (e.g. all variables must be typed by the invariant)
1587 % MachineType: machine type (machine, refinement, ...)
1588 % Sections: list of sections representing the raw (untyped) machine
1589 % RefMachines: list of already typed machines
1590 % NonGroundExceptions: list of types that may be not ground because the concrete type
1591 % is determinded by machine parameter
1592 % Ein/Eout: difference list of errors
1593 % Old/New: the new typed section is added (by conjunction) to the machine
1594 type_section_with_single_predicate(Sec,Name,SectionsToType,MachineType,Sections,
1595 RefMachines,NonGroundExceptions,Ein,Eout,Old,New) :-
1596 optional_rawmachine_section(Sec,Sections,truth(none),Predicate),
1597 ( Predicate = truth(_) ->
1598 % even if there is no content, we must check if all identifiers are typed
1599 check_if_all_ids_are_typed(SectionsToType,RefMachines,NonGroundExceptions,Ein,Eout),
1600 Old=New
1601 ;
1602 get_machine_infos(Sections,Infos),
1603 toplevel_raw_predicate_sanity_check(Sec,Name,Predicate,Infos),
1604 type_predicates(Sec,SectionsToType,MachineType,[Predicate],RefMachines,NonGroundExceptions,
1605 [Typed],Ein,Eout),
1606 conjunct_to_section(Sec,Typed,Old,New)
1607 ),
1608 !.
1609 type_section_with_single_predicate(Sec,Name,SectsToType,MchType,_,_,_,_,_,_,_) :-
1610 add_internal_error('type_section_with_single_predicate failed',
1611 type_section_with_single_predicate(Sec,Name,SectsToType,MchType,_,_,_,_,_,_,_)),
1612 fail.
1613
1614 % get some infos relevant for sanity check:
1615 get_machine_infos(Sections,Infos) :-
1616 ((rawmachine_section_exists(concrete_variables,Sections) ; rawmachine_section_exists(abstract_variables,Sections))
1617 -> Infos = [has_variables|I1] ; Infos = I1),
1618 ((rawmachine_section_exists(concrete_constants,Sections) ; rawmachine_section_exists(abstract_constants,Sections))
1619 -> I1 = [has_constants] ; I1 = []).
1620
1621 % Type a section with multiple predicates, such as ASSERTIONS
1622 type_section_with_predicate_list(Sec,SectionsToType,MachineType,Sections,
1623 RefMachines,NonGroundExceptions,Ein,Eout,Old,New) :-
1624 write_section(Sec,Typed,Old,New),
1625 optional_rawmachine_section(Sec,Sections,[],Predicates),
1626 type_predicates(Sec,SectionsToType,MachineType,Predicates,RefMachines,NonGroundExceptions,Typed,Ein,Eout),
1627 !.
1628 type_section_with_predicate_list(Sec,SectsToType,MchType,Sects,RefMchs,NonGrndExc,Ein,Eout,Old,New) :-
1629 add_internal_error('type_section_with_predicate_list failed',
1630 type_section_with_predicate_list(Sec,SectsToType,MchType,Sects,RefMchs,NonGrndExc,Ein,Eout,Old,New)),
1631 fail.
1632
1633
1634 type_predicates(_Sec,SectionsToType,_MachineType,[],RefMachines,NonGroundExceptions,Typed,Ein,Eout) :-
1635 !,Typed=[],
1636 check_if_all_ids_are_typed(SectionsToType,RefMachines,NonGroundExceptions,Ein,Eout).
1637 type_predicates(Sec,SectionsToType,MachineType,Predicates,RefMachines,NonGroundExceptions,Typed,Ein,Eout) :-
1638 visible_env(MachineType, Sec, RefMachines, Env, Ein, E1),
1639 same_length(Predicates,Types),maplist(is_pred_type,Types),
1640 btype_ground_dl_in_section(Sec,Predicates,Env,NonGroundExceptions,Types,Typed1,E1,E2),
1641 mark_with_section(Sec,Typed1,Typed),
1642 check_if_all_ids_are_typed(SectionsToType,RefMachines,NonGroundExceptions,E2,Eout),
1643 (no_perrors_occured(Ein,Eout)
1644 -> perform_post_static_check(Typed) % only run if no type errors, it makes use of find_typed_identifier_uses
1645 ; true
1646 ).
1647
1648 no_perrors_occured(Ein,Eout) :- Ein==Eout,!.
1649 no_perrors_occured([H|T],Eout) :- nonvar(H),not_a_perror(H),no_perrors_occured(T,Eout).
1650
1651 not_a_perror(warning(_,_)).
1652 % other possible values: error(Msg,Pos), internal_error(Msg,Pos); see get_perror/2
1653
1654 % check if the identifiers that should be typed by this section are completly typed
1655 check_if_all_ids_are_typed([],_RefMachines,_NonGroundExceptions,Ein,Eout) :- !,Ein=Eout.
1656 check_if_all_ids_are_typed(SectionsToType,RefMachines,NonGroundExceptions,Ein,Eout) :-
1657 memberchk(ref(local,Local),RefMachines),
1658 get_all_identifiers(SectionsToType,Local,IdentifiersToType),
1659 check_ground_types_dl(IdentifiersToType, NonGroundExceptions, Ein, Eout).
1660
1661
1662 mark_with_section(Sec,In,Out) :-
1663 maplist(mark_with_section2(Sec),In,Out).
1664 mark_with_section2(Sec,In,Out) :-
1665 remove_bt(In,conjunct(A,B),conjunct(NA,NB),Out),!,
1666 mark_with_section2(Sec,A,NA), mark_with_section2(Sec,B,NB).
1667 mark_with_section2(Sec,In,Out) :-
1668 add_texpr_infos(In,[section(Sec)],Out).
1669
1670 type_initialisation_section(Sections,Name,MType,RefMachines,NonGroundExceptions,Ein,Eout,Old,New) :-
1671 write_section(initialisation,Initialisation,Old,New),
1672 ( rawmachine_section(initialisation,Sections,Init) ->
1673 visible_env(MType, initialisation, RefMachines, InitEnv, Ein, E1),
1674 ? btype_ground_dl([Init],InitEnv,NonGroundExceptions,[subst],[TypedInit],E1,Eout),
1675 Initialisation=[init(Name,TypedInit)]
1676 ;
1677 Ein=Eout,
1678 Initialisation=[]).
1679
1680 :- use_module(library(ugraphs)).
1681
1682 type_operations_section(Sections,MType,RefMachines,NonGroundExceptions,Ein,Eout,Old,New) :-
1683 write_section(operation_bodies,Operations,Old,New),
1684 visible_env(MType, operation_bodies, RefMachines, Env, Ein, E1),
1685 optional_rawmachine_section(operations,Sections,[],Ops1),
1686 optional_rawmachine_section(local_operations,Sections,[], Ops2),
1687 append(Ops2,Ops1,Ops),
1688 topological_sort(Ops,Env,SOps),
1689 (debug_mode(off) -> true ; length(SOps,NrOps),debug_stats(finished_topological_sorting(NrOps))),
1690 same_length(SOps,Types), maplist(is_op_type,Types),
1691 ? btype_ground_dl(SOps,Env,NonGroundExceptions,Types,Operations,E1,Eout),!.
1692
1693 allow_local_or_expr_op_calls :-
1694 (get_preference(allow_local_operation_calls,true) -> true
1695 ; get_preference(allow_operation_calls_in_expr,true)).
1696 % at the moment ProB allows local calls inside expressions, independently of the allow_local_operation_calls preference
1697
1698 % perform a topological sort of the operations: treat called operation before calling operation
1699 % only relevant when allow_local_operation_calls is set to true
1700 topological_sort(Ops,Env,SortedOps) :-
1701 allow_local_or_expr_op_calls,
1702 findall(OtherID-ID, (member(Op,Ops),op_calls_op(Op,Env,ID,OtherID)),Edges),
1703 % print(edges(Edges)),nl,
1704 % TO DO: maybe only store edges where OtherID also appears in Ops (i.e., call within same machine)
1705 Edges \= [],
1706 !,
1707 findall(ID,(member(operation(_,RawID,_,_,_),Ops),raw_id(RawID,ID)),Vertices), %print(vertices(Vertices)),nl,
1708 vertices_edges_to_ugraph(Vertices,Edges,Graph),
1709 (top_sort(Graph,Sorted)
1710 -> sort_ops(Sorted,Ops,SortedOps)
1711 ; get_preference(allow_operation_calls_in_expr,true) ->
1712 add_warning(topological_sort,'Mutual recursion or cycle in the (local) operation call graph, this may cause problems computing reads information: ',Edges),
1713 SortedOps=Ops
1714 % not necessarily a problem, because operations called in expressions are not allowed to modify the state
1715 % TODO: however, we may have an issue with computing reads information correctly for mutual recursion !?
1716 % direct recursion should be ok
1717 ; add_error(topological_sort,'Cycle in the (local) operation call graph: ',Edges),
1718 SortedOps=Ops).
1719 topological_sort(Ops,_,Ops).
1720
1721 sort_ops([],Ops,Ops). % Ops should be []
1722 sort_ops([OpID|T],Ops,Res) :-
1723 raw_op_id(Op1,OpID),
1724 ? (select(Op1,Ops,TOps)
1725 -> Res = [Op1|TSOps], sort_ops(T,TOps,TSOps)
1726 ; % operation from another machine
1727 % print(could_not_find(OpID,Ops)),nl,
1728 sort_ops(T,Ops,Res)
1729 ).
1730
1731 is_op_type(op(_,_)).
1732 is_pred_type(pred).
1733
1734 % compute which other operations are directly called
1735 op_calls_op(operation(_,RawID,_,_,RawBody),Env,ID,OtherID) :- raw_id(RawID,ID),
1736 ? raw_body_calls_operation(RawBody,ID,Env,OtherID).
1737
1738 raw_body_calls_operation(RawBody,ID,Env,OtherID) :-
1739 ? raw_member(OpCall,RawBody),
1740 raw_op_call(OpCall,ID,Env,RawOtherID), raw_id(RawOtherID,OtherID).
1741
1742 raw_op_call(operation_call(_,RawOtherID,_,_),_,_, RawOtherID).
1743 raw_op_call(operation_call_in_expr(_,RawOtherID,_),ID,_, RawOtherID) :-
1744 \+ raw_id(RawOtherID,ID). % we do not look at direct recursion: it poses no problem for computing reads/writes info
1745 raw_op_call(function(_,RawOtherID,_), ID, Env, RawOtherID) :- % function calls possibly not yet translated to operation_call_in_expr
1746 get_preference(allow_operation_calls_in_expr,true),
1747 \+ raw_id(RawOtherID,ID), % direct recursion ok
1748 btypechecker:is_operation_call(RawOtherID,Env).
1749 raw_op_call(identifier(Pos,OtherID), ID, Env, RawOtherID) :- % possible operation call in expr without arguments
1750 OtherID \= ID, % direct recursion ok
1751 get_preference(allow_operation_calls_in_expr,true),
1752 RawOtherID = identifier(Pos,OtherID),
1753 btypechecker:is_operation_call(RawOtherID,Env).
1754
1755
1756 raw_op_id(operation(_,RawID,_,_,_RawBody),ID) :- raw_id(RawID,ID).
1757 raw_id(identifier(_,ID),ID).
1758
1759 % a utility function to work on the raw AST Functor(POS,Arg1,...,Argn)
1760 % this will not be able to look inside DEFINITIONS !
1761 % TO DO: deal with more raw substitutions which have list arguments
1762 raw_member(X,X).
1763 ?raw_member(X,parallel(_,List)) :- !, member(Term,List), raw_member(X,Term).
1764 ?raw_member(X,sequence(_,List)) :- !, member(Term,List), raw_member(X,Term).
1765 ?raw_member(X,[H|T]) :- !, (raw_member(X,H) ; raw_member(X,T)).
1766 raw_member(X,Term) :- compound(Term), Term =.. [_Functor,_Pos|Args],
1767 ? member(A,Args), raw_member(X,A).
1768
1769
1770 create_section_identifiers(Section,DestSection,RawMachine,Old,New) :-
1771 write_section(DestSection,Vars,Old,New),
1772 optional_rawmachine_section(Section,RawMachine,[],Identifiers),
1773 create_section_ids2(Identifiers,[],Vars,DestSection,New).
1774
1775 create_section_ids2([],_,[],_,_).
1776 create_section_ids2([Ext|Rest],Infos,Res,DestSection,MachSections) :-
1777 expand_definition_to_variable_list(Ext,MachSections,List),!,
1778 append(List,Rest,NewList),
1779 create_section_ids2(NewList,Infos,Res,DestSection,MachSections).
1780 create_section_ids2([Ext|Rest],Infos,Res,DestSection,MachSections) :-
1781 create_section_id(Ext,Infos,DestSection,TId),
1782 ( TId = error(Msg,Term,Pos) ->
1783 Res = TRest, add_error(bmachine_construction,Msg,Term,Pos)
1784 ;
1785 Res = [TId|TRest]),
1786 create_section_ids2(Rest,Infos,TRest,DestSection,MachSections).
1787 create_section_id(Ext,Infos,DestSection,TId) :-
1788 (unwrap_pragma(Ext,Ext2,PragmaInfos) -> append(PragmaInfos,Infos,FullInfos)
1789 ; Ext2=Ext, FullInfos=Infos),
1790 I=identifier(_),
1791 ( ext2int(Ext2,I,_Pos,_Type,I,FullInfos,TId) ->
1792 true
1793 ; Ext2 = definition(POSINFO,ID,_) ->
1794 TId = error('Trying to use DEFINITION name as identifier: ',
1795 (ID,within(DestSection)), POSINFO)
1796 ;
1797 TId = error('Illegal identifier: ',
1798 (Ext2,within(DestSection)), Ext2)
1799 ).
1800
1801 % support using DEFINITIONS which are variable lists;
1802 % currently for ProB parser you need to write VARS == (x,y,..) for Atelier-B: VARS == x,y,..
1803 expand_definition_to_variable_list(definition(_POSINFO,ID,_),MachSections,List) :-
1804 get_section(definitions,MachSections,Defs),
1805 member(definition_decl(ID,expression,_InnerPos,[],RawExpr,_Deps),Defs),
1806 extract_identifier_list(RawExpr,List,[]).
1807
1808 % convert a raw tuple into a raw identifier list:
1809 extract_identifier_list(identifier(Pos,ID)) --> [identifier(Pos,ID)].
1810 extract_identifier_list(couple(_,List)) -->
1811 extract_identifier_list(List).
1812 extract_identifier_list([]) --> [].
1813 extract_identifier_list([H|T]) --> extract_identifier_list(H), extract_identifier_list(T).
1814
1815 % calling ext2int conversion with pragma support
1816 ext2int_with_pragma(Ext,Expr,Pos,Type,Expr2,Infos,Elem) :-
1817 unwrap_pragma(Ext,ID,PragmaInfos),!,
1818 append(PragmaInfos,Infos,FullInfos),
1819 ext2int(ID,Expr,Pos,Type,Expr2,FullInfos,Elem).
1820 ext2int_with_pragma(Ext,Expr,Pos,Type,Expr2,FullInfos,Elem) :-
1821 ext2int(Ext,Expr,Pos,Type,Expr2,FullInfos,Elem).
1822
1823 unwrap_pragma(description(_,D,ID),ID,[description(D)]).
1824 unwrap_pragma(unit(_,U,ID),ID,[unit(U)]).
1825 unwrap_pragma(new_unit(_,U,ID),ID,[new_unit(U)]).
1826 unwrap_pragma(inferred_unit(_,_,ID),ID,[]). % currently ignored
1827 unwrap_pragma(inferredunit(_,_,ID),ID,[]). % currently ignored
1828
1829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1830 % sort the machines topologically
1831
1832 % can be used to store the result:
1833 assert_machine_order(Order) :-
1834 retractall(machine_global_order(_)),
1835 debug_print(9,machine_global_order(Order)),
1836 assertz(machine_global_order(Order)).
1837
1838 get_mach_position(Order,M,Ref,Pos-mch(M,Ref)) :-
1839 get_machine_name(M,Name),
1840 ? (nth1(Pos,Order,Name) -> true
1841 ; add_internal_error('Unknown machine:',Name:Order),
1842 Pos=0).
1843 get_machine(_-mch(M,_),M). % re-extract info after sorting
1844 get_reference(_-mch(_,R),R).
1845
1846 :- use_module(library(samsort),[samkeysort/2]).
1847 sort_machines_by_global_order(Machines,SortedMachines) :-
1848 sort_machines_by_global_order(Machines,_,SortedMachines,_).
1849 sort_machines_by_global_order(Machines,Refs,SortedMachines,SortedRefs) :-
1850 machine_global_order(Order),
1851 maplist(get_mach_position(Order),Machines,Refs,KM), % add position so that sorting works
1852 samkeysort(KM,SKM), % for test 925 it is important to keep duplicates and not use sort/2
1853 maplist(get_machine,SKM,SortedMachines),
1854 maplist(get_reference,SKM,SortedRefs),!.
1855 %maplist(get_machine_name,Sorted,SNs),print(sorted(SNs)),nl.
1856 sort_machines_by_global_order(M,R,M,R) :-
1857 add_internal_error('Sorting machines failed:',M).
1858
1859 % perform the actual computation:
1860 machine_order(Machines,Order) :-
1861 machine_dependencies(Machines,Dependencies),
1862 topsort(Dependencies,Order).
1863
1864 % sort the machines topologically
1865 topsort(Deps,Sorted) :-
1866 topsort2(Deps,[],Sorted).
1867 topsort2([],_,[]) :- !.
1868 topsort2(Deps,Known,Sorted) :-
1869 split_list(all_deps_known(Known),Deps,DAvailable,DNotAvailable),
1870 DAvailable = [_|_], % we have new machines available whose dependencies are all known
1871 !,
1872 maplist(dep_name,DAvailable,Available),
1873 append(Available,Known,NewKnown),
1874 append(Available,Rest,Sorted),
1875 topsort2(DNotAvailable,NewKnown,Rest).
1876 topsort2(Deps,_Known,_) :-
1877 member(dep(Name,NameDeps),Deps),
1878 add_error(bmachine_construction,'Could not resolve machine dependencies for: ',Name:depends_on(NameDeps)),
1879 fail.
1880
1881 ?all_deps_known(K,dep(_Name,Deps)) :- sort(Deps,DS),sort(K,KS),subseq0(KS,DS),!.
1882 dep_name(dep(Name,_Deps),Name).
1883
1884 % find dependencies between machines
1885 machine_dependencies(Machines,Dependencies) :-
1886 maplist(machine_dependencies2,Machines,Deps),
1887 sort(Deps,Dependencies).
1888 machine_dependencies2(M,dep(Name,Deps)) :-
1889 get_constructed_machine_name_and_body(M,Name,_,Body),
1890 findall(Ref,
1891 (refines(M,Ref);machine_reference(Body,Ref)),
1892 Deps).
1893
1894 machine_reference(MachineBody,Ref) :-
1895 ? ( member(sees(_,R),MachineBody)
1896 ? ; member(uses(_,R),MachineBody) ),
1897 ? member(identifier(_,PrefixRef),R),
1898 split_prefix(PrefixRef,_,Ref).
1899 machine_reference(MachineBody,Ref) :-
1900 ? ( member(includes(_,R),MachineBody)
1901 ? ; member(extends(_,R),MachineBody)
1902 ? ; member(imports(_,R),MachineBody) ),
1903 ? member(machine_reference(_,PrefixRef,_),R),
1904 split_prefix(PrefixRef,_,Ref).
1905
1906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1907 % refinements
1908 merge_refinement_and_abstraction(Concrete,RefMachines,Result,Ein,Eout) :-
1909 memberchk(ref(abstraction,Abstraction),RefMachines),
1910 append_sections([sets,concrete_constants,concrete_variables],Abstraction,Concrete,M1),
1911 append_if_new(abstract_constants,Abstraction,M1,M2),
1912 get_section(properties,Abstraction,AbstractProperties),
1913 conjunct_to_section(properties,AbstractProperties,M2,M3),
1914 % now get current invariant Invariant and filter out gluing/linking invariant
1915 % (the linking invariant talks about variables which no longer exist; hence we cannot check it anymore)
1916 select_section(invariant,Invariant,FullConcreteInvariant,M3,M4),
1917 write_section(linking_invariant,LinkingInvariant,M4,Merged),
1918 % we now also copy from the abstraction those invariants which are still valid
1919 get_section(invariant,Abstraction,AbstractInvariant),
1920 filter_abstract_invariant(AbstractInvariant,Concrete,AbsInvariantStillValid),
1921 filter_linking_invariant(Invariant,LinkingInvariant,ConcreteInvariant),
1922 conjunct_predicates([AbsInvariantStillValid,ConcreteInvariant],FullConcreteInvariant),
1923 propagate_abstract_operations(Abstraction,Merged,RefMachines,Result,Ein,Eout).
1924 merge_refinement_and_abstraction(Machine,_,Machine,Errors,Errors).
1925
1926 % append sections from abstract machine to concrete machine:
1927 append_sections(Sections,AbsMachine,Old,New) :-
1928 expand_shortcuts(Sections,AllSections),
1929 append_sections2(AllSections,AbsMachine,Old,New).
1930 append_sections2([],_,M,M).
1931 append_sections2([Section|Rest],AbsMachine,Old,New) :-
1932 get_section(Section,AbsMachine,Content),
1933 append_to_section3(Section,Content,Old,Inter),
1934 append_sections2(Rest,AbsMachine,Inter,New).
1935
1936 append_to_section3(Section,Content,Old,Inter) :- section_can_have_duplicates(Section),!,
1937 append_to_section_and_remove_dups(Section,Content,Old,Inter).
1938 append_to_section3(Section,Content,Old,Inter) :- append_to_section(Section,Content,Old,Inter).
1939
1940 :- assert_must_succeed((create_machine(abs,EA), create_machine(conc,EB),
1941 write_section(abstract_constants,[b(identifier(x),integer,[some_info])],EA,A),
1942 write_section(abstract_constants,[b(identifier(x),integer,[other_info]),
1943 b(identifier(y),integer,[info])],EB,B),
1944 append_if_new(abstract_constants,A,B,ResultM),
1945 get_section(abstract_constants,ResultM,ResultConst),
1946 ResultConst==[b(identifier(x),integer,[other_info]),
1947 b(identifier(y),integer,[info])]
1948 )).
1949
1950 append_if_new(Section,Machine,In,Out) :-
1951 get_section(Section,Machine,Content),
1952 select_section(Section,Old,New,In,Out),
1953 get_texpr_ids(Old,ExistingIds),
1954 exclude(is_in_existing_ids(ExistingIds),Content,NewElements),
1955 append(Old,NewElements,New).
1956 is_in_existing_ids(ExistingIds,TId) :-
1957 get_texpr_id(TId,Id),
1958 memberchk(Id,ExistingIds).
1959
1960 % filter linking and concrete invariant
1961 filter_linking_invariant(Invariant,Linking,Concrete) :-
1962 split_conjuncts(Invariant,Predicates),
1963 split_list(contains_abstraction_refs,Predicates,Linkings,Concretes),
1964 conjunct_predicates(Linkings,Linking),
1965 conjunct_predicates(Concretes,Concrete).
1966
1967
1968 % contains_abstraction_refs can be used on predicates of the current machine: the abstraction info field has been computed for this machine
1969 contains_abstraction_refs(TExpr) :-
1970 syntaxtraversion(TExpr,_,_,Infos,Subs,_),
1971 ( memberchk(abstraction,Infos) % This info field comes from the last argument of visibility/6
1972 -> true
1973 ? ; member(Sub,Subs),
1974 ? contains_abstraction_refs(Sub)).
1975
1976 % Determine which part of the abstract invariant can be imported into the refinement machine
1977 % TODO: should this be applied to WHILE loop INVARIANTS?
1978 filter_abstract_invariant(AbsInvariant,ConcreteMachine,ConcreteInv) :-
1979 split_conjuncts(AbsInvariant,Predicates),
1980 get_machine_sorted_variables(ConcreteMachine,SortedConcrVars),
1981 split_list(contains_abstract_variables(SortedConcrVars),Predicates,_Discard,Concretes),
1982 %print(discarded(_Discard)),nl,
1983 conjunct_predicates(Concretes,ConcreteInv). %, print('COPY: '), translate:print_bexpr(Concrete),nl.
1984 :- use_module(translate,[translate_bexpression/2]).
1985 contains_abstract_variables(SortedConcrVars,TExpr) :-
1986 ? contains_abstract_variables2(SortedConcrVars,TExpr,Cause),
1987 (silent_mode(on) -> true
1988 ; translate_bexpression(Cause,ID),
1989 ajoin(['Discarding abstract INVARIANT (requires variable "',ID,'"): '],Msg),
1990 add_message(bmachine_construction,Msg,TExpr,Cause)
1991 ).
1992 contains_abstract_variables2(SortedConcrVars,TExpr,Cause) :-
1993 syntaxtraversion(TExpr,Expr,Type,Infos,Subs,_),
1994 ( memberchk(loc(_,_Mch,abstract_variables),Infos) % are there other things that pose problems: abstract_constants ?
1995 -> %print('Abs: '),translate:print_bexpr(TExpr),nl, print(SortedConcrVars),nl,
1996 Cause=TExpr,
1997 \+ ord_member_nonvar_chk(b(Expr,Type,_),SortedConcrVars) % otherwise variable is re-introduced with same type
1998 % in some Event-B models: VARIABLES keyword is used and in refinement VARIABLES are re-listed
1999 % TO DO: check what happens when variable not immediately re-introduced
2000 ? ; member(Sub,Subs),
2001 ? contains_abstract_variables2(SortedConcrVars,Sub,Cause)
2002 ).
2003
2004 get_machine_sorted_variables(Machine,SortedAllVars) :-
2005 get_section(abstract_variables,Machine,AbsVars),
2006 get_section(concrete_variables,Machine,ConcVars),
2007 append(ConcVars,AbsVars,AllVars),
2008 sort(AllVars,SortedAllVars).
2009
2010 split_conjuncts(Expr,List) :-
2011 split_conjuncts2(Expr,List,[]).
2012 split_conjuncts2(Expr) -->
2013 {get_texpr_expr(Expr,conjunct(A,B)),!},
2014 split_conjuncts2(A),
2015 split_conjuncts2(B).
2016 split_conjuncts2(Expr) --> [Expr].
2017
2018 % copy the abstract operations or re-use their preconditions
2019 propagate_abstract_operations(Abstract,Concrete,RefMachines,Result,Ein,Eout) :-
2020 get_section(promoted,Abstract,APromoted),
2021 get_section(operation_bodies,Abstract,ABodies),
2022 % signature: select_section(SecName,OldContent,NewContent,OldMachine,NewMachine)
2023 select_section(promoted,CPromotedIn,CPromotedOut,Concrete,Concrete2),
2024 select_section(operation_bodies,CBodiesIn,CBodiesOut,Concrete2,Result),
2025 propagate_aops(APromoted,ABodies,RefMachines,CPromotedIn,CBodiesIn,CPromotedOut,CBodiesOut,Ein,Eout).
2026 propagate_aops([],_ABodies,_RefMachines,CPromoted,CBodies,CPromoted,CBodies,Errors,Errors).
2027 propagate_aops([APromoted|ApRest],ABodies,RefMachines,CPromotedIn,CBodiesIn,CPromotedOut,CBodiesOut,Ein,Eout) :-
2028 get_operation(APromoted,ABodies,AbstractOp),
2029 def_get_texpr_id(APromoted,op(APromotedOpName)),
2030 copy_texpr_wo_info(APromoted,CProm),
2031 ? ( member(CProm,CPromotedIn) ->
2032 debug_format(19,'Refining promoted abstract operation ~w to refinement machine.~n',[APromotedOpName]),
2033 extract_concrete_preconditions(AbstractOp,RefMachines,Pre),
2034 change_operation(APromoted,ConcreteOpOld,ConcreteOpNew,CBodiesIn,CBodiesRest),
2035 add_precondition(Pre,ConcreteOpOld,ConcreteOpNew), % propagate PRE down to concrete operation
2036 CPromotedIn = CPromotedRest,
2037 Ein = E1
2038 % TO DO: do not copy if event is refined at least once with renaming !
2039 ? ; is_refined_by_some_event(APromotedOpName,CPromotedIn,ConcreteOpName) ->
2040 debug_format(19,'Not copying abstract operation ~w to refinement machine, as it is refined by ~w.~n',[APromotedOpName,ConcreteOpName]),
2041 CPromotedRest=CPromotedIn, CBodiesRest=CBodiesIn,
2042 E1=Ein
2043 ;
2044 debug_format(19,'Copying abstract operation ~w to refinement machine, as it is not refined.~n',[APromotedOpName]),
2045 % TO DO: check that this is also the right thing to do for Atelier-B Event-B
2046 check_copied_operation(APromoted,AbstractOp,RefMachines,Ein,E1),
2047 append(CPromotedIn,[APromoted],CPromotedRest),
2048 append(CBodiesIn,[AbstractOp],CBodiesRest)
2049 ),
2050 propagate_aops(ApRest,ABodies,RefMachines,CPromotedRest,CBodiesRest,CPromotedOut,CBodiesOut,E1,Eout).
2051
2052 is_refined_by_some_event(AbstractName,CPromotedList,ConcreteName) :-
2053 ? member(TID,CPromotedList),
2054 get_texpr_info(TID,Infos),
2055 memberchk(refines_operation(AbstractName),Infos),
2056 def_get_texpr_id(TID,ConcreteName).
2057
2058 get_operation(TId,Bodies,Operation) :-
2059 select_operation(TId,Bodies,Operation,_BodiesRest).
2060 change_operation(TId,OldOp,NewOp,OldBodies,[NewOp|NewBodies]) :-
2061 select_operation(TId,OldBodies,OldOp,NewBodies).
2062 select_operation(TId,Bodies,Operation,BodiesRest) :-
2063 copy_texpr_wo_info(TId,OpId),
2064 get_texpr_expr(Operation,operation(OpId,_,_,_)),
2065 ? select(Operation,Bodies,BodiesRest),!.
2066
2067 extract_concrete_preconditions(Op,RefMachines,FPre) :-
2068 extract_preconditions_op(Op,Pre),
2069 extract_op_arguments(Op,Args),
2070 conjunction_to_list(Pre,Pres),
2071 % todo: check the "machine" parameter
2072 visible_env(machine,operation_bodies,RefMachines,Env1,_Errors,[]),
2073 store_variables(Args,Env1,Env),
2074 filter_predicates_with_unknown_identifiers(Pres,Env,FPres),
2075 conjunct_predicates(FPres,FPre).
2076
2077 extract_op_arguments(Op,Params) :-
2078 get_texpr_expr(Op,operation(_,_,Params,_)).
2079
2080 extract_preconditions_op(OpExpr,Pre) :-
2081 get_texpr_expr(OpExpr,operation(_,_,_,Subst)),
2082 extract_preconditions(Subst,Pres,_),
2083 conjunct_predicates(Pres,Pre).
2084 extract_preconditions(TExpr,Pres,Inner) :-
2085 get_texpr_expr(TExpr,Expr),
2086 extract_preconditions2(Expr,TExpr,Pres,Inner).
2087 extract_preconditions2(precondition(Pre,Subst),_,[Pre|Pres],Inner) :- !,
2088 extract_preconditions(Subst,Pres,Inner).
2089 extract_preconditions2(block(Subst),_,Pres,Inner) :- !,
2090 extract_preconditions(Subst,Pres,Inner).
2091 extract_preconditions2(_,Inner,[],Inner).
2092
2093 filter_predicates_with_unknown_identifiers([],_Env,[]).
2094 filter_predicates_with_unknown_identifiers([Pred|Prest],Env,Result) :-
2095 ( find_unknown_identifier(Pred,Env,_Id) ->
2096 !,Result = Rrest
2097 ;
2098 Result = [Pred|Rrest]),
2099 filter_predicates_with_unknown_identifiers(Prest,Env,Rrest).
2100 find_unknown_identifier(Pred,Env,Id) :-
2101 get_texpr_id(Pred,Id),!,
2102 \+ env_lookup_type(Id,Env,_).
2103 find_unknown_identifier(Pred,Env,Id) :-
2104 syntaxtraversion(Pred,_,_,_,Subs,Names),
2105 store_variables(Names,Env,Subenv),
2106 find_unknown_identifier_l(Subs,Subenv,Id).
2107 find_unknown_identifier_l([S|_],Env,Id) :-
2108 find_unknown_identifier(S,Env,Id),!.
2109 find_unknown_identifier_l([_|Rest],Env,Id) :-
2110 find_unknown_identifier_l(Rest,Env,Id).
2111
2112 :- use_module(library(ordsets),[ord_union/3]).
2113 % we add a precondition to an existing operation
2114 % Note: we need to update the reads info computed by the type checker (compute_accessed_vars_infos_for_operation)
2115 add_precondition(b(truth,_,_),Old,New) :- !, Old=New.
2116 add_precondition(Pre,b(Old,T,I),b(New,T,I2)) :-
2117 Old=operation(Id,Res,Params,Subst),
2118 New=operation(Id,Res,Params,NewSubst),
2119 extract_preconditions(Subst,OldPres,Inner),
2120 conjunct_predicates([Pre|OldPres],NewPre),
2121 create_texpr(precondition(NewPre,Inner),subst,[],NewSubst),
2122 ? (select(reads(OldReads),I,I1) % we do not have to update modifies(.), non_det_modifies(.), reads_locals(.),...
2123 -> I2=[reads(NewReads)|I1],
2124 get_texpr_ids(Params,Ignore),
2125 find_identifier_uses(Pre,Ignore,PreUsedIds),
2126 ord_union(PreUsedIds,OldReads,NewReads)
2127 ; add_internal_error('No reads info for operation: ',add_precondition(Pre,b(Old,T,I),b(New,T,I2))),
2128 I2=I).
2129
2130
2131
2132 check_copied_operation(OpRef,Op,RefMachines,Ein,Eout) :-
2133 % todo: check the "refinement" parameter
2134 visible_env(refinement,operation_bodies,RefMachines,Env1,_Errors,[]),
2135 get_texpr_id(OpRef,OpId),get_texpr_type(OpRef,OpType),
2136 env_store(OpId,OpType,[],Env1,Env),
2137 findall(U, find_unknown_identifier(Op,Env,U), Unknown1),
2138 sort(Unknown1,Unknown),
2139 ( Unknown=[] -> Ein=Eout
2140 ;
2141 op(OpName) = OpId,
2142 join_ids(Unknown,IdList),
2143 (Unknown = [_] -> Plural=[]; Plural=['s']),
2144 append([['Operation ',OpName,
2145 ' was copied from abstract machine but the identifier'],
2146 Plural,
2147 [' '],
2148 IdList,
2149 [' cannot be seen anymore']],Msgs),
2150 ajoin(Msgs,Msg), Ein = [error(Msg,none)|Eout]
2151 ).
2152 join_ids([I],[Msg]) :- !,opname(I,Msg).
2153 join_ids([A|Rest],[Msg,','|Mrest]) :- opname(A,Msg),join_ids(Rest,Mrest).
2154 opname(op(Id),Id) :- !.
2155 opname(Id,Id).
2156
2157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2158 % split an identifier into a (possible empty) prefix and the name itself
2159 % e.g. split_prefix('path.to.machine', 'path.to', 'machine').
2160 split_prefix(Term,Prefix,Main) :-
2161 one_arg_term(Functor,Arg,Term),!,
2162 one_arg_term(Functor,MArg,Main),
2163 split_prefix(Arg,Prefix,MArg).
2164 split_prefix(PR,Prefix,Main) :- %print(split_prefix(PR,Prefix,Main)),nl,trace,
2165 safe_atom_chars(PR,Chars,split_prefix1),
2166 split_prefix2(Chars,Chars,[],CPrefix,CMain),
2167 safe_atom_chars(Main,CMain,split_prefix2),
2168 safe_atom_chars(Prefix,CPrefix,split_prefix3).
2169 split_prefix2([],Main,_,[],Main).
2170 split_prefix2([C|Rest],Previous,PrefBefore,Prefix,Main) :-
2171 ( C='.' ->
2172 append(PrefBefore,RestPrefix,Prefix),
2173 split_prefix2(Rest,Rest,[C],RestPrefix,Main)
2174 ;
2175 append(PrefBefore,[C],NextPref),
2176 split_prefix2(Rest,Previous,NextPref,Prefix,Main)).
2177
2178 rawmachine_section(Elem,List,Result) :- %
2179 functor(Pattern,Elem,2),
2180 arg(2,Pattern,Result),
2181 ? select(Pattern,List,Rest),!,
2182 (functor(Pattern2,Elem,2),member(Pattern2,Rest)
2183 -> arg(1,Pattern2,Pos),
2184 add_error(bmachine_construction,'Multiple sections for: ',Elem,Pos)
2185 ; true).
2186
2187 optional_rawmachine_section(Elem,List,Default,Result) :-
2188 ( rawmachine_section(Elem,List,Result1) -> true
2189 ; Result1=Default),
2190 Result1=Result.
2191
2192 one_arg_term(Functor,Arg,Term) :- %print(one_arg_term(Functor,Arg,Term)),nl,
2193 functor(Term,Functor,1),arg(1,Term,Arg).
2194
2195 % check if a rawmachine section list has a given section
2196 rawmachine_section_exists(Elem,List) :- %
2197 functor(Pattern,Elem,2),
2198 ? (member(Pattern,List) -> true).
2199
2200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2201 % visibility rules
2202
2203 % the visibility/5 predicate declares what a part of a machine can see
2204 % visibility(MType, Scope, Section, Access, Info) means:
2205 % In a machine of type MType (machine, refinement, implementation),
2206 % an expression in a Section (like invariant) can see
2207 % the identifiers in the Access sections. Access is a list of
2208 % sections, where shortcuts are allowed (see shortcut/2, e.g., shortcut(operations,[unpromoted,promoted]).).
2209 % Scope defines where (in relation to the Section)
2210 % the section in Access are (local: same machine, included: in an
2211 % included machine, etc.)
2212 % Info is a list of additional information that is added to each
2213 % identifier in the environment to build up. E.g. in an operation
2214 % definition, constants are marked readonly.
2215 visibility(machine, local, constraints, [parameters],[]).
2216 visibility(machine, local, includes, [parameters,sets,constants],[]).
2217 visibility(machine, local, properties, [sets,constants],[]).
2218 visibility(machine, local, invariant, [parameters,sets,constants,variables],[]).
2219 visibility(machine, local, operation_bodies, [parameters,sets,constants],[readonly]).
2220 visibility(machine, local, operation_bodies, [operations],Info) :- Info =[readonly,dontcall].
2221 % an operation to be readonly: means we cannot assign to it; but the operation itself can change variables
2222 % for allow_operation_calls_in_expr=true we check that operation is inquiry in type checker
2223 % (get_preference(allow_operation_calls_in_expr,true) -> Info = [inquiry]
2224 % ; Info =[readonly,dontcall] ). % we check in btype(operation_call_in_expr)
2225 visibility(machine, local, operation_bodies, [variables],[]).
2226 ?visibility(machine, local, initialisation, Access,[not_initialised|Info]) :- visibility(machine,local,operation_bodies,Access,Info).
2227
2228 visibility(machine, Scope, assertions, [Allow],[inquiry|DC]) :-
2229 (Scope = local -> Allow=operations, DC=[dontcall] ; Allow=promoted, DC=[]),
2230 get_preference(allow_operation_calls_in_expr,true). % if we allow calling operations in expressions
2231 visibility(machine, Scope, invariant, [promoted],[inquiry]) :-
2232 Scope \= local, % do not allow calling local operations in invariant; their correctness relies on the invariant
2233 get_preference(allow_operation_calls_in_expr,true).
2234
2235 visibility(machine, included, properties, [sets,constants],[]).
2236 visibility(machine, included, invariant, [sets,constants,variables],[]).
2237 visibility(machine, included, operation_bodies, [sets,constants,variables],[readonly]).
2238 visibility(machine, included, operation_bodies, [promoted],Info) :- Info = [readonly].
2239 % for allow_operation_calls_in_expr=true we check that operation is inquiry in type checker
2240 % (get_preference(allow_operation_calls_in_expr,true) -> Info = [inquiry] ; Info=[readonly]).
2241 visibility(machine, included, initialisation, [sets,constants,variables,promoted],[readonly]).
2242
2243 visibility(machine, used, properties, [sets,constants],[]).
2244 visibility(machine, used, invariant, [parameters,sets,constants,variables],[]).
2245 visibility(machine, used, operation_bodies, [parameters,sets,constants,variables],[readonly]).
2246 visibility(machine, used, initialisation, [parameters,sets,constants,variables],[readonly]).
2247 visibility(machine, used, operation_bodies, [operations],[inquiry]) :-
2248 get_preference(allow_operation_calls_for_uses,true). %% added by leuschel, allowed in Schneider Book
2249 % but not allowed by Atelier-B; see test 2135
2250
2251 visibility(machine, seen, includes, [sets,constants],[]).
2252 visibility(machine, seen, properties, [sets,constants],[]).
2253 visibility(machine, seen, invariant, [sets,constants],[]).
2254 visibility(machine, seen, operation_bodies, [sets,constants,variables],[readonly]).
2255 visibility(machine, seen, initialisation, [sets,constants,variables],[readonly]).
2256 visibility(machine, seen, operation_bodies, [operations],[inquiry]). %% added by leuschel, allow query operation
2257
2258 visibility(refinement, local, Section, Access, Info) :-
2259 Section \= assertions, % assertions are handled below
2260 ? visibility(machine, local, Section, Access, Info).
2261
2262 visibility(refinement, abstraction, includes, [sets,concrete_constants],[]).
2263 visibility(refinement, abstraction, properties, [sets,constants],[]).
2264 visibility(refinement, abstraction, invariant, [sets,constants,concrete_variables],[]).
2265 visibility(refinement, abstraction, invariant, [abstract_variables],[abstraction]).
2266 visibility(refinement, abstraction, operation_bodies, [sets,concrete_constants],[readonly]).
2267 visibility(refinement, abstraction, operation_bodies, [concrete_variables],[]).
2268
2269 visibility(refinement, included, properties, [sets,constants],[]).
2270 visibility(refinement, included, invariant, [sets,constants,variables],[]).
2271 visibility(refinement, included, operation_bodies, [sets,constants,variables,promoted],[re]). % What is re ??? TO DO: investigate
2272
2273 visibility(refinement, seen, includes, [sets,constants],[]).
2274 visibility(refinement, seen, properties, [sets,constants],[]).
2275 visibility(refinement, seen, invariant, [sets,constants],[]).
2276 visibility(refinement, seen, operation_bodies, [sets,constants,variables],[readonly]).
2277 visibility(refinement, seen, operation_bodies, [operations],[inquiry]).
2278
2279 visibility(refinement, Ref, initialisation, Access, [not_initialised|Info]) :-
2280 ? visibility(refinement,Ref,operation_bodies,Access,Info).
2281
2282 % assertions have same visibility as invariant
2283 visibility(MType, Ref, assertions, Part, Access) :-
2284 ? visibility(MType,Ref,invariant,Part,Access).
2285
2286 visibility(implementation, Ref, Section, Part, Access) :-
2287 ? visibility(refinement, Ref, Section, Part, Access).
2288 visibility(implementation, local, values_expression, [concrete_constants,sets],[]). % seems to have no effect (yet); see ArrayValuationAImp
2289 visibility(implementation, included, values_expression, [concrete_constants,sets],[]).
2290 visibility(implementation, seen, values_expression, [concrete_constants,sets],[]).
2291 visibility(implementation, abstraction,values_expression, [concrete_constants,sets],[]).
2292
2293 % For predicates over pre- and post-states
2294 visibility(MType, Rev, prepost, Access, Info) :-
2295 ? visibility(MType, Rev, invariant, Access, Info).
2296 visibility(MType, Rev, prepost, Access, [primed,poststate|Info]) :-
2297 ? visibility(MType, Rev, invariant, Access, Info).
2298
2299 % add error messages for some common mistakes (access to parameters in the properties)
2300 visibility(machine, local, properties, [parameters], [error('a parameter cannot be accessed in the PROPERTIES section')]).
2301 % the following rule should be helpful for the user, but additionally it also
2302 % provides a mechanism to re-introduce abstract variables in the INVARIANT
2303 % section of a while loop (to enable this, an identifier is also marked with "abstraction")
2304 % in the predicate allow_access_to_abstract_var
2305 visibility(refinement, abstraction, operation_bodies, [abstract_variables],
2306 [error('illegal access to an abstract variable in an operation'),abstraction]).
2307 visibility(refinement, abstraction, operation_bodies, [abstract_constants],
2308 [error('illegal access to an abstract constant in an operation (only allowed in WHILE INVARIANT or ASSERT)'),abstraction]).
2309
2310
2311 % lookups up all identifier sections that are accessible from
2312 % the given section, removes all shortcuts and removes
2313 % duplicate entries
2314 %
2315 % Returns a list of vis(Section,Info) where Section is the
2316 % identifier section that can be seen with Info as a list
2317 % of additional information
2318 expanded_visibility(MType, Ref, Part, Access) :-
2319 findall(vis(Section,Infos),
2320 ( visibility(MType,Ref,Part,Sections1,Infos),
2321 expand_shortcuts(Sections1,Sections),
2322 member(Section,Sections)),
2323 Access1),
2324 sort(Access1,Access).
2325 %format('MType=~w, Ref=~w, Part=~w~n Vis=~w~n',[MType,Ref,Part,Access]).
2326
2327 % visible_env/6 creates a type environment for a certain
2328 % part of a machine by looking up which identifier should
2329 % be visible from there and what additional information should
2330 % be added (e.g. to restrict access to read-only)
2331 %
2332 % The visibility/6 facts are used to define which identifier are visible
2333 %
2334 % MType: machine type (machine, refinement, ...)
2335 % Part: part of the machine for which the environment should be created
2336 % RefMachines: referred machines that are already typed
2337 % Env: The created environment
2338 % Errors: errors might be added if multiple variables with the same identifier
2339 % are declared
2340 visible_env(MType, Part, RefMachines, Env, Err_in, Err_out) :-
2341 env_empty(Init),
2342 visible_env(MType, Part, RefMachines, Init, Env, Err_in, Err_out).
2343 % visible_env/7 is like visible_env/6, but an initial environment
2344 % can be given in "In"
2345 visible_env(MType, Part, RefMachines, In, Out, Err_in, Err_out) :-
2346 foldl(visible_env2(MType,Part),RefMachines,In/Err_in,Out/Err_out).
2347 visible_env2(MType,Part,ref(Scope,Machine),InEnvErr,OutEnvErr) :-
2348 get_machine_name(Machine,MName),
2349 %format('adding identifiers from machine ~w for scope ~w~n',[MName,Scope]),
2350 ( Scope == local ->
2351 get_section(definitions,Machine,Defs),
2352 %nl,print(adding_defs(Defs)),nl,nl,
2353 foldl(env_add_def(MName),Defs,InEnvErr,InterEnvErr)
2354 ;
2355 InEnvErr=InterEnvErr),
2356 expanded_visibility(MType, Scope, Part, Access),
2357 foldl(create_vis_env(Scope,MName,Machine),Access,InterEnvErr,OutEnvErr).
2358 env_add_def(MName,definition_decl(Name,PType,Pos,Params,Body,_Deps),InEnvErr,OutEnvErr) :-
2359 Type = definition(PType,Params,Body),
2360 Info = [nodeid(Pos),loc(local,MName,definitions)],
2361 create_texpr(identifier(Name),Type,Info,TExpr),
2362 add_unique_variable(TExpr,InEnvErr,OutEnvErr),!.
2363 env_add_def(MName,Def,EnvErr,EnvErr) :-
2364 add_internal_error('Cannot deal with DEFINITION: ',env_add_def(MName,Def)).
2365
2366 create_vis_env(Scope,MName,IDS,vis(Section,Infos),InEnvErr,OutEnvErr) :-
2367 get_section(Section,IDS,Identifiers1),
2368 %get_texpr_ids(Identifiers2,II),format('Got identifiers for ~w:~w = ~w~n',[MName,Section,II]),
2369 (Section=freetypes
2370 -> generate_free_type_ids(Identifiers1,Identifiers2)
2371 ; Identifiers2=Identifiers1),
2372 maplist(add_infos_to_identifier([loc(Scope,MName,Section)|Infos]),Identifiers2,Identifiers),
2373 foldl(add_unique_variable,Identifiers,InEnvErr,OutEnvErr).
2374
2375 % freetypes: generate IDs for Z freetype section
2376 % The classical B FREETYPE section is dealt with in another place (TODO: unify this)
2377 generate_free_type_ids([freetype(FTypeId,Cases)|T],[b(identifier(FTypeId),set(freetype(FTypeId)),[])|FT]) :- !,
2378 findall(b(identifier(CaseID),CaseType,[]),
2379 (member(case(CaseID,ArgType),Cases), gen_freecase_type(ArgType,FTypeId,CaseType)),
2380 FT, FT2),
2381 %write(generated_freetype_cases(FT)),nl,
2382 generate_free_type_ids(T,FT2).
2383 generate_free_type_ids(T,T).
2384
2385 gen_freecase_type(ArgType,FTypeId,Type) :- nonvar(ArgType), ArgType=constant(_),!, Type = freetype(FTypeId).
2386 gen_freecase_type(ArgType,FTypeId,set(couple(ArgType,freetype(FTypeId)))).
2387
2388 add_unique_variable(Var1,Old/Err_in,New/Err_out) :-
2389 optionally_rewrite_id(Var1,Var),
2390 get_texpr_id(Var,Id),
2391 get_texpr_type(Var,Type),
2392 get_texpr_info(Var,InfosOfNew),!,
2393 ( env_lookup_type(Id,Old,_) ->
2394 % we have a collision of two identifiers
2395 handle_collision(Var,Id,Type,Old,InfosOfNew,New,Err_in,Err_out)
2396 ;
2397 % no collision, just introduce the new identifier
2398 env_store(Id,Type,InfosOfNew,Old,New),
2399 %btypechecker:portray_env(New),nl,
2400 Err_in=Err_out
2401 ).
2402 add_unique_variable(Var,Env/Err,Env/Err) :- print(Var),nl,
2403 ( Var = b(definition(DEFNAME,_),_,INFO) ->
2404 add_error(add_unique_variable,'DEFINITION used in place of Identifier: ',DEFNAME,INFO)
2405 ; Var = b(description(Txt,_),_,INFO) ->
2406 add_error(add_unique_variable,'Unsupported @desc pragma: ',Txt,INFO)
2407 ;
2408 add_error(add_unique_variable,'Expected Identifier, but got: ',Var,Var)
2409 ).
2410
2411 add_infos_to_identifier(NewInfos,In,Out) :-
2412 add_texpr_infos(In,NewInfos,Out).
2413
2414 % get the ID of the variable, prime it if the infos contain "primed"
2415 optionally_rewrite_id(Var,NewVar) :-
2416 get_texpr_info(Var,InfosIn),
2417 ( selectchk(primed,InfosIn,InfosOut) ->
2418 get_texpr_id(Var,Id1),
2419 get_texpr_type(Var,Type),
2420 atom_concat(Id1,'\'',Id),
2421 create_texpr(identifier(Id),Type,InfosOut,NewVar)
2422 ;
2423 Var = NewVar).
2424
2425 :- use_module(translate,[translate_span/2]).
2426 % in case of a collision, we have three options:
2427 % - overwrite the old identifier,
2428 % - ignore the new identifier or
2429 % - generate an error message
2430 handle_collision(Var,Name,Type,OldEnv,InfosOfNew,NewEnv,Ein,Eout) :-
2431 env_lookup_infos(Name,OldEnv,InfosOfExisting),
2432 %btypechecker:portray_env(OldEnv),nl,
2433 ? ( collision_precedence(Name,InfosOfExisting,InfosOfNew) ->
2434 % this identifier should be ignored
2435 OldEnv = NewEnv,
2436 Ein = Eout
2437 ; collision_precedence(Name,InfosOfNew,InfosOfExisting) ->
2438 % the existing should be overwritten
2439 env_store(Name,Type,InfosOfNew,OldEnv,NewEnv),
2440 Ein = Eout
2441 ;
2442 % generate error and let the environment unchanged
2443 (Name = op(IName) -> true; Name=IName),
2444 get_texpr_pos(Var,Pos1),
2445 safe_get_info_pos(InfosOfExisting,Pos2),
2446 ? ( double_inclusion_allowed(Name,Pos1,Pos2,InfosOfExisting)
2447 -> %print(double_inclusion_of_id_allowed(Name,Type,Pos1,OldEnv,InfosOfExisting)),nl,
2448 OldEnv=NewEnv,
2449 Ein=Eout
2450 ? ; (better_pos(Pos2,Pos1), \+ better_pos(Pos1,Pos2)
2451 -> Pos = Pos2, translate_span(Pos1,PS1)
2452 ; Pos = Pos1,
2453 PS1='' % Pos1 is already part of error span
2454 ),
2455 translate_span(Pos2,PS2),
2456 translate_inclusion_path(InfosOfExisting,Path2),
2457 get_texpr_info(Var,Info1), translate_inclusion_path(Info1,Path1),
2458 %ajoin(['Identifier \'', IName, '\' declared twice at (Line:Col[:File]) ', PS1, Path1, ' and ', PS2, Path2],Msg),
2459 ajoin(['Identifier \'', IName, '\'', PS1, Path1, ' already declared at ', PS2, Path2],Msg),
2460 %format(user_error,'*** ~w~n',[Msg]),trace,
2461 Ein = [error(Msg,Pos)|Eout],
2462 OldEnv = NewEnv
2463 )
2464 ).
2465
2466
2467 % example identifier: %b(identifier(aa),integer,[loc(seen,M2,concrete_constants),readonly,usesee(M2,aa,seen),origin([included/M1]),nodeid(pos(18,2,2,11,2,13))])
2468
2469 % try and infer inclusion path of identifier from Infos
2470 ?translate_inclusion_path(Infos,Str) :- member(loc(How,Machine,_Section),Infos),!,
2471 (member(origin(Path),Infos) -> get_origin_path(Path,T) ; T=[')']),
2472 ajoin([' (', How,' from ', Machine|T],Str).
2473 translate_inclusion_path(_,'').
2474
2475 get_origin_path([How/Machine|T],[', ', How,' from ',Machine|TRes]) :- !,
2476 get_origin_path(T,TRes).
2477 get_origin_path(_,[')']).
2478
2479
2480 % SEE ISSUE PROB-403, test 1857
2481 % Correct behaviour related to multiple instantiation is specified in
2482 % B Reference Manual (AtelierB 4.2.1), 8.3 B Project/Instantiating and renaming.
2483 % => Constants and Sets defined in machines instantiated multiple times CAN be used in the including machine with their original (non-prefixed names).
2484 % Note: this code did lead to the constants being added multiple times; this has been fixed in concat_section_contents
2485 double_inclusion_allowed(Name,Pos1,Pos2,InfosOfExisting) :-
2486 %print(check_double_inclusion(Name,Pos1,Pos2,InfosOfExisting)),nl,
2487 Pos1==Pos2,
2488 %print(chk(InfosOfExisting)),nl,
2489 ? member(loc(LOC,_,Section),InfosOfExisting),
2490 %print(try(LOC,Section)),nl,
2491 section_can_be_included_multiple_times_nonprefixed(Section),
2492 % check that we are in a context of an included machine identifier:
2493 (inclusion_directive(LOC,Name,Pos2)
2494 -> true
2495 ; %LOC is probably local
2496 ? member(origin([INCL/_MACHINE|_]),InfosOfExisting),
2497 inclusion_directive(INCL,Name,Pos2)
2498 ).
2499
2500 inclusion_directive(included,_,_).
2501 inclusion_directive(used,_,_).
2502 inclusion_directive(seen,_,_). % imports ??
2503 inclusion_directive(abstraction,Name,Pos) :- % probably not allowed by Atelier-B
2504 (debug_mode(off) -> true
2505 ; add_message(bmachine_construction,'Allowing double inclusion from abstraction of: ',Name,Pos)).
2506
2507 section_can_be_included_multiple_times_nonprefixed(abstract_constants).
2508 section_can_be_included_multiple_times_nonprefixed(concrete_constants).
2509 section_can_be_included_multiple_times_nonprefixed(sets).
2510 section_can_be_included_multiple_times_nonprefixed(enumerated_sets).
2511 section_can_be_included_multiple_times_nonprefixed(enumerated_elements).
2512 section_can_be_included_multiple_times_nonprefixed(deferred_sets). % added 2.12.2022
2513 section_can_be_included_multiple_times_nonprefixed(constants). % shortcut
2514
2515
2516 % decide which position info is better: prefer info in main file (highlighting)
2517 :- use_module(bmachine,[b_get_main_filenumber/1]).
2518 better_pos(Pos,_) :- get_position_filenumber(Pos,Filenumber),
2519 b_get_main_filenumber(Filenumber).
2520 better_pos(_,none).
2521
2522 safe_get_info_pos(Info,Pos) :- (get_info_pos(Info,Pos) -> true ; Pos=none).
2523
2524 % collision_precedence/3 decides if the first variable takes
2525 % precedence over the second in case of a collision
2526 % the decision is made by the additional information of both
2527 % variables
2528 collision_precedence(_Name,PreferredVarInfos,DroppedVarInfos) :-
2529 % in case of a re-introduced variable from the abstraction,
2530 % we prefer the concrete variable to the abstract one.
2531 ? is_abstraction(DroppedVarInfos,PreferredVarInfos),!.
2532 collision_precedence(_Name,PreferredVarInfos,DroppedVarInfos) :-
2533 % We are checking an Event-B model with multi-level support
2534 % and have the same variable in two different refinement levels.
2535 % Then the one in the more refined module takes precedence
2536 member(level(L1),PreferredVarInfos),
2537 member(level(L2),DroppedVarInfos),
2538 % Level 0 is the abstract level, level 1 the first refinement, etc.
2539 L1 > L2,!.
2540 collision_precedence(Name,PreferredVarInfos,DroppedVarInfos) :-
2541 % A local definition takes precedence over a non-local identifier
2542 % TODO:
2543 member(loc(local,_DefMachine,definitions),PreferredVarInfos),
2544 ? member(loc(_,_VarMachine,Section),DroppedVarInfos),
2545 Section \= definitions,!,
2546 (preferences:get_preference(warn_if_definition_hides_variable,true)
2547 % default is true; we could also check clash_strict_checks
2548 ? -> get_id_kind(Section,HiddenIdKind),
2549 (get_info_pos(PreferredVarInfos,Pos1), Pos1 \= none,
2550 get_info_pos(DroppedVarInfos,Pos2), Pos2 \= none
2551 -> translate:translate_span(Pos1,Pos1Str), translate:translate_span(Pos2,Pos2Str),
2552 ajoin(['Warning: DEFINITION of ', Name, ' at ', Pos1Str,
2553 ' hides ',HiddenIdKind,' with same name at ', Pos2Str, '.'], Msg)
2554 ; ajoin(['Warning: DEFINITION of ', Name, ' hides ',HiddenIdKind,' with same name.'], Msg),
2555 Pos1 = unknown
2556 ),
2557 store_warning(Msg,Pos1) % TO DO: add position info
2558 ; true
2559 ).
2560 % TO DO: allow identical DEFINITIONS ?
2561
2562 % translate section name into a name for the identifier
2563 get_id_kind(abstract_constants,'constant').
2564 get_id_kind(concrete_constants,'constant').
2565 get_id_kind(parameters,'parameter').
2566 get_id_kind(deferred_sets,'deferred set').
2567 get_id_kind(enumerated_sets,'enumerated set').
2568 get_id_kind(enumerated_elements,'enumerated set element').
2569 get_id_kind(freetypes,'freetype').
2570 get_id_kind(promoted,'operation').
2571 % TODO: complete and use in other places
2572 get_id_kind(_SectionName,'variable').
2573
2574
2575 % is_abstraction/2 tries to find out if (in case of a name clash of
2576 % two variables) the second variable is just the re-introduced abstract
2577 % variable in a refinement.
2578 % InfosAbs is the list of information about the abstract variable
2579 % InfosConc is the list of information about the concrete variable
2580 is_abstraction(InfosAbs,InfosConc) :-
2581 % one variable is an abstract variable, introduced in the abstraction
2582 ? member(loc(abstraction,_,abstract_variables),InfosAbs),
2583 % the other is either an abstract or concrete variable,
2584 ? member(VarType,[abstract_variables,concrete_variables]),
2585 % introduced either locally or in an included machine
2586 ? member(Scope,[local,included]),
2587 ? member(loc(Scope,_,VarType),InfosConc).
2588 % and the same for constants:
2589 is_abstraction(InfosAbs,InfosConc) :-
2590 % one variable is an abstract variable, introduced in the abstraction
2591 ? member(loc(abstraction,_,abstract_constants),InfosAbs),
2592 % the other is either an abstract or concrete variable,
2593 ? member(VarType,[abstract_constants,concrete_constants]),
2594 % introduced either locally or in an included machine
2595 ? member(Scope,[local,included]),
2596 ? member(loc(Scope,_,VarType),InfosConc).
2597
2598 % shortcuts for sections, to ease the use of typical combinations of
2599 % sections
2600 shortcut(all_parameters,[parameters,internal_parameters]).
2601 shortcut(sets,[deferred_sets,enumerated_sets,enumerated_elements|T]) :-
2602 (animation_minor_mode(M), (M=z ; M=eventb)
2603 -> T = [freetypes]
2604 ; T = []). % The FREETYPES section in classical B is unfortunately dealt with differently and
2605 % we currently have errors if add the freetypes section here
2606 shortcut(constants,[abstract_constants,concrete_constants]).
2607 shortcut(variables,[abstract_variables,concrete_variables]).
2608 shortcut(operations,[unpromoted,promoted]).
2609 shortcut(identifiers,[all_parameters,sets,constants,variables,operations]).
2610
2611 expand_shortcuts(Sections,Expanded) :-
2612 foldl(expand_shortcut,Sections,Expanded,[]).
2613 expand_shortcut(Section,Sections,RSections) :-
2614 ( shortcut(Section,Expanded) ->
2615 foldl(expand_shortcut,Expanded,Sections,RSections)
2616 ; valid_section(Section) ->
2617 Sections = [Section|RSections]
2618 ;
2619 add_internal_error('invalid section',expand_shortcut(Section,Sections,RSections)),fail).
2620
2621 % find sections that can see given sections
2622 find_relevant_sections(RSecs,MTypes,Result) :-
2623 expand_shortcuts(RSecs,Sections),
2624 findall(R,
2625 ( member(MType,MTypes),
2626 visibility(MType,local,R,SAccess,_),
2627 expand_shortcuts(SAccess,Access),
2628 member(S,Sections),
2629 member(S,Access),
2630 valid_section(R)),
2631 Result1),
2632 sort(Result1,Result).
2633
2634
2635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2636 % renaming
2637
2638 rename_relevant_sections(DefSecs,Renamings,Machine,New) :-
2639 find_relevant_sections(DefSecs,[machine],Relevant),
2640 ? rename_in_sections(Relevant,Renamings,Machine,New).
2641 rename_in_sections([],_,M,M).
2642 rename_in_sections([Section|Rest],Renamings,Old,New) :-
2643 select_section_texprs(Section,OTExprs,NTExprs,Old,Inter),
2644 ? rename_bt_l(OTExprs,Renamings,NTExprs),
2645 ? rename_in_sections(Rest,Renamings,Inter,New).
2646
2647 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2648 % cleaning up machine
2649 clean_up_machine(In,RefMachines,Out) :-
2650 extract_parameter_types([ref(local,In)|RefMachines],NonGroundExceptions),
2651 clean_up_machine2(NonGroundExceptions,In,Out).
2652 clean_up_machine2(NonGroundExceptions) -->
2653 get_section_content(enumerated_sets,Enum),
2654 get_section_content(enumerated_elements,Elems),
2655 {register_enumerated_sets(Enum,Elems)}, % register name of enumerated sets, e.g., to detect finite in ast_cleanup
2656 % TODO: also register enumerated_elements
2657 clean_up_section(constraints,NonGroundExceptions),
2658 clean_up_section(properties,NonGroundExceptions),
2659 clean_up_section(invariant,NonGroundExceptions),
2660 clean_up_section(initialisation,NonGroundExceptions),
2661 clean_up_section(assertions,NonGroundExceptions),
2662 clean_up_section(operation_bodies,NonGroundExceptions).
2663 :- load_files(library(system), [when(compile_time), imports([environ/2])]).
2664 :- if(environ(prob_safe_mode,true)).
2665 clean_up_section(Section,NonGroundExceptions,In,Out) :-
2666 select_section_texprs(Section,Old,New,In,Out),
2667 %format('Cleaning up and optimizing section ~w~n',[Section]), %maplist(check_ast,Old), % this will raise errors
2668 clean_up_l_with_optimizations(Old,NonGroundExceptions,New,Section),
2669 %format('Checking result of clean_up section ~w~n',[Section]),
2670 maplist(check_ast(true),New),
2671 formatsilent('Finished checking section ~w~n',[Section]).
2672 :- else.
2673 clean_up_section(Section,NonGroundExceptions,In,Out) :-
2674 % debug_stats(cleaning_up(Section)),
2675 select_section_texprs(Section,Old,New,In,Out),
2676 clean_up_l_with_optimizations(Old,NonGroundExceptions,New,Section).
2677 :- endif.
2678
2679 get_section_content(SecName,SectionContent,Mch,Mch) :- get_section(SecName,Mch,SectionContent).
2680
2681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2682 % type expressions in context of an already type-checked machine
2683 % TO DO: maybe do some performance optimisations for identifiers, values, ... to avoid creating scope, see formula_typecheck2_for_eval optimisation
2684 % b_type_literal does it in bmachine before calling type_in_machine_l
2685 type_in_machine_l(Exprs,Scope,Machine,Types,TExprs,Errors) :-
2686 MType = machine,
2687 create_scope_if_necessary(Exprs,Scope,MType,Machine,Env,Errors,E1), % this can be expensive for big B machines
2688 %runtime_profiler:profile_single_call(create_scope,unknown,
2689 % bmachine_construction:create_scope(Scope,MType,Machine,Env,Errors,E1)),
2690 btype_ground_dl(Exprs,Env,[],Types,TExprUncleans,E1,[]),
2691 perform_post_static_check(TExprUncleans),
2692 ? maplist(clean_up_pred_or_expr([]),TExprUncleans,TExprs).
2693
2694 % detect a few common expressions which do not require creating a scope of all the identifiers
2695 create_scope_if_necessary([E],_Scope,MType,Machine,Env,Ein,Eout) :- raw_expr_wo_ids(E),!,
2696 create_scope([],MType,Machine,Env,Ein,Eout).
2697 create_scope_if_necessary(_Exprs,Scope,MType,Machine,Env,Ein,Eout) :-
2698 create_scope(Scope,MType,Machine,Env,Ein,Eout).
2699
2700 % a few common raw ASTs which do not refer to identifiers
2701 raw_expr_wo_ids(falsity(_)).
2702 raw_expr_wo_ids(truth(_)).
2703 raw_expr_wo_ids(empty_set(_)).
2704 raw_expr_wo_ids(equal(_,A,B)) :- raw_expr_wo_ids(A), raw_expr_wo_ids(B).
2705 raw_expr_wo_ids(not_equal(_,A,B)) :- raw_expr_wo_ids(A), raw_expr_wo_ids(B).
2706 raw_expr_wo_ids(interval(_,A,B)) :- raw_expr_wo_ids(A), raw_expr_wo_ids(B).
2707 raw_expr_wo_ids(add(_,A,B)) :- raw_expr_wo_ids(A), raw_expr_wo_ids(B).
2708 raw_expr_wo_ids(minus_or_set_subtract(_,A,B)) :- raw_expr_wo_ids(A), raw_expr_wo_ids(B).
2709 raw_expr_wo_ids(mult_or_cart(_,A,B)) :- raw_expr_wo_ids(A), raw_expr_wo_ids(B).
2710 raw_expr_wo_ids(unary_minus(_,A)) :- raw_expr_wo_ids(A).
2711 raw_expr_wo_ids(boolean_true(_)).
2712 raw_expr_wo_ids(boolean_false(_)).
2713 raw_expr_wo_ids(bool_set(_)).
2714 raw_expr_wo_ids(integer(_,_)).
2715 raw_expr_wo_ids(real(_,_)).
2716 raw_expr_wo_ids(string(_,_)).
2717
2718 % note prob_ids(visible) scope is expanded somewhere else
2719 create_scope(Scope,MType,Machine,Env,Ein,Eout) :-
2720 env_empty(Init),
2721 add_theory_operators(Machine,Init,WithOperators),
2722 foldl(create_scope2(MType,Machine),Scope,WithOperators/Ein,Env/Eout).
2723 add_theory_operators(Machine,Ein,Eout) :-
2724 get_section(operators,Machine,Operators),
2725 keys_and_values(Operators,Ids,Ops),
2726 foldl(env_store_operator,Ids,Ops,Ein,Eout).
2727 create_scope2(MType,Machine,Scope,In/Ein,Out/Eout) :-
2728 ( Scope = constants ->
2729 visible_env(MType,properties,[ref(local,Machine)],In,Out,Ein,Eout)
2730 ; Scope = variables ->
2731 visible_env(MType,invariant,[ref(local,Machine)],In,Out,Ein,Eout)
2732 ; Scope = assertions_scope ->
2733 visible_env(MType,assertions,[ref(local,Machine)],In,Out,Ein,Eout)
2734 ; Scope = prepost ->
2735 visible_env(MType,prepost,[ref(local,Machine)],In,Out,Ein,Eout)
2736 ; Scope = operation_bodies ->
2737 visible_env(MType,operation_bodies,[ref(local,Machine)],In,Out,Ein,Eout)
2738 ; Scope = operation(Op) ->
2739 create_operation_scope(Op,Machine,In,Out), Ein=Eout
2740 ; Scope = env(ExplicitEnv) ->
2741 ExplicitEnv = Out, Ein=Eout
2742 ; Scope = identifier(Ids) ->
2743 store_variables(Ids,In,Out), Ein=Eout
2744 ; Scope = external_library(LibName) % be sure to make these last to avoid duplication errors
2745 -> store_ext_defs(LibName,In,Out), Ein=Eout
2746 ;
2747 add_error(bmachine_construction, 'invalid scope', Scope),fail).
2748 create_operation_scope(Op,Machine,In,Out) :-
2749 get_section(operation_bodies,Machine,OpBodies),
2750 get_texpr_id(OpId,op(Op)),
2751 get_texpr_expr(TOp,operation(OpId,Results,Params,_)),
2752 ? ( member(TOp,OpBodies) ->
2753 append(Results,Params,LocalVariables),
2754 store_variables(LocalVariables,In,Out)
2755 ;
2756 ajoin(['operation \'',Op,'\' not found for building scope'], Msg),
2757 add_error(bmachine_construction,Msg),fail).
2758 store_variables(Ids,In,Out) :- foldl(store_variable,Ids,In,Out).
2759 store_variable(Id,In,Out) :-
2760 get_texpr_id(Id,Name),get_texpr_type(Id,Type),
2761 env_store(Name,Type,[],In,Out).
2762
2763 type_open_predicate_with_quantifier(OptionalOuterQuantifier,Predicate,Scope,Machine,TResult,Errors) :-
2764 ? type_open_formula(Predicate,Scope,false,Machine,pred,Identifiers,TPred,Errors),
2765 ( Identifiers = [] ->
2766 TResult = TPred
2767 ; OptionalOuterQuantifier=forall ->
2768 create_forall(Identifiers,TPred,TResult)
2769 ; OptionalOuterQuantifier=no_quantifier ->
2770 TResult = TPred
2771 ; % OptionalOuterQuantifier=exists
2772 %perform_do_not_enumerate_analysis(Identifiers,TPred,'EXISTS',Span,TPred2), % now done by apply_kodkod_or_other_optimisations
2773 create_exists(Identifiers,TPred,TResult)
2774 ).
2775
2776 type_open_formula(Raw,Scope,AllowOpenIdsinExpressions,Machine,Type,Identifiers,Result,Errors) :-
2777 create_scope_if_necessary([Raw],Scope,machine,Machine,Env1,Errors,E1),
2778 ( Identifiers==[] -> Mode=closed, Env1=Env
2779 ; Mode=open, openenv(Env1,Env)),
2780 btype_ground_dl([Raw],Env,[],[Type],[TExprUnclean],E1,E2),
2781 ( Mode=closed -> true
2782 ;
2783 openenv_identifiers(Env,Identifiers), % TODO: treat theory operators ?
2784 check_ground_types_dl(Identifiers,[],E2,E3)
2785 ),
2786 %print(type_open_formula(Identifiers,TExprUnclean)),nl,
2787 mark_outer_quantifier_ids(TExprUnclean,TExprUnclean2),
2788 perform_post_static_check([TExprUnclean2]),
2789 ? clean_up_pred_or_expr([],TExprUnclean2,TResult), % TODO: only run if requested
2790 ( Identifiers = [] -> % no newly introduced identifiers, no problem
2791 E3 = []
2792 ; Type = pred -> % newly introduced identifiers in a predicate - ok
2793 E3 = []
2794 ; AllowOpenIdsinExpressions=true -> % we explicitly allow open ids in expressions
2795 E3 = []
2796 ; % newly introduced identifiers in expression make no sense
2797 % (is that so?)
2798 foldl(add_unknown_identifier_error,Identifiers,E3,[])
2799 ),
2800 Result = TResult.
2801 add_unknown_identifier_error(TId,[error(Msg,Pos)|E],E) :-
2802 get_texpr_id(TId,Id),
2803 ajoin(['Unknown identifier ',Id,'.'],Msg),
2804 % TO DO: generate fuzzy match and possible completions message
2805 get_texpr_pos(TId,Pos).
2806
2807 % mark outermost identfiers so that they don't get optimized away
2808 % e.g., ensure that we print the solution for something like #(y2,x2).(x2 : 0..10 & y2 : 0..10 & x2 = 10 & y2 = 10)
2809 mark_outer_quantifier_ids(b(exists(IDS,Pred),pred,Info),Res) :-
2810 maplist(mark_id,IDS,MIDS),!,
2811 Res = b(exists(MIDS,Pred),pred,Info).
2812 mark_outer_quantifier_ids(b(let_predicate(IDS,Exprs,Pred),pred,Info),Res) :-
2813 maplist(mark_id,IDS,MIDS),!,
2814 Res = b(let_predicate(MIDS,Exprs,Pred),pred,Info).
2815 mark_outer_quantifier_ids(b(forall(IDS,LHS,RHS),pred,Info),Res) :-
2816 maplist(mark_id,IDS,MIDS),!,
2817 Res = b(forall(MIDS,LHS,RHS),pred,Info).
2818 mark_outer_quantifier_ids(X,X).
2819
2820 mark_id(b(identifier(ID),TYPE,INFO),b(identifier(ID),TYPE,[do_not_optimize_away|INFO])).
2821
2822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2823
2824 % some additional static checks; they should be run only once before ast_cleanup runs
2825 % TO DO: move maybe some of the exists/forall checks here; would be simpler and not require removed_typing inspection
2826
2827 :- use_module(bsyntaxtree,[map_over_typed_bexpr/2]).
2828 perform_post_static_check([Typed|_]) :- %print(t(Typed)),nl,
2829 preferences:get_preference(disprover_mode,false),
2830 map_over_typed_bexpr(post_static_check,Typed),
2831 fail.
2832 perform_post_static_check([_|T]) :- !, perform_post_static_check(T).
2833 perform_post_static_check(_).
2834
2835 post_static_check(b(E,T,I)) :-
2836 %bsyntaxtree:check_infos(I,post_static_check),
2837 post_static_check_aux(E,T,I).
2838
2839 :- use_module(bsyntaxtree,[find_identifier_uses/3, is_a_disjunct_or_implication/4]).
2840 :- use_module(library(ordsets),[ord_subtract/3]).
2841 % should detect patterns like { zz | # r__1, q__1, zz . ( ...)}
2842 % {x,z|z=1}[{TRUE}] = {1}
2843 % %x.(1=1|1)(TRUE) = 1
2844 post_static_check_aux(lambda(Ids,Body,Expr),_T,Info) :-
2845 get_texpr_ids(Ids,AtomicIds), sort(AtomicIds,SortedIds),
2846 find_identifier_uses(Body,[],UsedIds1),
2847 find_identifier_uses(Expr,[],UsedIds2), % relevant for tests 1106, 1264, 1372, 1622 to also look at Expr
2848 ord_subtract(SortedIds,UsedIds1,S2),
2849 ord_subtract(S2,UsedIds2,UnusedIds), UnusedIds \= [],
2850 add_warning_with_info('Condition of lambda does not use these identifiers: ',UnusedIds,Body,Info).
2851 post_static_check_aux(comprehension_set(Ids,Body),_T,Info) :-
2852 get_texpr_ids(Ids,AtomicIds), sort(AtomicIds,SortedIds),
2853 find_identifier_uses(Body,[],UsedIds),
2854 ord_subtract(SortedIds,UsedIds,UnusedIds), UnusedIds \= [],
2855 add_warning_with_info('Body of comprehension set does not use these identifiers: ',UnusedIds,Body,Info).
2856 post_static_check_aux(exists(_,P),_T,Info) :-
2857 is_a_disjunct_or_implication(P,Type,_Q,_R),
2858 exists_body_warning(P,Info,Type).
2859
2860
2861 exists_body_warning(_,_,_) :- animation_minor_mode(X),(X=eventb ; X=tla),!.
2862 exists_body_warning(P,I,Type) :-
2863 translate_bexpression(P,PS),
2864 ajoin(['Warning: body of existential quantifier is a ',Type,
2865 ' (not allowed by Atelier-B): '],Msg),
2866 add_warning_with_info(Msg,PS,P,I).
2867
2868
2869 :- use_module(bsyntaxtree,[contains_info_pos/1]).
2870 add_warning_with_info(Msg1,Msg2,P,Info) :-
2871 (contains_info_pos(Info) -> Pos=Info ; Pos=P),
2872 add_warning(bmachine_construction,Msg1,Msg2,Pos).
2873
2874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2875 % Warnings
2876
2877 :- dynamic warnings/2.
2878 clear_warnings :-
2879 retractall( warnings(_,_) ).
2880 show_warnings :-
2881 warnings(Warning,Span),
2882 add_warning(bmachine_construction, Warning,'',Span),
2883 fail.
2884 show_warnings.
2885
2886
2887 store_warning(Warning,Span) :-
2888 (warnings(Warning,Span) -> true ; assertz(warnings(Warning,Span))).