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_structure,[ create_machine/2 % create a new, empty machine |
6 | | , get_machine_name/2 % get the name of the machine |
7 | | , valid_section/1 % checks if the given section exists |
8 | | , get_section/3 % get the content of a section |
9 | | , write_section/4 % overwrite the content of a section |
10 | | , select_section/5 % modify the content of a section |
11 | | , get_section_of_machines/3 % get one section for multiple machines |
12 | | , get_section_texprs/3 % get all typed expressions of a section |
13 | | , select_section_texprs/5 % modify the typed expressions of a section |
14 | | , append_to_section/4 % append a list to a section |
15 | | , append_to_section_and_remove_dups/4 % append a list and remove duplicates |
16 | | , conjunct_to_section/4 % write the conjunction of the new and old value |
17 | | ]). |
18 | | |
19 | | :- use_module(tools_lists,[is_list_simple/1]). |
20 | | :- use_module(error_manager,[add_internal_error/2]). |
21 | | :- use_module(bsyntaxtree). |
22 | | |
23 | | :- use_module(module_information,[module_info/2]). |
24 | | :- module_info(group,typechecker). |
25 | | :- module_info(description,'Here is the data structure defined that holds a complete B machine.'). |
26 | | |
27 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
28 | | % access to machines |
29 | | |
30 | | % creates an empty machine |
31 | | create_machine(Name,M) :- |
32 | | create_texpr(truth,pred,[initial],Truth), |
33 | | M = machine(Name, |
34 | | [deferred_sets/[], enumerated_sets/[], enumerated_elements/[], |
35 | | parameters/[], internal_parameters/[], |
36 | | abstract_constants/[], concrete_constants/[], |
37 | | abstract_variables/[], concrete_variables/[], |
38 | | promoted/[], unpromoted/[], |
39 | | |
40 | | constraints/Truth, |
41 | | properties/Truth, |
42 | | invariant/Truth, |
43 | | linking_invariant/Truth, |
44 | | assertions/[], |
45 | | |
46 | | initialisation/[], |
47 | | operation_bodies/[], |
48 | | definitions/[], |
49 | | used/[], |
50 | | freetypes/[], |
51 | | operators/[], |
52 | | values/[], |
53 | | |
54 | | meta/[] |
55 | | ]). |
56 | | |
57 | | get_machine_name(machine(Name,_),Res) :- !, Res=Name. |
58 | | get_machine_name(M,Res) :- add_internal_error('Illegal machine: ',get_machine_name(M,Res)), Res = '?'. |
59 | | |
60 | | % checks if the given secion exists |
61 | | valid_section(Sec) :- |
62 | ? | create_machine(_,machine(_,List)), member(Sec/_,List),!. |
63 | | |
64 | | % get the content of a section |
65 | | get_section(Sec,machine(_,List),Content) :- !, |
66 | | memberchk(Sec/C,List),C=Content. |
67 | | get_section(Sec,M,C) :- |
68 | | add_internal_error('Illegal machine:',get_section(Sec,M,C)),fail. |
69 | | |
70 | | % overwrite the content of a section |
71 | | write_section(Sec,Content,Old,New) :- select_section(Sec,_,Content,Old,New). |
72 | | |
73 | | |
74 | | % modify the content of a section |
75 | | select_section(Sec,OldContent,NewContent,machine(Name,OldM),machine(Name,NewM)) :- |
76 | | select_section2(OldM,NewM,Sec,O,N),!, |
77 | | O=OldContent,N=NewContent. |
78 | | select_section(Sec,Old,_,M,NewM) :- |
79 | | add_internal_error('Section does not exist:',select_section(Sec,Old,_,M,NewM)), |
80 | | Old=[],NewM=M. |
81 | | select_section2([Sec/C1|R1],[Sec/C2|R2],Select,O,N) :- |
82 | | ( Sec==Select -> O=C1, N=C2, R1=R2 |
83 | | ; C1=C2, select_section2(R1,R2,Select,O,N)). |
84 | | |
85 | | % append the content to a section (section content must be a list) |
86 | | append_to_section(_Sec,Content,Old,New) :- Content==[],!,Old=New. |
87 | | append_to_section(Sec,Content,Old,New) :- |
88 | | select_section(Sec,Before,App,Old,New), |
89 | | append(Before,Content,App). |
90 | | |
91 | | % just append new elements to a section; removes duplicates |
92 | | append_to_section_and_remove_dups(Sec,Content,Old,New) :- |
93 | | select_section(Sec,Before,App2,Old,New), |
94 | | append(Before,Content,App), |
95 | | remove_dups_merge_origin(App,App2). % ideally we should just remove dups from Content, not Before |
96 | | |
97 | | :- use_module(library(avl)). |
98 | | :- use_module(library(lists),[select/3, subseq0/2]). |
99 | | % remove duplicates, apart from the origin field, which can be merged if compatible |
100 | | remove_dups_merge_origin([],[]). |
101 | | remove_dups_merge_origin([H|T],[H|Res]) :- |
102 | | empty_avl(E), decompose_texpr_origin(H,HT,HO), |
103 | | avl_store(HT,E,HO,A1), |
104 | | rem_dups_o(T,A1,Res). |
105 | | |
106 | ? | decompose_texpr_origin(b(E,T,I),b(E,T,I2),Origin) :- select(origin(Origin),I,I2),!. |
107 | | decompose_texpr_origin(TE,TE,[]). |
108 | | origin_compatible(StoredOrigin,NewOrigin) :- |
109 | ? | (subseq0(StoredOrigin,NewOrigin) -> true % the origin is included in the stored origin |
110 | | ; print(incompatible_origin),nl,fail). % TODO: merge |
111 | | |
112 | | rem_dups_o([],_,[]). |
113 | | rem_dups_o([H|T],AVL,Res) :- |
114 | | decompose_texpr_origin(H,HTExpr,NewOrigin), |
115 | | (avl_fetch(HTExpr,AVL,StoredOrigin), |
116 | | origin_compatible(StoredOrigin,NewOrigin) |
117 | | -> rem_dups_o(T,AVL,Res) |
118 | | ; Res=[H|TRes], |
119 | | avl_store(HTExpr,AVL,NewOrigin,AVL1), |
120 | | rem_dups_o(T,AVL1,TRes)). |
121 | | |
122 | | % --------------- |
123 | | |
124 | | % append the content to a section (section content must be a list) |
125 | | conjunct_to_section(Sec,Content,Old,New) :- |
126 | | select_section(Sec,Before,App,Old,New), |
127 | | conjunct_predicates([Before,Content],App). |
128 | | |
129 | | % get the content of a section |
130 | | % get_section_of_machines(List of Machine,Name of Section,List of Content) |
131 | | get_section_of_machines([],_,[]). |
132 | | get_section_of_machines([Machine|MRest],Section,[Content|CRest]) :- |
133 | | get_section(Section,Machine,Content), |
134 | | get_section_of_machines(MRest,Section,CRest). |
135 | | %get_sections([],_,[]). |
136 | | %get_sections([Sec|Rest],M,[Content|CRest]) :- |
137 | | % get_section(Sec,M,Content),get_sections(Rest,M,CRest). |
138 | | |
139 | | % get all typed expressions of a section |
140 | | get_section_texprs(Sec,Machine,TExprs) :- |
141 | | get_section(Sec,Machine,Content), |
142 | ? | extract_sec_texprs(Sec,Content,TExprs). |
143 | | extract_sec_texprs(Sec,C,C) :- has_texpr_l(Sec). |
144 | | extract_sec_texprs(Sec,C,[C]) :- has_texpr(Sec). |
145 | | extract_sec_texprs(initialisation,C,I) :- |
146 | | ( is_texpr(C) -> I=[C] |
147 | | ; is_list_simple(C) -> findall(Subst,member(init(_,Subst),C),I)). |
148 | | |
149 | | % modify the typed expressions of a section |
150 | | select_section_texprs(Sec,OldTExprs,NewTExprs,OldMachine,NewMachine) :- |
151 | | select_section(Sec,OldContent,NewContent,OldMachine,NewMachine), |
152 | | change_sec_texprs(Sec,OldContent,OldTExprs,NewTExprs,NewContent). |
153 | | change_sec_texprs(Sec,O,O,N,N) :- has_texpr_l(Sec),!. |
154 | | change_sec_texprs(Sec,O,[O],[N],N) :- has_texpr(Sec),!. |
155 | | change_sec_texprs(initialisation,O,OI,NI,N) :- |
156 | | ( is_list_simple(O) |
157 | | -> change_init(O,OI,NI,N) |
158 | | ; OI=[O], NI=[N]). |
159 | | |
160 | | change_init([],[],[],[]). |
161 | | change_init([init(Name,O)|IOrest],[O|Orest],[N|Nrest],[init(Name,N)|INrest]) :- |
162 | | change_init(IOrest,Orest,Nrest,INrest). |
163 | | |
164 | | |
165 | | has_texpr_l(Sec) :- |
166 | | memberchk(Sec,[deferred_sets, enumerated_sets, enumerated_elements, |
167 | | parameters, internal_parameters, abstract_constants, concrete_constants, |
168 | | abstract_variables, concrete_variables, |
169 | | promoted, unpromoted, assertions, |
170 | | operation_bodies,values]). |
171 | | has_texpr(Sec) :- memberchk(Sec,[constraints, properties, invariant]). |