1 | % (c) 2017-2019 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(alloy2b,[load_alloy_ast_prolog_file/1, | |
6 | load_alloy_model/2, | |
7 | load_alloy_model/3, | |
8 | translate_alloy_model/2]). | |
9 | ||
10 | :- use_module(probsrc(debug)). | |
11 | :- use_module(library(lists)). | |
12 | :- use_module(library(plunit)). | |
13 | :- use_module(probsrc(bmachine)). | |
14 | :- use_module(probsrc(translate)). | |
15 | :- use_module(library(file_systems)). | |
16 | :- use_module(probsrc(error_manager)). | |
17 | :- use_module(library(sets),[subtract/3]). | |
18 | :- use_module(probsrc(specfile),[set_animation_minor_mode/1]). | |
19 | :- use_module(library(ordsets),[ord_intersection/3, ord_union/3, ord_subtract/3]). | |
20 | ||
21 | :- dynamic enumerated_set/1, singleton_set/1, total_function/2, ordered_signature/1, command_counter/1, extending_signatures/1, is_sub_signature_of/3, is_seq/1, current_command/1, maxseq/1, uses_seqs/0. | |
22 | :- volatile enumerated_set/1, singleton_set/1, total_function/2, ordered_signature/1, command_counter/1, extending_signatures/1, is_sub_signature_of/3, is_seq/1, current_command/1, maxseq/1, uses_seqs/0. | |
23 | ||
24 | :- meta_predicate map_translate(3,-,-,-). | |
25 | ||
26 | command_counter(0). | |
27 | ||
28 | % An automated translation from Alloy to classical B. | |
29 | % The Alloy abstract syntax tree is translated to an untyped B AST as supported by ProB. | |
30 | % Afterwards, the untyped AST can be typechecked and loaded by ProB. | |
31 | % The used positions are from the Alloy parser and thus refer to the Alloy model. | |
32 | ||
33 | % Usage: | |
34 | % load_alloy_model/2: input is an Alloy model represented as a Prolog term as provided by the Kotlin translation; the model is translated to an untyped B AST and loaded by ProB | |
35 | % translate_alloy_model/2: input is an Alloy model represented as a Prolog term as provided by the Kotlin translation, output is an untyped B AST | |
36 | ||
37 | % Run tests: | |
38 | % - launch ProB Tcl/Tk or ProB CLI | |
39 | % - 'use_module(extension('alloy2b/alloy2b')).' | |
40 | % - 'error_manager:reset_errors , plunit:run_tests(full_machine_translation).'. | |
41 | % - run a single test: 'error_manager:reset_errors , plunit:run_tests(full_machine_translation:directctrl).' | |
42 | % - 'bmachine:full_b_machine(L) , translate:print_machine(L)'. | |
43 | ||
44 | % KNOWN ISSUES / TO DOs | |
45 | % ---------------------- | |
46 | % - nested quantifiers: the usage of facts for singleton_set is error prone, and cannot deal with | |
47 | % nested quantifiers with variable clashes, in particular when in the inner quantifier the | |
48 | % identifier is not a singleton set | |
49 | % - multiplicity annotations in signatures and nested multiplicity annotations for non-binary relations | |
50 | % - variable capture due to use of DEFINITIONS | |
51 | % - ProB does not allow arithmetic operators on non-singleton sets; | |
52 | % this is a design decision to detect most probably unintended uses of arithmetic | |
53 | % - ProB does use mathematical integers, bit-width is used for MAXINT and MININT, but only influences | |
54 | % enumeration scopes | |
55 | ||
56 | load_alloy_ast_prolog_file(File) :- | |
57 | \+ file_exists(File,read) , ! , | |
58 | add_error(load_alloy_ast_prolog_file,'Alloy AST file has not been created:',[File]) , fail. | |
59 | load_alloy_ast_prolog_file(File) :- | |
60 | format('Opening Alloy AST file: ~w~n',[File]), | |
61 | open(File,read,Stream), | |
62 | safe_read_term(Stream,AlloyTerm), | |
63 | close(Stream), | |
64 | load_alloy_model(AlloyTerm,'alloytranslation'). | |
65 | ||
66 | safe_read_term(Stream,Term) :- | |
67 | on_exception(error(E,_), read(Stream,Term), | |
68 | (add_internal_error('Exception while reading Prolog term from stream:',E), | |
69 | fail)). | |
70 | ||
71 | load_alloy_model(AlloyTerm,AlloyFile) :- | |
72 | % use the first run or check command by default for models that use sequences, otherwise all commands are translated | |
73 | load_alloy_model(0,AlloyTerm,AlloyFile). | |
74 | ||
75 | load_alloy_model(CurrentCommand,AlloyTerm,AlloyFile) :- | |
76 | integer(CurrentCommand) , | |
77 | reset_errors , | |
78 | format('Translating AST to B.~n',[]) , | |
79 | retract_state, % in case things not properly reseted or initialised | |
80 | assert(current_command(CurrentCommand)) , | |
81 | %tools_printing:nested_print_term(AlloyTerm,10), | |
82 | translate_alloy_model(AlloyTerm,UntypedBAst) , ! , | |
83 | UntypedBAst = machine(generated(none,AbstractMachine)) , | |
84 | b_load_machine_from_term(AlloyFile,complete_machine('alloytranslation',[AbstractMachine],[AlloyFile])), | |
85 | set_animation_minor_mode(alloy). | |
86 | load_alloy_model(CurrentCommand,_,_) :- | |
87 | \+ integer(CurrentCommand) , | |
88 | add_error(load_alloy_model,'Current command has to be an integer:',CurrentCommand) , fail. | |
89 | load_alloy_model(_,AlloyTerm,_) :- | |
90 | add_error(load_alloy_model,'Translating Alloy AST failed:',AlloyTerm) , fail. | |
91 | ||
92 | process_options(Options) :- | |
93 | member(sequences:B,Options) , | |
94 | B == true , ! , | |
95 | asserta(uses_seqs). | |
96 | process_options(_). | |
97 | ||
98 | % TODO: handle all modules in the model but exclude integer, relation, ordering and sequences | |
99 | % Currently we only extract and translate the main module | |
100 | translate_alloy_model(alloy(RootModule, Models), UntypedBAst) :- | |
101 | member(alloy_model(RootModule,Facts,Assertions,Commands,Functions,Signatures,OSigNames,Options),Models),!, | |
102 | translate_alloy_model(alloy_model(RootModule,Facts,Assertions,Commands,Functions,Signatures,OSigNames,Options), UntypedBAst). | |
103 | ||
104 | % TODO: use atelierb_pp_mode (e.g. we use let expressions which are not supported by native B) | |
105 | translate_alloy_model(alloy_model(_ModuleName, facts(Facts),assertions(Assertions),commands(Commands),functions(Functions), | |
106 | signatures(Signatures),ordered_signatures(OSigNames),Options),UntypedBAst) :- | |
107 | % singleton sets are asserted at runtime using singleton_set/1 | |
108 | % accumulate all translations, afterwards we build the untyped machine ast | |
109 | process_options(Options) , | |
110 | maplist(assert_ordered_sig_name,OSigNames) , | |
111 | empty_machine_acc(MAcc), | |
112 | debug_println(19,translating_signatures), | |
113 | maplist(preprocess_signature,Signatures), % assert some signature names as singleton | |
114 | map_translate(translate_signature,MAcc,Signatures,MAcc0), | |
115 | debug_println(19,translating_assertions), | |
116 | map_translate(translate_assertion,MAcc0,Assertions,MAcc1), | |
117 | debug_println(19,translating_commands), | |
118 | % TO DO: extract common scopes for all commands, to set deferred set sizes: | |
119 | % NOTE: extract_common_scopes can be removed in case we stick to translating a single command at a time | |
120 | extract_common_scopes(Commands,GS,ExactScopes,UpBoundScopes,BitWidth,TMaxSeq,Con), | |
121 | (TMaxSeq = maxSeq(MaxSeq) ; MaxSeq = -1) , | |
122 | format('Common scopes to all commands : global=~w, exact=~w, bw=~w, ms=~w, conflicts=~w~n',[GS,ExactScopes,BitWidth,MaxSeq,Con]), | |
123 | (number(GS),GS>0 -> preferences:temporary_set_preference(globalsets_fdrange,GS) % TO DO: improve | |
124 | ; true), | |
125 | maplist(generate_exact_scope_predicate,ExactScopes,ScopePreds1), | |
126 | maplist(generate_leq_scope_predicate,UpBoundScopes,ScopePreds2), | |
127 | append(ScopePreds1,ScopePreds2,ScopePreds), | |
128 | extend_machine_with_conjuncts(properties,ScopePreds,MAcc1,MAcc2), | |
129 | (BitWidth=bitwidth(BW), number(BW), BW>0, | |
130 | MaxInt is integer(2**(BW-1)) -1, MinInt is integer(-(2**(BW-1))), | |
131 | preferences:temporary_set_preference(maxint,MaxInt), | |
132 | preferences:temporary_set_preference(minint,MinInt) | |
133 | -> true ; true), | |
134 | (MaxSeq \= -1 | |
135 | -> translate_seq_scopes(MaxSeq,SeqScopesPred) , extend_machine_acc(properties,MAcc2,SeqScopesPred,MAcc3) | |
136 | ; MAcc3 = MAcc2) , | |
137 | map_translate(translate_command,MAcc3,Commands,MAcc4) , | |
138 | debug_println(19,translating_functions), | |
139 | map_translate(translate_function,MAcc4,Functions,MAcc5) , | |
140 | debug_println(19,translating_facts), | |
141 | map_translate(translate_fact,MAcc5,Facts,MAcc6) , ! , | |
142 | finalize_extending_signatures(MAcc6,MAcc7) , | |
143 | debug_println(19,build_machine_ast), | |
144 | build_machine_ast(MAcc7,UntypedBAst), | |
145 | %print(UntypedBAst),nl,nl, | |
146 | %tools_printing:nested_print_term(UntypedBAst,20), | |
147 | (debug_mode(off) -> true ; nl,translate:print_raw_machine_terms(UntypedBAst),nl), | |
148 | retract_state. | |
149 | ||
150 | map_translate(_,MAcc,[],MAcc). | |
151 | map_translate(TypePred,MAcc,[Part|T],Res) :- | |
152 | call(TypePred,MAcc,Part,NewMAcc) , | |
153 | map_translate(TypePred,NewMAcc,T,Res). | |
154 | ||
155 | % things that need to be done before translating the signatures, e.g., assert singleton set info | |
156 | preprocess_signature(signature(Name,_Fields,_Facts,Options,_)) :- | |
157 | % assert signatures for singleton checks | |
158 | assert_singleton_set(Options,Name) , | |
159 | assert_enumerated_set(Options,Name). | |
160 | ||
161 | % translate signature declaration sig Name {Fields} | |
162 | translate_signature(MAcc,signature(Name,Fields,Facts,Options,pos(Col,Row)),NewMAcc) :- | |
163 | extend_machine_acc(signatures,MAcc,[Name],MAcc1), | |
164 | translate_signature_aux(Name,Options,pos(Col,Row),MAcc1,MAcc2), | |
165 | translate_signature_fields(Fields,Name,MAcc2,MAcc3), | |
166 | translate_e_p(Name,TName) , | |
167 | map_translate(translate_signature_fact(TName),MAcc3,Facts,NewMAcc). | |
168 | ||
169 | translate_signature_aux(Name,Options,Pos,MAcc,NewMAcc) :- | |
170 | % ordered signatures are defined as distinct sets of integer when translating a command | |
171 | member(ordered,Options) , ! , | |
172 | define_ordered_signature_functions(Pos,MAcc,Name,MAcc1) , | |
173 | extend_machine_acc(signatures,MAcc1,[Name],MAcc2) , | |
174 | translate_e_p(Name,TID) , | |
175 | extend_machine_acc(properties,MAcc2, | |
176 | member(none,TID,pow_subset(none,integer_set(none,'INTEGER'))),MAcc3) , | |
177 | define_sig_as_set_or_constant_aux(constants,MAcc3,Name,Options,Pos,NewMAcc). | |
178 | translate_signature_aux(Name,Options,Pos,MAcc,NewMAcc) :- | |
179 | define_sig_as_set_or_constant(MAcc,Name,Options,Pos,NewMAcc). | |
180 | ||
181 | define_ordered_signature_functions(POS,MAcc,Sig,NewMAcc) :- | |
182 | translate_pos(POS,BPOS), | |
183 | gen_identifier(0,"_c_",TIDX), | |
184 | TIDS = identifier(BPOS,s) , | |
185 | translate_e_p(Sig,TSig) , MemberX = member(BPOS,TIDX,TSig) , | |
186 | % next_Sig(s) == IF succ[s] <: Sig THEN succ[s] ELSE {} END | |
187 | atom_concat(next_,Sig,NextName) , | |
188 | SuccessorImg = image(BPOS,successor(BPOS),TIDS) , | |
189 | PredecessorImg = image(BPOS,predecessor(BPOS),TIDS) , | |
190 | extend_machine_acc(definitions,MAcc, | |
191 | expression_definition(BPOS,NextName,[TIDS],if_then_else(BPOS,subset(BPOS,SuccessorImg,TSig),SuccessorImg,empty_set(BPOS))),MAcc1) , | |
192 | % nexts_Sig(s) == {x|x:Sig & min({x} \/ s) /: {x}} | |
193 | atom_concat(nexts_,Sig,NextsName) , | |
194 | NextsBody = conjunct(BPOS,MemberX,not_member(BPOS,min(BPOS,union(BPOS,set_extension(BPOS,[TIDX]),TIDS)),set_extension(BPOS,[TIDX]))) , | |
195 | extend_machine_acc(definitions,MAcc1, | |
196 | expression_definition(BPOS,NextsName,[TIDS],comprehension_set(BPOS,[TIDX],NextsBody)),MAcc2) , | |
197 | atom_concat(prev_,Sig,PrevName) , | |
198 | % prev_Sig(s) == IF pred[s] <: Sig THEN pred[s] ELSE {} END | |
199 | extend_machine_acc(definitions,MAcc2, | |
200 | expression_definition(BPOS,PrevName,[TIDS],if_then_else(BPOS,subset(BPOS,PredecessorImg,TSig),PredecessorImg,empty_set(BPOS))),MAcc3) , | |
201 | % prevs_Sig(s) == {x|x:Sig & max({x} \/ s) /: {x}} | |
202 | atom_concat(prevs_,Sig,PrevsName) , | |
203 | PrevsBody = conjunct(BPOS,MemberX,not_member(BPOS,max(BPOS,union(BPOS,set_extension(BPOS,[TIDX]),TIDS)),set_extension(BPOS,[TIDX]))) , | |
204 | extend_machine_acc(definitions,MAcc3, | |
205 | expression_definition(BPOS,PrevsName,[TIDS],comprehension_set(BPOS,[TIDX],PrevsBody)),NewMAcc). | |
206 | ||
207 | translate_signature_fields(Fields,SignatureName) --> | |
208 | {translate_e_p(SignatureName,TSignatureName)}, | |
209 | translate_signature_fields_aux(Fields,SignatureName,TSignatureName). | |
210 | ||
211 | translate_signature_fields_aux([],_,_) --> []. | |
212 | translate_signature_fields_aux([Field|T],SignatureName,TSignatureName) --> | |
213 | translate_signature_field(SignatureName,TSignatureName,Field), | |
214 | translate_signature_fields_aux(T,SignatureName,TSignatureName). | |
215 | ||
216 | translate_signature_field(SignatureName,TSignatureName,Field,MAcc,NewMAcc) :- | |
217 | translate_signature_field_aux(SignatureName,TSignatureName,Field,TField,MAcc,MAcc1), | |
218 | extend_machine_acc(properties,MAcc1,TField,NewMAcc). | |
219 | ||
220 | translate_signature_field_aux(SignatureName,TSignatureName, | |
221 | field(FieldName,Expr,FieldType,Options,POS),TFieldPred,MAcc,NewMAcc) :- | |
222 | FieldType = type(TypeList,Arity), A1 is Arity+1, % add SignatureName to type: | |
223 | FieldID = identifier(FieldName,type([SignatureName|TypeList],A1),POS), | |
224 | translate_e_p(FieldName,TFieldName), | |
225 | extend_machine_acc(constants,MAcc,TFieldName,MAcc1) , | |
226 | translate_pos(POS,BPOS), | |
227 | disjoint_field_declaration(TSignatureName,BPOS,Options,MAcc1,TFieldName,NewMAcc) , | |
228 | translate_field_decl(BPOS,SignatureName,TSignatureName,Expr,FieldID,TFieldName,TFieldPred) , !. | |
229 | ||
230 | translate_function_field(field(FieldName,Expr,type(_Type,_Arity),_Options,POS),TField) :- | |
231 | %(Functor = function -> assert_singleton_set(FieldName) ; true) , % NO LONGER NEEDED | |
232 | translate_e_p(FieldName,TTFieldName), | |
233 | strip_singleton_set_from_this(TTFieldName,TFieldName) , % necessary for nested definition calls with 'this' | |
234 | translate_pos(POS,BPOS), | |
235 | fun_or_pred_decl_special_cases(Expr,TFieldName,BPOS,TField,_IsSingleton) , !. | |
236 | % TO DO: !! what if IsSingleton is set !! | |
237 | ||
238 | disjoint_field_declaration(TSignatureName,TPos,Options,MAcc,TFieldName,NewMAcc) :- | |
239 | member(disj,Options) , ! , | |
240 | % all a, b: S | a != b implies no a.f & b.f | |
241 | IdA = identifier(TPos,a) , IdB = identifier(TPos,b) , | |
242 | ImplLhs = conjunct(TPos,conjunct(TPos,member(TPos,IdA,TSignatureName),member(TPos,IdB,TSignatureName)), | |
243 | not_equal(TPos,IdA,IdB)) , | |
244 | ImplRhs = equal(TPos,intersection(TPos,image(TPos,TFieldName,set_extension(none,[IdA])), | |
245 | image(TPos,TFieldName,set_extension(none,[IdB]))),empty_set(TPos)) , | |
246 | Disjoint = forall(TPos,[IdA,IdB],implication(TPos,ImplLhs,ImplRhs)) , | |
247 | extend_machine_acc(properties,MAcc,Disjoint,NewMAcc). | |
248 | disjoint_field_declaration(_,_,_,MAcc,_,MAcc). | |
249 | ||
250 | ||
251 | ||
252 | is_disjoint_quantifier(Fields) :- Fields=[F|_], is_disjoint_quantifier_field(F). % assumption: all or no field is disjoint | |
253 | is_disjoint_quantifier_field(field(_FieldName,_Expr,type(_Type,_Arity),Options,_POS)) :- member(disj,Options). | |
254 | ||
255 | translate_quantifier_field(field(FieldName,Expr,type(_Type,_Arity),_Options,POS),TField,FieldName) :- | |
256 | translate_pos(POS,BPOS), | |
257 | fun_or_pred_decl_special_cases(Expr,TFieldName,BPOS,TField,IsSingleton), | |
258 | !, | |
259 | (IsSingleton=singleton -> | |
260 | assert_singleton_set(FieldName) ; true), | |
261 | translate_e_p(FieldName,TFieldName). | |
262 | ||
263 | ||
264 | translate_fact(MAcc,fact(Expr,_Pos),NewMAcc) :- | |
265 | translate_e_p(Expr,TExpr) , | |
266 | extend_machine_acc(properties,MAcc,TExpr,NewMAcc). | |
267 | translate_assertion(MAcc,fact(Expr,_Pos),NewMAcc) :- | |
268 | translate_e_p(Expr,TExpr) , | |
269 | extend_machine_acc(assertions,MAcc,TExpr,NewMAcc). | |
270 | ||
271 | % Signature facts: Identifiers may refer to the signature and are joined with 'this'. | |
272 | % We then need a universal quantification using 'this'. | |
273 | translate_signature_fact(TSignatureName,MAcc,Expr,NewMAcc) :- | |
274 | alloy_expr_contains_join(Expr), | |
275 | translate_e_p(Expr,TExpr), % we quantify in such a way that this is a singleton_set_id; this is always considered a singleton set id | |
276 | ThisID = identifier(none,'this'), | |
277 | TImplication = implication(none,subset(none,set_extension(none,[ThisID]),TSignatureName),TExpr), | |
278 | FORALL = forall(none,[ThisID],TImplication), | |
279 | extend_machine_acc(properties,MAcc,FORALL,NewMAcc). | |
280 | translate_signature_fact(_TSignatureName,MAcc,Expr,NewMAcc) :- | |
281 | translate_e_p(Expr,TExpr) , | |
282 | extend_machine_acc(properties,MAcc,TExpr,NewMAcc). | |
283 | ||
284 | % TO DO: write generic AST traversal predicate | |
285 | alloy_expr_contains_join(AndOr) :- | |
286 | AndOr =.. [Functor,ListOfAsts,_Pos], !, | |
287 | member(Functor,[and,or]), | |
288 | member(Ast,ListOfAsts), | |
289 | alloy_expr_contains_join(Ast),!. | |
290 | alloy_expr_contains_join(identifier('this',_,_)). | |
291 | %alloy_expr_contains_join_with_this(join(Arg1,Arg2,_Type,_Pos)) :- | |
292 | % Arg1 = identifier('this',_,_) ; Arg2 = identifier('this',_,_). | |
293 | alloy_expr_contains_join(Expr) :- | |
294 | Expr =.. [_Functor,Arg1,Arg2,_Type,_Pos], !, | |
295 | (alloy_expr_contains_join(Arg1) -> true | |
296 | ; alloy_expr_contains_join(Arg2)). | |
297 | alloy_expr_contains_join(Expr) :- | |
298 | Expr =.. [_Functor,Arg,_Type,_Pos] , | |
299 | alloy_expr_contains_join(Arg). | |
300 | alloy_expr_contains_join(Expr) :- | |
301 | Expr =.. [Functor,_Params,Fields,Body,_Type,_POS], | |
302 | member(Functor,[all,no,some,one,lone,comprehension]), | |
303 | (alloy_expr_contains_join(Body) -> true | |
304 | ; member(F,Fields), alloy_expr_contains_join(F) -> true). | |
305 | ||
306 | % translate fun NAME Decls { Body } or pred Name Decls { Body } | |
307 | translate_function(MAcc,FunctionOrPredicate,NewMAcc) :- | |
308 | FunctionOrPredicate =.. [Functor,Name,Params,Decls,Body,POS] , | |
309 | alloy_to_b_operator(Functor,BFunctor), | |
310 | maplist(translate_e_p,Params,TParams), | |
311 | % identifier like 'this' are singleton sets, parameters have to be identifiers | |
312 | maplist(strip_singleton_set,TParams,TTParams) , | |
313 | maplist(translate_function_field,Decls,TDecls), | |
314 | translate_e_p(Body,TBody), | |
315 | translate_pos(POS,BPOS), | |
316 | (Functor == function | |
317 | -> (TDecls == [] | |
318 | -> TResult = TBody % no need to create set comprehension | |
319 | ; % create {temp | TDecls & temp : TBody } | |
320 | append(TDecls,[member(none,identifier(none,'_fun_res_'),TBody)],BehaviorList) , | |
321 | join_untyped_ast_nodes(conjunct,BehaviorList,Behavior) , | |
322 | TResult = comprehension_set(BPOS,[identifier(none,'_fun_res_')],Behavior) | |
323 | ), | |
324 | UAst =.. [BFunctor,BPOS,Name,TTParams,TResult] | |
325 | ; append(TDecls,[TBody],BehaviorList) , | |
326 | join_untyped_ast_nodes(conjunct,BehaviorList,Behavior) , | |
327 | UAst =.. [BFunctor,BPOS,Name,TTParams,Behavior]) , | |
328 | extend_machine_acc(definitions,MAcc,UAst,NewMAcc). | |
329 | ||
330 | % extract scopes common to all commands | |
331 | extract_common_scopes([Cmd|T],GlobalScopes,ExactScopes,UpBoundScopes,BitWidth,MaxSeq,Conflicts) :- | |
332 | get_scopes(Cmd,GlobalScopes1,ExactScopes1,UpBound1,BitWidth1,MaxSeq1),!, | |
333 | extract_common_aux(T,GlobalScopes1,ExactScopes1,UpBound1,BitWidth1,MaxSeq1,[], | |
334 | GlobalScopes,ExactScopes,UpBoundScopes,BitWidth,MaxSeq,Conflicts). | |
335 | extract_common_scopes(_,-1,[],[],none,none,[]). | |
336 | extract_common_aux([],GS,ES,UpS,BW,MS,C,GS,ES,UpS,BW,MS,C). | |
337 | extract_common_aux([Cmd|T],GlobalScope0,ExactScopes0,UpBoundScopes0,BitWidth0,MaxSeq0,Conflicts0, | |
338 | GlobalScopes,ExactScopes,UpBoundScopes,BitWidth,MaxSeq,Conflicts) :- | |
339 | get_scopes(Cmd,GlobalScope1,ExactScopes1,UpBoundScopes1,BitWidth1,MaxSeq1), | |
340 | (GlobalScope0 = GlobalScope1 -> GlobalScope2 = GlobalScope0 ; GlobalScope2=none), | |
341 | (BitWidth0 = BitWidth1 -> BitWidth2 = BitWidth1 ; BitWidth2=none), | |
342 | (MaxSeq0 = MaxSeq1 -> MaxSeq2 = MaxSeq1 ; MaxSeq2=none), | |
343 | join_scopes(ExactScopes0,ExactScopes1,ExactScopes2,Conflicts1), | |
344 | ord_union(Conflicts0,Conflicts1,Conflicts2), | |
345 | join_scopes(UpBoundScopes0,UpBoundScopes1,UpBoundScopes2,Conflicts3), | |
346 | ord_union(Conflicts2,Conflicts3,Conflicts4), | |
347 | !, | |
348 | extract_common_aux(T,GlobalScope2,ExactScopes2,UpBoundScopes2,BitWidth2,MaxSeq2,Conflicts4, | |
349 | GlobalScopes,ExactScopes,UpBoundScopes,BitWidth,MaxSeq,Conflicts). | |
350 | ||
351 | join_scopes(S1,S2,Inter,Conflicts) :- | |
352 | sort(S1,SS1), sort(S2,SS2), ord_intersection(SS1,SS2,Inter), | |
353 | ord_union(SS1,SS2,Union), | |
354 | ord_subtract(Union,Inter,Conflicts). | |
355 | ||
356 | get_scopes(Command,GlobalScope,ExactScopes,UpBoundScopes,BitWidth,MaxSeq) :- | |
357 | Command =.. [_Functor,_Body,global_scope(GlobalScope), | |
358 | exact_scopes(ExactScopes),upper_bound_scopes(UpBoundScopes),BitWidth,MaxSeq|_] , | |
359 | !, format('Command scopes: global=~w, exact=~w, upbound=~w,bitwidth=~w~n,maxseq=~w~n', | |
360 | [GlobalScope,ExactScopes,UpBoundScopes,BitWidth,MaxSeq]). | |
361 | get_scopes(Command,-1,[],[],none,none) :- | |
362 | add_error(alloy2b,'Cannot process Alloy Command:',Command). | |
363 | ||
364 | translate_command(MAcc,Command,NewMAcc) :- | |
365 | Command =.. [Functor,Body,GlobalScope,ExactScopes,UpBoundScopes,BitWidth,MaxSeq,index(CommandIndex),POS] , | |
366 | % either a model uses no sequences and we translate all commands or only the chosen one | |
367 | (\+ uses_seqs ; (current_command(CurrentIndex) , CurrentIndex == CommandIndex)) , ! , | |
368 | translate_command_aux(MAcc,Functor,Body,GlobalScope,ExactScopes,UpBoundScopes,BitWidth,MaxSeq,POS,NewMAcc). | |
369 | translate_command(MAcc,Command,MAcc) :- | |
370 | % only translate the current command if using sequences (either selected by the user or the first one by default) | |
371 | Command =.. [_,_,_,_,_,_,_,index(CommandIndex),_] , | |
372 | current_command(CurrentIndex) , | |
373 | CurrentIndex =\= CommandIndex , !. | |
374 | translate_command(MAcc,Command,MAcc) :- | |
375 | add_error('Unknown Alloy command (be sure Alloy2B library is up-to-date):',Command). | |
376 | ||
377 | translate_command_aux(MAcc,Functor,Body,GlobalScope,ExactScopes,UpBoundScopes,BitWidth,MaxSeq,POS,NewMAcc) :- | |
378 | debug_println(19,translating_command(Functor,GlobalScope,ExactScopes)), | |
379 | (Functor = check ; Functor = run) , | |
380 | translate_e_p(Body,TBody) , | |
381 | % we need all signature names to define the global scope | |
382 | get_signature_names_from_machine_acc(MAcc,SignatureNames) , | |
383 | debug_println(19,translate_scopes(SignatureNames)), | |
384 | translate_scopes(SignatureNames,GlobalScope,ExactScopes,UpBoundScopes,BitWidth,MaxSeq,TScopesPred) , | |
385 | translate_pos(POS,BPOS), | |
386 | Precondition = conjunct(BPOS,TScopesPred,TBody) , | |
387 | get_command_counter_atom(CommandCounter) , | |
388 | atom_concat(Functor,CommandCounter,OperationName) , | |
389 | Operation = operation(BPOS,identifier(BPOS,OperationName),[],[],precondition(BPOS,Precondition,skip(none))) , | |
390 | extend_machine_acc(operations,MAcc,Operation,NewMAcc) , | |
391 | MaxSeq = maxseq(MaxSeqSize) , | |
392 | assert(maxseq(MaxSeqSize)). | |
393 | ||
394 | % global scope, exact scopes and bitwidth | |
395 | % We do not need to set the bitwidth since we have real integers in B. | |
396 | % Note: If only one command is defined in the Alloy model we could set min and max int of ProB in the definitions. | |
397 | translate_scopes(SignatureNames,global_scope(GlobalScope),exact_scopes(ExactScopes),upper_bound_scopes(UpBoundScopes),_BitWidth,maxseq(MaxSeq), | |
398 | conjunct(none,SeqScopePred,conjunct(none,TScopes,TGlobalScopes))) :- | |
399 | % translate exact and upper bound scopes first | |
400 | translate_exact_and_upper_bound_scopes(0,ExactScopes,UpBoundScopes,EUSignatureNames,TScopes,OrdSigCounter1) , | |
401 | % if present, define the global scope for the remaining signatures | |
402 | translate_global_scope(OrdSigCounter1,GlobalScope,SignatureNames,EUSignatureNames,TGlobalScopes,_) , | |
403 | translate_seq_scopes(MaxSeq,SeqScopePred). | |
404 | ||
405 | translate_seq_scopes(MaxSeq,ScopePred) :- | |
406 | findall((Seq,MaxSeq),is_seq(Seq),Seqs) , | |
407 | maplist(generate_leq_scope_predicate,Seqs,ScopePreds) , | |
408 | join_predicates(conjunct,ScopePreds,ScopePred). | |
409 | ||
410 | % no exact scopes defined | |
411 | translate_exact_and_upper_bound_scopes(OrdSigCounter,[],[],ExactSignatureNames,truth(none),OrdSigCounter) :- !, | |
412 | ExactSignatureNames=[]. | |
413 | translate_exact_and_upper_bound_scopes(OrdSigCounter,ExactScopes,UpBoundScopes,SignatureNames,TScopes,NewOrdSigCounter) :- | |
414 | translate_exact_and_upper_bound_scopes_aux(OrdSigCounter,UpBoundScopes,[], | |
415 | UpperBoundSignatureNames,[],TempTUpScopes,OrdSigCounter1) , | |
416 | translate_exact_and_upper_bound_scopes_aux(OrdSigCounter1,ExactScopes,[], | |
417 | ExactSignatureNames,[],TempTExactScopes,NewOrdSigCounter) , | |
418 | append(TempTUpScopes,TempTExactScopes,TempTScopes) , | |
419 | append(ExactSignatureNames,UpperBoundSignatureNames,SignatureNames) , | |
420 | join_predicates(conjunct,TempTScopes,TScopes). | |
421 | ||
422 | translate_exact_and_upper_bound_scopes_aux(OrdSigCounter,[],NamesAcc,NamesAcc,TScopeAcc,TScopeAcc,OrdSigCounter). | |
423 | translate_exact_and_upper_bound_scopes_aux(OrdSigCounter,[(SignatureName,Scope)|T], | |
424 | NameAcc,ExactSignatureNames,TScopeAcc,TempTExactScopes,NewOrdSigCounter) :- | |
425 | is_ordered_signature(SignatureName) , ! , | |
426 | define_ordered_signature_as_integer_set(OrdSigCounter,SignatureName,Scope, | |
427 | TScope,TNewOrdSigCounter) , | |
428 | translate_exact_and_upper_bound_scopes_aux(TNewOrdSigCounter,T,[SignatureName|NameAcc], | |
429 | ExactSignatureNames,[TScope|TScopeAcc],TempTExactScopes,NewOrdSigCounter). | |
430 | translate_exact_and_upper_bound_scopes_aux(OrdSigCounter,[(SignatureName,Scope)|T], | |
431 | NameAcc,ExactSignatureNames,TScopeAcc,TempTExactScopes,NewOrdSigCounter) :- | |
432 | generate_exact_scope_predicate((SignatureName,Scope),TScope), | |
433 | translate_exact_and_upper_bound_scopes_aux(OrdSigCounter,T,[SignatureName|NameAcc], | |
434 | ExactSignatureNames,[TScope|TScopeAcc],TempTExactScopes,NewOrdSigCounter). | |
435 | ||
436 | generate_exact_scope_predicate((SignatureName,Scope),TScopePred) :- | |
437 | translate_e_p(SignatureName,TSignatureName), | |
438 | %format('Exact scope for SignatureName=~w with scope ~w~n',[SignatureName,Scope]), | |
439 | TScopePred = equal(none,card(none,TSignatureName),integer(none,Scope)). | |
440 | generate_leq_scope_predicate((SignatureName,Scope),TScopePred) :- | |
441 | translate_e_p(SignatureName,TSignatureName) , | |
442 | TScopePred = less_equal(none,card(none,TSignatureName),integer(none,Scope)). | |
443 | ||
444 | define_ordered_signatures_as_integer_set(OrdSigCounter,[],_,[],OrdSigCounter). | |
445 | define_ordered_signatures_as_integer_set(OrdSigCounter,[TSignatureName|T],Scope,[TScope|TScopes],NewOrdSigCounter) :- | |
446 | define_ordered_signature_as_integer_set(OrdSigCounter,TSignatureName,Scope,TScope,TNewOrdSigCounter) , | |
447 | define_ordered_signatures_as_integer_set(TNewOrdSigCounter,T,Scope,TScopes,NewOrdSigCounter). | |
448 | ||
449 | define_ordered_signature_as_integer_set(OrdSigCounter,TSignatureName,Scope,TScope,NewOrdSigCounter) :- | |
450 | NewOrdSigCounter is OrdSigCounter + Scope , | |
451 | NewOrdSigCounter1 is NewOrdSigCounter - 1 , | |
452 | TScope = equal(none,identifier(none,TSignatureName),interval(none,integer(none,OrdSigCounter),integer(none,NewOrdSigCounter1))). | |
453 | ||
454 | translate_global_scope(OrdSigCounter,-1,_,_,truth(none),OrdSigCounter) :- !. % no global scope defined | |
455 | translate_global_scope(OrdSigCounter,GlobalScope,SignatureNames,ExactSignatureNames,TGlobalScopes,NewOrdSigCounter) :- | |
456 | split_ordered_unordered_signatures(SignatureNames,ExactSignatureNames,OrderedSignatureNames,RestSignatureNames) , | |
457 | translate_global_scope_aux(RestSignatureNames,GlobalScope,[],TempTGlobalScopes) , | |
458 | join_predicates(conjunct,TempTGlobalScopes,TTGlobalScopes) , | |
459 | define_ordered_signatures_as_integer_set(OrdSigCounter,OrderedSignatureNames,GlobalScope,TOrderedScopes,NewOrdSigCounter) , | |
460 | join_predicates(conjunct,[TTGlobalScopes|TOrderedScopes],TGlobalScopes). | |
461 | ||
462 | translate_global_scope_aux([],_,Acc,Acc). | |
463 | translate_global_scope_aux([SignatureName|T],GlobalScope,Acc,TGlobalScopes) :- | |
464 | translate_e_p(SignatureName,TSignatureName) , | |
465 | TScope = less_equal(none,card(none,TSignatureName),integer(none,GlobalScope)) , | |
466 | translate_global_scope_aux(T,GlobalScope,[TScope|Acc],TGlobalScopes). | |
467 | translate_global_scope_aux([_|T],GlobalScope,Acc,TGlobalScopes) :- | |
468 | translate_global_scope_aux(T,GlobalScope,Acc,TGlobalScopes). | |
469 | ||
470 | split_ordered_unordered_signatures(SNames,ExactSNames,OSNames,Rest) :- | |
471 | split_ordered_unordered_signatures(SNames,[],[],TOSNames,TRest) , | |
472 | % remove exact signatures which are defined separately | |
473 | subtract(TOSNames,ExactSNames,OSNames) , | |
474 | subtract(TRest,ExactSNames,Rest). | |
475 | ||
476 | split_ordered_unordered_signatures([],OAcc,RAcc,OAcc,RAcc). | |
477 | split_ordered_unordered_signatures([SName|T],OAcc,RAcc,OSNames,Rest) :- | |
478 | is_ordered_signature(SName) , | |
479 | \+ member(SName,OAcc) , ! , | |
480 | split_ordered_unordered_signatures(T,[SName|OAcc],RAcc,OSNames,Rest). | |
481 | split_ordered_unordered_signatures([SName|T],OAcc,RAcc,OSNames,Rest) :- | |
482 | \+ is_ordered_signature(SName) , | |
483 | \+ member(SName,RAcc) , ! , | |
484 | split_ordered_unordered_signatures(T,OAcc,[SName|RAcc],OSNames,Rest). | |
485 | split_ordered_unordered_signatures([_|T],OAcc,RAcc,OSNames,Rest) :- | |
486 | split_ordered_unordered_signatures(T,OAcc,RAcc,OSNames,Rest). | |
487 | ||
488 | % signature in (subset) | |
489 | define_sig_as_set_or_constant(MAcc,Name,Options,POS,NewMAcc) :- | |
490 | memberchk(subset(Parents),Options) , ! , | |
491 | % maplist(assert_extending_signature(Name),Parents) , % subset signatures do not need to be distinct | |
492 | translate_pos(POS,BPOS), | |
493 | define_sig_as_set_or_constant_aux(constants,MAcc,Name,Options,BPOS,MAcc1) , | |
494 | % TODO: consider several parents -> we need the universe type | |
495 | Parents = [Parent|_], | |
496 | translate_e_p(Name,TName), | |
497 | translate_e_p(Parent,TParent), | |
498 | TNode = subset(BPOS,TName,TParent) , | |
499 | extend_machine_acc(properties,MAcc1,TNode,NewMAcc). | |
500 | % signature extends | |
501 | define_sig_as_set_or_constant(MAcc,Name,Options,POS,NewMAcc) :- | |
502 | member(subsig(Parent),Options), | |
503 | !, | |
504 | (member(one,Options) -> One=one ; One=set), | |
505 | assert_extending_signature(Name,Parent,One), | |
506 | translate_pos(POS,BPOS), | |
507 | define_sig_as_set_or_constant_aux(constants,MAcc,Name,Options,BPOS,MAcc1), | |
508 | translate_e_p(Name,TName), | |
509 | translate_e_p(Parent,TParent), | |
510 | TNode = subset(BPOS,TName,TParent), | |
511 | extend_machine_acc(properties,MAcc1,TNode,NewMAcc). | |
512 | % default signature | |
513 | define_sig_as_set_or_constant(MAcc,Name,Options,POS,NewMAcc) :- | |
514 | translate_pos(POS,BPOS), | |
515 | define_sig_as_set_or_constant_aux(sets,MAcc,Name,Options,BPOS,NewMAcc). | |
516 | ||
517 | define_sig_as_set_or_constant_aux(sets,MAcc,Name,Options,BPOS,NewMAcc) :- | |
518 | member(one,Options) , ! , | |
519 | atom_concat('_',Name,EnumElement) , | |
520 | % TODO: couldn't figure out untyped ast of enumerated set, define enumerated set S = {_S} instead of constant etc. | |
521 | extend_machine_acc(sets,MAcc,deferred_set(BPOS,Name),MAcc1) , | |
522 | extend_machine_acc(constants,MAcc1,identifier(BPOS,EnumElement),MAcc2) , | |
523 | extend_machine_acc(properties,MAcc2,equal(BPOS,identifier(BPOS,Name),set_extension(BPOS,[identifier(BPOS,EnumElement)])),NewMAcc). | |
524 | define_sig_as_set_or_constant_aux(sets,MAcc,Name,Options,BPOS,NewMAcc) :- | |
525 | member(some,Options) , ! , | |
526 | extend_machine_acc(sets,MAcc,deferred_set(BPOS,Name),MAcc1) , | |
527 | extend_machine_acc(properties,MAcc1,greater_equal(BPOS,card(BPOS,identifier(BPOS,Name)),integer(BPOS,1)),NewMAcc). | |
528 | define_sig_as_set_or_constant_aux(sets,MAcc,Name,Options,BPOS,NewMAcc) :- | |
529 | member(lone,Options) , ! , | |
530 | extend_machine_acc(sets,MAcc,deferred_set(BPOS,Name),MAcc1) , | |
531 | extend_machine_acc(properties,MAcc1,less_equal(BPOS,card(BPOS,identifier(BPOS,Name)),integer(BPOS,1)),NewMAcc). | |
532 | define_sig_as_set_or_constant_aux(sets,MAcc,Name,_Options,BPOS,NewMAcc) :- | |
533 | extend_machine_acc(sets,MAcc,deferred_set(BPOS,Name),NewMAcc). | |
534 | define_sig_as_set_or_constant_aux(constants,MAcc,Name,_Options,BPOS,NewMAcc) :- | |
535 | extend_machine_acc(constants,MAcc,identifier(BPOS,Name),NewMAcc). | |
536 | ||
537 | % -------- | |
538 | % Semantic translation rules: translate expression or predicate | |
539 | % -------- | |
540 | ||
541 | translate_e_p(A,TA) :- %% functor(A,F,N),format('~n TRANSLATE: ~w/~w : ~w ~n',[F,N,A]), | |
542 | translate_quantifier_e(A,TA) , !. | |
543 | translate_e_p(A,TA) :- | |
544 | translate_cst_e_p(A,TA) , !. | |
545 | translate_e_p(A,TA) :- | |
546 | translate_unary_e_p(A,TA) , !. | |
547 | translate_e_p(A,TA) :- | |
548 | translate_binary_e_p(A,TA) , !. | |
549 | translate_e_p(A,TA) :- | |
550 | translate_if_then_else(A,TA). | |
551 | translate_e_p(A,_) :- | |
552 | add_error(load_alloy_model,'Translation failed for:',A),fail. | |
553 | ||
554 | % Translation in the context where we expect an integer | |
555 | translate_e_p_integer(integer(A,POS),integer(BPOS,A)) :- !, | |
556 | translate_pos(POS,BPOS). | |
557 | translate_e_p_integer(identifier(ID,_Type,POS),identifier(BPOS,ID)) :- % translate without the set_extension | |
558 | is_singleton_set_id(ID) , !, | |
559 | translate_pos(POS,BPOS). | |
560 | translate_e_p_integer(A,TA) :- | |
561 | translate_e_p(A,TSetA), | |
562 | (TSetA = set_extension(_,[Single]) | |
563 | -> TA = Single | |
564 | ; get_position(A,BPOS), | |
565 | add_message(translate_e_p_integer,'Notice: using MU operator, could not statically extract integer singleton set for: ',TSetA,BPOS), | |
566 | %construct_choose(TSetA,TA) | |
567 | TA = mu(BPOS,TSetA) % use the Zed MU operator | |
568 | ). | |
569 | ||
570 | %construct_choose(TSetA,external_function_call(none,'CHOOSE',[TSetA],string(none,'a member of X'),TypeParams,Decl)) :- | |
571 | % % format of raw AST of CHOOSE copied from btype2 | |
572 | % TypeParams = rewrite_protected([identifier(none,T)]), | |
573 | % Decl = rewrite_protected(total_function(none,pow_subset(none,identifier(none,T)),identifier(none,T))). | |
574 | ||
575 | translate_if_then_else(if_then_else(ConditionPred,TruthExpr,FalsityExpr,_Type,POS),TIfThenElse) :- | |
576 | translate_e_p(ConditionPred,TConditionPred), | |
577 | translate_e_p(TruthExpr,TTruthExpr), | |
578 | translate_e_p(FalsityExpr,TFalsityExpr), | |
579 | translate_pos(POS,BPOS), | |
580 | get_type_and_arity_from_alloy_term(TruthExpr,Type,_), | |
581 | ((Type = [untyped] ; is_primitive_type(Type,_)) | |
582 | -> TIfThenElse = conjunct(BPOS, | |
583 | implication(BPOS,TConditionPred,TTruthExpr), | |
584 | implication(BPOS,negation(BPOS,TConditionPred),TFalsityExpr)) | |
585 | ; TIfThenElse = if_then_else(BPOS,TConditionPred,TTruthExpr,TFalsityExpr) | |
586 | ). | |
587 | ||
588 | translate_quantifier_e(Quantifier,TQuantifier) :- | |
589 | Quantifier =.. [Functor,Params,Fields,Body,_Type,POS], | |
590 | member(Functor,[all,no,some,one,lone,comprehension]), | |
591 | maplist(translate_e_p,Params,TParams), | |
592 | maplist(strip_singleton_set,TParams,TTParams) , % more of a hack; we should ensure singleton_set is properly set | |
593 | translate_pos(POS,BPOS), | |
594 | maplist(translate_quantifier_field,Fields,TFieldsList,SingletonSetNames), | |
595 | (is_disjoint_quantifier(Fields) | |
596 | -> maplist(translate_e_p,SingletonSetNames,TSets), | |
597 | AllDiff = equal(BPOS,card(BPOS,general_union(BPOS,set_extension(BPOS,TSets))),integer(BPOS,Len)), | |
598 | length(Fields,Len), | |
599 | %print(disjoint(Len)),nl, | |
600 | join_untyped_ast_nodes(conjunct,[AllDiff|TFieldsList],TFields) | |
601 | ; join_untyped_ast_nodes(conjunct,TFieldsList,TFields) | |
602 | ), | |
603 | translate_e_p(Body,TBody), | |
604 | translate_quantifier_e_aux(BPOS,Functor,TTParams,TFields,TBody,TQuantifier), | |
605 | maplist(retract_singleton_set(BPOS),Params), | |
606 | maplist(retract_singleton_set(BPOS),SingletonSetNames). | |
607 | ||
608 | translate_quantifier_e_aux(Pos,all,TParams,TFields,TBody,forall(Pos,TParams,implication(none,TFields,TBody))). | |
609 | translate_quantifier_e_aux(Pos,no,TParams,TFields,TBody,negation(Pos,exists(none,TParams,conjunct(none,TFields,TBody)))). | |
610 | translate_quantifier_e_aux(Pos,some,TParams,TFields,TBody,exists(Pos,TParams,conjunct(none,TFields,TBody))). | |
611 | translate_quantifier_e_aux(Pos,one,TParams,TFields,TBody,equal(Pos,card(none,comprehension_set(none,TParams,conjunct(none,TFields,TBody))),integer(none,1))). | |
612 | translate_quantifier_e_aux(Pos,lone,TParams,TFields,TBody,less_equal(Pos,card(none,comprehension_set(none,TParams,conjunct(none,TFields,TBody))),integer(none,1))). | |
613 | translate_quantifier_e_aux(Pos,comprehension,TParams,TFields,TBody,comprehension_set(Pos,TParams,conjunct(none,TFields,TBody))). | |
614 | ||
615 | % Translate Constants | |
616 | translate_cst_e_p(iden(POS),event_b_identity(BPOS)) :- % has no Span Info ! | |
617 | translate_pos(POS,BPOS). | |
618 | translate_cst_e_p(identifier(Cst,_,POS),BConstruct) :- | |
619 | alloy_constant_to_b(Cst,BPOS,BConstruct),!, | |
620 | translate_pos(POS,BPOS). | |
621 | translate_cst_e_p(this,_) :- print('this not yet translated'),nl,fail. | |
622 | ||
623 | ||
624 | alloy_constant_to_b(none,BPOS,empty_set(BPOS)). | |
625 | alloy_constant_to_b('boolean''False',BPOS,boolean_false(BPOS)). | |
626 | alloy_constant_to_b('boolean''True',BPOS,boolean_true(BPOS)). | |
627 | ||
628 | ||
629 | translate_unary_e_p(string(StringCodes,POS),set_extension(BPOS,[string(BPOS,String)])) :- | |
630 | atom_codes(String,StringCodes) , ! , | |
631 | translate_pos(POS,BPOS). | |
632 | translate_unary_e_p(seq(ID),sequence_extension(none,TID)) :- | |
633 | translate_unary_e_p(ID,TID) , !. | |
634 | translate_unary_e_p(Int,integer(none,Int)) :- integer(Int) , !. | |
635 | translate_unary_e_p(identifier(ID,_Type,POS),set_extension(BPOS,[identifier(BPOS,NID)])) :- | |
636 | % singleton enumerated set like S = {_S} | |
637 | enumerated_set(ID) , | |
638 | is_singleton_set_id(ID) , !, | |
639 | atom_concat('_',ID,NID) , | |
640 | translate_pos(POS,BPOS). | |
641 | translate_unary_e_p(identifier(ID,_Type,POS),set_extension(BPOS,[identifier(BPOS,ID)])) :- | |
642 | is_singleton_set_id(ID) , !, | |
643 | translate_pos(POS,BPOS). | |
644 | translate_unary_e_p(ID,set_extension(none,[identifier(none,NID)])) :- | |
645 | enumerated_set(ID) , | |
646 | is_singleton_set_id(ID) , ! , | |
647 | atom_concat('_',ID,NID). | |
648 | translate_unary_e_p(ID,set_extension(none,[identifier(none,ID)])) :- | |
649 | is_singleton_set_id(ID) , !. % DOES THIS EVER TRIGGER ? | |
650 | translate_unary_e_p(integer(A,POS),set_extension(BPOS,[integer(BPOS,A)])) :- !, | |
651 | translate_pos(POS,BPOS). | |
652 | translate_unary_e_p(identifier('Int',_Type,POS),integer_set(BPOS,'INTEGER')) :- !, | |
653 | translate_pos(POS,BPOS). | |
654 | translate_unary_e_p(identifier('String',_,_),string_set(none)) :- !. | |
655 | translate_unary_e_p('Int',integer_set(none,'INTEGER')) :- !. | |
656 | translate_unary_e_p(identifier(ID,_Type,POS),identifier(BPOS,ID)) :- !,translate_pos(POS,BPOS). | |
657 | translate_unary_e_p(boolean(true,POS),truth(BPOS)) :- !, % was boolean_true, but Alloy has no booleans | |
658 | translate_pos(POS,BPOS). | |
659 | translate_unary_e_p(boolean(false,POS),falsity(BPOS)) :- !, % was boolean_false | |
660 | translate_pos(POS,BPOS). | |
661 | translate_unary_e_p(Type,integer_set(none,'INTEGER')) :- | |
662 | % lhs of sequence is integer, Alloy Types are like [seqInt,A] for set(couple(INTEGER,A)) | |
663 | atom(Type) , atom_concat(seq,_,Type) , !. | |
664 | translate_unary_e_p(ID,identifier(none,ID)) :- atom(ID) , !. | |
665 | translate_unary_e_p(UnaryP,TUnaryP) :- | |
666 | % and/or defines a list of ast nodes | |
667 | UnaryP =.. [Op,ArgList|_] , | |
668 | memberchk(Op,[and,or]) , % translated to conjunct/disjunct | |
669 | is_list(ArgList) , ! , | |
670 | maplist(translate_e_p,ArgList,TArgList) , | |
671 | join_predicates(Op,TArgList,TUnaryP). | |
672 | translate_unary_e_p(UnaryP,TUnaryP) :- | |
673 | UnaryP =.. [Op,Arg,_Type,POS] , | |
674 | member(Op,[no,one,some,lone]) , ! , | |
675 | translate_e_p(Arg,TArg), | |
676 | translate_pos(POS,BPOS), | |
677 | translate_quantified_e(BPOS,Op,TArg,TUnaryP). | |
678 | translate_unary_e_p(card(Arg,_Type,POS),set_extension(BPOS,[card(BPOS,TArg)])) :- !, % wrap card into set extension | |
679 | translate_e_p(Arg,TArg), | |
680 | translate_pos(POS,BPOS). | |
681 | translate_unary_e_p(UnaryP,TUnaryP) :- | |
682 | UnaryP =.. [Op,Arg,_Type,POS] , | |
683 | translate_e_p(Arg,TArg) , | |
684 | alloy_to_b_unary_operator(Op,BOp), | |
685 | translate_pos(POS,BPOS), | |
686 | TUnaryP =.. [BOp,BPOS,TArg]. | |
687 | ||
688 | ||
689 | % FUNCTIONS defined by func in util: | |
690 | ||
691 | %alloy_utility_function(Name,Arity,BOperator,ArgType,ReturnType). | |
692 | alloy_utility_function(Name,Arity,BOperator,integer,integer) :- | |
693 | alloy_to_b_integer_to_integer_func(Name,Arity,BOperator). | |
694 | alloy_utility_function(Name,Arity,BOperator,set,integer) :- | |
695 | alloy_to_b_integer_func(Name,Arity,BOperator). | |
696 | alloy_utility_function(Name,Arity,BOperator,integer,set) :- | |
697 | alloy_to_b_integer_operator_func(Name,Arity,BOperator). | |
698 | alloy_utility_function(Name,Arity,BOperator,set,set) :- | |
699 | alloy_to_b_operator_func(Name,Arity,BOperator). | |
700 | ||
701 | % functions with integer arguments and result | |
702 | alloy_to_b_integer_to_integer_func('integer''minus',2,minus). | |
703 | alloy_to_b_integer_to_integer_func('integer''plus',2,add). | |
704 | alloy_to_b_integer_to_integer_func('integer''div',2,div). | |
705 | alloy_to_b_integer_to_integer_func('integer''mul',2,multiplication). | |
706 | alloy_to_b_integer_to_integer_func('integer''rem',2,modulo). | |
707 | %alloy_to_b_integer_to_integer_func('integer''sum',sigma). % TO DO: translate sum | |
708 | alloy_to_b_integer_to_integer_func('integer''add',2,add). | |
709 | alloy_to_b_integer_to_integer_func('integer''sub',2,minus). | |
710 | %alloy_to_b_integer_to_integer_func('integer''smaller',max). % TO DO: if Arg1 < Arg2 then Arg1 else Arg2 end | |
711 | ||
712 | % Unary: | |
713 | alloy_to_b_integer_to_integer_func('integer''negate',1,unary_minus). | |
714 | alloy_to_b_integer_to_integer_func('integer''next',1,successor). % not sure this is called; seems to call arity 0 and use join | |
715 | alloy_to_b_integer_to_integer_func('integer''prev',1,predecessor). | |
716 | ||
717 | ||
718 | % functions with integer result but set arguments | |
719 | alloy_to_b_integer_func('integer''min',1,min). | |
720 | alloy_to_b_integer_func('integer''max',1,max). | |
721 | alloy_to_b_integer_func('integer''min',0,min_int). % TO DO: investigate bit-width related translation | |
722 | alloy_to_b_integer_func('integer''max',0,max_int). % maybe we should have a preference for Alloy2B about INT/INTEGER | |
723 | % Note: for run Arithmetic for 6 Int the Alloy Evaluator produces {-32} for min and {+31} for max | |
724 | ||
725 | % predicate functions with integer arguments | |
726 | alloy_to_b_operator_func('integer''next',0,successor). | |
727 | alloy_to_b_operator_func('integer''prev',0,predecessor). | |
728 | ||
729 | % predicate functions with integer arguments | |
730 | alloy_to_b_integer_operator_func('integer''gt',2,greater). | |
731 | alloy_to_b_integer_operator_func('integer''lt',2,less). | |
732 | alloy_to_b_integer_operator_func('integer''gte',2,greater_equal). | |
733 | alloy_to_b_integer_operator_func('integer''lte',2,less_equal). | |
734 | alloy_to_b_integer_operator_func('integer''eq',2,equal). | |
735 | ||
736 | % dom[r] = dom(r) | |
737 | alloy_to_b_relational_utility_function('relation''dom',[Param],_Type,BPOS,TCall) :- ! , | |
738 | translate_e_p(Param,TParam) , | |
739 | TCall = dom(BPOS,TParam). | |
740 | % ran[r] = ran(r) | |
741 | alloy_to_b_relational_utility_function('relation''ran',[Param],_Type,BPOS,TCall) :- ! , | |
742 | translate_e_p(Param,TParam) , | |
743 | TCall = range(BPOS,TParam). | |
744 | % total[r,d] = !x.(x:d => r[{x}] /= {}}) | |
745 | alloy_to_b_relational_utility_function('relation''total',[Relation,Domain],_Type,BPOS,TCall) :- ! , | |
746 | translate_e_p(Relation,TRelation) , | |
747 | translate_e_p(Domain,TDomain) , | |
748 | gen_identifier(0,"_c_",ID0), | |
749 | LHS = member(BPOS,ID0,TDomain) , | |
750 | RHS = not_equal(BPOS,image(BPOS,TRelation,set_extension(BPOS,[ID0])),empty_set(BPOS)) , | |
751 | TCall = forall(BPOS,[ID0],implication(BPOS,LHS,RHS)). | |
752 | % functional[r,d] = !x.(x:d => card(r[{x}]) <= 1) | |
753 | alloy_to_b_relational_utility_function('relation''functional',[Relation,Domain],_Type,BPOS,TCall) :- ! , | |
754 | translate_e_p(Relation,TRelation) , | |
755 | translate_e_p(Domain,TDomain) , | |
756 | gen_identifier(0,"_c_",ID0), | |
757 | LHS = member(BPOS,ID0,TDomain) , | |
758 | RHS = less_equal(BPOS,card(BPOS,image(BPOS,TRelation,set_extension(BPOS,[ID0]))),integer(BPOS,1)) , | |
759 | TCall = forall(BPOS,[ID0],implication(BPOS,LHS,RHS)). | |
760 | % function[r,d] = !x.(x:d => card(r[{x}]) = 1) | |
761 | alloy_to_b_relational_utility_function('relation''function',[Relation,Domain],_Type,BPOS,TCall) :- ! , | |
762 | translate_e_p(Relation,TRelation) , | |
763 | translate_e_p(Domain,TDomain) , | |
764 | gen_identifier(0,"_c_",ID0), | |
765 | LHS = member(BPOS,ID0,TDomain) , | |
766 | RHS = equal(BPOS,card(BPOS,image(BPOS,TRelation,set_extension(BPOS,[ID0]))),integer(BPOS,1)) , | |
767 | TCall = forall(BPOS,[ID0],implication(BPOS,LHS,RHS)). | |
768 | % injective[r,d] = !(x).(x:d => card(r~[{x}]) <= 1) | |
769 | alloy_to_b_relational_utility_function('relation''injective',[Relation,Domain],_Type,BPOS,TCall) :- ! , | |
770 | translate_e_p(Relation,TRelation) , | |
771 | translate_e_p(Domain,TDomain) , | |
772 | gen_identifier(0,"_c_",ID0), | |
773 | LHS = member(BPOS,ID0,TDomain) , | |
774 | RHS = less_equal(BPOS,card(BPOS,image(BPOS,reverse(BPOS,TRelation),set_extension(BPOS,[ID0]))),integer(BPOS,1)) , | |
775 | TCall = forall(BPOS,[ID0],implication(BPOS,LHS,RHS)). | |
776 | alloy_to_b_relational_utility_function(FunName,_,_,BPOS,truth(BPOS)) :- | |
777 | atom_concat('relation',_,FunName) , ! , | |
778 | add_error(alloy_to_b_relational_utility_function,'Function from util/relation currently not supported',[],BPOS). | |
779 | % TODO: implement rest as described in the article | |
780 | ||
781 | %remove_prime(Old,New) :- atom_codes(Old,OldC) , delete(OldC,39,NewC) , atom_codes(New,NewC). | |
782 | ||
783 | get_clean_ordering_fun_name(OrderingFunctionName,CleanOrdFunName) :- | |
784 | member(CleanOrdFunName,[first,last,min,max,next,nexts,prev,prevs,larger,smaller,lt,lte,gt,gte]) , | |
785 | atom_concat(_,CleanOrdFunName,OrderingFunctionName). | |
786 | ||
787 | get_ordering_definition_name(TempFunctionName,SignatureName,FunctionName) :- | |
788 | member(TempFunctionName,[next,prev,nexts,prevs]) , | |
789 | atom_concat(TempFunctionName,'_',TTempFunctionName) , | |
790 | atom_concat(TTempFunctionName,SignatureName,FunctionName). | |
791 | ||
792 | translate_binary_e_p(in(Arg1,Arg2,_Type,POS),Translation) :- !, | |
793 | translate_pos(POS,BPOS), translate_e_p(Arg1,TArg1), | |
794 | translate_binary_in(TArg1,Arg2,BPOS,Translation). | |
795 | translate_binary_e_p(CartTerm,TCartesian) :- | |
796 | is_cartesian_product_term(CartTerm,Arg1,Arg2,POS), | |
797 | !, | |
798 | translate_pos(POS,BPOS), | |
799 | translate_cartesian(BPOS,Arg1,Arg2,TCartesian). | |
800 | % S <: Rel --> {x1,..,xk| x1:S & (x1,...,xk):Rel} | |
801 | translate_binary_e_p(dom_restr(Arg1,Arg2,_Type,POS),TDom) :- | |
802 | \+ is_binary_relation(Arg2), % for binary relation translation to B domain_restriction works | |
803 | !, | |
804 | get_type_and_arity_from_alloy_term(Arg2,_,Arity), | |
805 | gen_ids_and_couple(Arity,IDS,Couple), | |
806 | translate_pos(POS,BPOS), | |
807 | TDom = comprehension_set(BPOS,IDS,conjunct(BPOS,Mem1,Mem2)), | |
808 | IDS = [ID1|_], | |
809 | Mem1 = member(TPos,ID1,TArg1), | |
810 | Mem2 = member(TPos,Couple,TArg2), | |
811 | translate_e_p(Arg1,TArg1), | |
812 | translate_e_p(Arg2,TArg2). | |
813 | translate_binary_e_p(join(Arg1,Arg2,_Type,POS),TJoin) :- !, | |
814 | translate_pos(POS,BPOS), | |
815 | translate_join(BPOS,Arg1,Arg2,TJoin). | |
816 | translate_binary_e_p(let(VarName,Expr,Sub,Type,POS),TLet) :- ! , | |
817 | translate_e_p(VarName,TVarName) , | |
818 | translate_e_p(Expr,TExpr) , | |
819 | (Type == type(['PrimitiveBoolean'],0) -> NewFunctor = let_predicate ; NewFunctor = let_expression) , | |
820 | translate_e_p(Sub,TSub) , | |
821 | translate_pos(POS,BPOS) , | |
822 | TLet =.. [NewFunctor,BPOS,[TVarName],equal(BPOS,TVarName,TExpr),TSub]. | |
823 | translate_binary_e_p(Call,TCall) :- | |
824 | Call =.. [Functor,Name,Params,Type,POS] , | |
825 | (Functor = pred_call ; Functor = fun_call ) , ! , | |
826 | translate_pos(POS,BPOS), | |
827 | translate_function_call(Name,Params,Type,BPOS,TCall). | |
828 | translate_binary_e_p(Binary,TBinary) :- | |
829 | Binary =.. [Op,Arg1,Arg2,_Type,POS] , | |
830 | alloy_to_b_integer_operator(Op,BOp), !, | |
831 | translate_e_p_integer(Arg1,TArg1), | |
832 | translate_e_p_integer(Arg2,TArg2), | |
833 | translate_pos(POS,BPOS), | |
834 | TBinary =.. [BOp,BPOS,TArg1,TArg2]. | |
835 | translate_binary_e_p(Binary,TBinary) :- | |
836 | Binary =.. [Op,Arg1,Arg2,_Type,POS] , | |
837 | alloy_to_b_binary_operator(Op,BOp), | |
838 | translate_e_p(Arg1,TArg1), | |
839 | translate_e_p(Arg2,TArg2), | |
840 | translate_pos(POS,BPOS), | |
841 | TBinary =.. [BOp,BPOS,TArg1,TArg2]. | |
842 | ||
843 | % translate TArg1 in Arg2 (multplicity are not allowed for not in) | |
844 | translate_binary_in(TArg1,Arg2,BPOS,Translation) :- | |
845 | compound(Arg2),functor(Arg2,Functor,4), % binary operator, | |
846 | alloy_to_b_special_multiplicity_type(Functor,_,_,_,_), | |
847 | !, | |
848 | Translation = member(BPOS,TArg1,TArg2), % use element of rather than subset for special type opererators | |
849 | translate_special_multiplicity_binary_e_p(Arg2,TArg2). | |
850 | translate_binary_in(TArg1,Arg2,BPOS,subset(BPOS,TArg1,TArg2)) :- | |
851 | translate_e_p(Arg2,TArg2). | |
852 | ||
853 | /* | |
854 | not yet finished: | |
855 | % replace Arg1 M -> N Arg2 to pure cartesian product and generate predicates | |
856 | translate_multiplicity_to_cartesian_and_pred(cartesian(A,B,Type,Pos),LHS,Left,Right,Res) :- !, | |
857 | Res = cartesian(CA,CB,Type,Pos), | |
858 | get_type_and_arity_from_alloy_term(CA,_Type,ArityA), L2 is Left+ArityA, | |
859 | get_type_and_arity_from_alloy_term(CB,_Type,ArityB), R1 is Right-ArityB, | |
860 | translate_multiplicity_to_cartesian_and_pred(A,LHS,Left,R1,CA), | |
861 | translate_multiplicity_to_cartesian_and_pred(B,LHS,L2,Right,CB). | |
862 | translate_multiplicity_to_cartesian_and_pred(Binary,LHS,Left,Right,Res) :- | |
863 | Binary =.. [Op,Arg1,Arg2,Type,POS] , | |
864 | alloy_to_b_special_multiplicity_type(Op,BOp,LHSMult,RHSMult,ok), | |
865 | !, | |
866 | % TO DO: add extra predicates | |
867 | create_dom(Left,LHS,Pos,Proj1), % project away leftmost tuples | |
868 | create_ran(Right,Proj1,Pos,Proj2), % project away rightmost tuples | |
869 | ||
870 | translate_multiplicity_to_cartesian_and_pred(cartesian(A,B,Type,Pos),LHS,Left,Right,Res). | |
871 | translate_multiplicity_to_cartesian_and_pred(A,_,_,_,A). | |
872 | ||
873 | % create_dom(N,Expr,Pos,Res): create dom(...(dom(Expr))) to project away the leftmost N Arguments of Expr | |
874 | create_dom(0,E,_,Res) :- !, Res=E. | |
875 | create_dom(N,E,Pos,domain(Pos,D1)) :- N>0, N1 is N-1, | |
876 | create_dom(N1,E,Pos,D1). | |
877 | ||
878 | create_ran(0,E,_,Res) :- !, Res=E. | |
879 | */ | |
880 | ||
881 | % translate expressions of the form Arg1 MULT -> MULT Arg2 with MULT : {some,lone, one, ''} | |
882 | % The result is to be used in member(Pos,LHS,TBinary) not for subset checks ! | |
883 | translate_special_multiplicity_binary_e_p(Binary,TBinary) :- | |
884 | Binary =.. [Op,Arg1,Arg2,_Type,POS] , | |
885 | alloy_to_b_special_multiplicity_type(Op,BOp,_,_,ok), | |
886 | translate_e_p(Arg1,TArg1), | |
887 | translate_e_p(Arg2,TArg2), | |
888 | translate_pos(POS,BPOS), | |
889 | TBinary =.. [BOp,BPOS,TArg1,TArg2]. | |
890 | ||
891 | % TODO: update sequence implementation as described in the article | |
892 | ||
893 | % Note: Sequences in B are indexed from 1 to n, in Alloy from 0 to n-1. | |
894 | % Documentation available at http://alloy.lcs.mit.edu/alloy/documentation/quickguide/seq.html | |
895 | % Sequence function calls without a parameter but the sequence itself. | |
896 | % butlast: seq[{size(seq)-1}] | |
897 | sequence_function_to_b('seq\'butlast',BPOS,[Seq],image(BPOS,Seq,set_extension(BPOS,[minus(BPOS,size(BPOS,Seq),integer(BPOS,1))]))). | |
898 | % isEmpty: seq = <> | |
899 | sequence_function_to_b('seq\'isEmpty',BPOS,[Seq],equal(BPOS,Seq,empty_sequence(BPOS))). | |
900 | % hasDups: size(seq) /= card(ran(seq)) | |
901 | sequence_function_to_b('seq\'hasDups',BPOS,[Seq],not_equal(BPOS,size(BPOS,Seq),card(BPOS,range(BPOS,Seq)))). | |
902 | % inds: {x|x:1..size(seq)} | |
903 | sequence_function_to_b('seq\'inds',BPOS,[Seq],comprehension_set(BPOS,[identifier(BPOS,x)],member(BPOS,identifier(BPOS,x),interval(BPOS,integer(BPOS,1),size(BPOS,Seq))))). | |
904 | % lastIdx: LET x BE x = size(seq) IN (IF x > 0 THEN {x} ELSE {} END) END | |
905 | % TO DO: use let like let_expression(BPOS,[identifier(BPOS,x)],equal(BPOS,identifier(BPOS,x),size(BPOS,Seq)),if_then_else(BPOS,greater(BPOS,identifier(BPOS,x),integer(BPOS,0)),set_extension(BPOS,[identifier(BPOS,x)]),empty_set(BPOS))) | |
906 | sequence_function_to_b('seq\'lastIdx',BPOS,[Seq],let_expression(BPOS,[identifier(BPOS,x)],equal(BPOS,identifier(BPOS,x),size(BPOS,Seq)),if_then_else(BPOS,greater(BPOS,identifier(BPOS,x),integer(BPOS,0)),set_extension(BPOS,[identifier(BPOS,x)]),empty_set(BPOS)))). | |
907 | % afterLastIdx: LET x BE x = size(seq) IN (IF x < MAXSEQ THEN {x} ELSE {} END) END | |
908 | % TO DO: use let like let_expression(BPOS,[identifier(BPOS,x)],equal(BPOS,identifier(BPOS,x),size(BPOS,Seq)),if_then_else(BPOS,less(BPOS,identifier(BPOS,x),integer(BPOS,MaxSeq)),set_extension(BPOS,[identifier(BPOS,x)]),empty_set(BPOS))) | |
909 | sequence_function_to_b('seq\'afterLastIdx',BPOS,[Seq],let_expression(BPOS,[identifier(BPOS,x)],equal(BPOS,identifier(BPOS,x),size(BPOS,Seq)),if_then_else(BPOS,less(BPOS,identifier(BPOS,x),integer(BPOS,MaxSeq)),set_extension(BPOS,[identifier(BPOS,x)]),empty_set(BPOS)))) :- | |
910 | maxseq(MaxSeq). | |
911 | % Sequence function calls with one parameter and the sequence itself. | |
912 | % idxOf[elm]: IF size(seq) > 0 THEN {min(seq~[{elm}])} ELSE {} END | |
913 | sequence_function_to_b('seq\'idxOf',BPOS,[Seq,P1],if_then_else(BPOS,not_equal(BPOS,image(BPOS,reverse(BPOS,Seq),P1),empty_set(BPOS)),set_extension(BPOS,[min(BPOS,image(BPOS,reverse(BPOS,Seq),P1))]),empty_set(BPOS))). | |
914 | % lastIdxOf[elm]: IF size(seq) > 0 THEN {max(seq~[{elm}])} ELSE {} END | |
915 | sequence_function_to_b('seq\'lastIdxOf',BPOS,[Seq,P1],if_then_else(BPOS,not_equal(BPOS,image(BPOS,reverse(BPOS,Seq),P1),empty_set(BPOS)),set_extension(BPOS,[max(BPOS,image(BPOS,reverse(BPOS,Seq),P1))]),empty_set(BPOS))). | |
916 | % indsOf[elm]: seq~[{elm}] | |
917 | sequence_function_to_b('seq\'indsOf',BPOS,[Seq,P1],image(BPOS,reverse(BPOS,Seq),set_extension(BPOS,[P1]))). | |
918 | % append[seq2]: LET x BE x = s^s2 IN (IF size(x) < MAXSEQ THEN x ELSE x /|\ MAXSEQ END) END | |
919 | % TO DO: use let like let_expression(BPOS,[identifier(BPOS,x)],equal(BPOS,identifier(BPOS,x),concat(Seq,P1)),if_then_else(BPOS,less_equal(BPOS,size(BPOS,identifier(BPOS,x)),integer(BPOS,MaxSeq)),identifier(BPOS,x),restrict_front(BPOS,identifier(BPOS,x),integer(BPOS,MaxSeq)))) | |
920 | sequence_function_to_b('seq\'append',BPOS,[Seq,P1],let_expression(BPOS,[identifier(BPOS,x)],equal(BPOS,identifier(BPOS,x),concat(Seq,P1)),if_then_else(BPOS,less_equal(BPOS,size(BPOS,identifier(BPOS,x)),integer(BPOS,MaxSeq)),identifier(BPOS,x),restrict_front(BPOS,identifier(BPOS,x),integer(BPOS,MaxSeq))))) :- | |
921 | maxseq(MaxSeq). | |
922 | % add[elm]: IF size(seq) < MAXSEQ THEN seq <- elm ELSE seq END | |
923 | sequence_function_to_b('seq\'add',BPOS,[Seq,P1],if_then_else(BPOS,less(BPOS,size(BPOS,Seq),integer(BPOS,MaxSeq)),insert_tail(BPOS,Seq,P1),Seq)) :- | |
924 | maxseq(MaxSeq). | |
925 | % delete[i]: IF (i >= 0 & i < size(seq)) THEN (seq /|\ i) ^ (seq \|/ i+1) ELSE seq END | |
926 | sequence_function_to_b('seq\'delete',BPOS,[Seq,P1],if_then_else(BPOS,conjunct(BPOS,greater_equal(BPOS,P1,integer(BPOS,0)),less(BPOS,P1,size(BPOS,Seq))),concat(BPOS,restrict_front(BPOS,Seq,P1),restrict_tail(BPOS,Seq,add(BPOS,P1,integer(BPOS,1)))),Seq)). | |
927 | % Sequence function calls with two parameters and the sequence itself. | |
928 | % setAt[i,elm]: IF (i >= 0 & i < size(seq)) THEN (seq /|\ i) ^ [elm] ^ (seq \|/ i+1) ELSE seq END | |
929 | sequence_function_to_b('seq\'setAt',BPOS,[Seq,P1,P2],if_then_else(BPOS,conjunct(BPOS,greater_equal(BPOS,P1,integer(BPOS,0)),less(BPOS,P1,size(BPOS,Seq))),concat(concat(BPOS,restrict_front(BPOS,Seq,P1),sequence_extension(BPOS,[P2])),restrict_tail(BPOS,Seq,add(BPOS,P1,integer(BPOS,1)))),Seq)). | |
930 | % insert[i,elm]: LET x BE x = (IF size(seq) = MAXSEQ THEN seq /|\ (MAXSEQ - 1) ELSE seq END) IN (x /|\ i) ^ [elm] ^ (x \|/ i) END | |
931 | sequence_function_to_b('seq\'insert',BPOS,[Seq,P1,P2],let_expression(BPOS,[identifier(BPOS,x)],equal(BPOS,identifier(BPOS,x),if_then_else(BPOS,equal(BPOS,size(BPOS,Seq),integer(BPOS,MaxSeq)),restrict_front(BPOS,Seq,minus(BPOS,integer(BPOS,MaxSeq),integer(BPOS,1))),Seq)),concat(concat(BPOS,restrict_front(BPOS,Seq,P1),sequence_extension(BPOS,[P2])),restrict_tail(BPOS,Seq,add(BPOS,P1,integer(BPOS,1)))))) :- | |
932 | maxseq(MaxSeq). | |
933 | % subseq[from,to]: IF 0 <= from & from <= to & to < size(seq) THEN (s \|/ from) /|\ ((to-from)+1) ELSE seq end | |
934 | sequence_function_to_b('seq\'subseq',BPOS,[Seq,P1,P2],if_then_else(BPOS,conjunct(BPOS,conjunct(BPOS,less_equal(BPOS,integer(BPOS,0),P1),less_equal(BPOS,P1,P2)),less(BPOS,P2,size(BPOS,Seq))),restrict_front(BPOS,restrict_tail(BPOS,Seq,P1),add(BPOS,minus(BPOS,P2,P1),integer(BPOS,1))))). | |
935 | ||
936 | sequence_function_to_b_functor(Name,BFunctor) :- | |
937 | atom_concat('seq\'',Functor,Name) , | |
938 | sequence_function_to_b_functor_aux(Functor,BFunctor). | |
939 | ||
940 | sequence_function_to_b_functor_aux(first,first). | |
941 | sequence_function_to_b_functor_aux(last,last). | |
942 | sequence_function_to_b_functor_aux(rest,tail). | |
943 | sequence_function_to_b_functor_aux(elems,range). | |
944 | ||
945 | translate_seq_function_param(join(identifier(this,type([Type],1),IPos),Arg2,JType,JPos),TParam) :- ! , | |
946 | % remove join with this for signature fields | |
947 | translate_e_p(join(identifier(Type,type([Type],1),IPos),Arg2,JType,JPos),TParam). | |
948 | translate_seq_function_param(Param,TParam) :- | |
949 | translate_e_p(Param,TParam). | |
950 | ||
951 | ||
952 | % sequence function calls: first, last, rest, elems | |
953 | translate_function_call(Name,[Param],_Type,BPOS,TCall) :- | |
954 | sequence_function_to_b_functor(Name,BFunctor) , ! , | |
955 | translate_seq_function_param(Param,TParam) , | |
956 | TCall =.. [BFunctor,BPOS,TParam]. | |
957 | translate_function_call(Function,Params,_Type,BPOS,TCall) :- | |
958 | maplist(translate_seq_function_param,Params,TParams) , | |
959 | sequence_function_to_b(Function,BPOS,TParams,TCall) , !. | |
960 | translate_function_call(Name,Params,Type,BPOS,Result) :- | |
961 | alloy_to_b_relational_utility_function(Name,Params,Type,BPOS,Result). | |
962 | translate_function_call(Name,Params,_Type,BPOS,Result) :- | |
963 | length(Params,Arity), | |
964 | alloy_utility_function(Name,Arity,BOp,ArgType,ReturnType) , !, % functions like plus, minus, mul, ... with integer arguments and result | |
965 | (ArgType = integer -> | |
966 | maplist(translate_e_p_integer,Params,TParams) | |
967 | ; maplist(translate_e_p,Params,TParams)), | |
968 | (ReturnType = integer -> | |
969 | Result = set_extension(BPOS,[TCall]) % we add set_extension wrapper | |
970 | ; Result = TCall), | |
971 | TCall =.. [BOp,BPOS|TParams]. | |
972 | % ordering function calls | |
973 | translate_function_call(FunName,Params,type([SignatureName|_],_),BPOS,TCall) :- | |
974 | translate_e_p(SignatureName,TSignatureName) , | |
975 | get_clean_ordering_fun_name(FunName,CleanOrdFunName) , | |
976 | translate_ordering_function(CleanOrdFunName,Params,SignatureName,TSignatureName,BPOS,TCall). | |
977 | translate_function_call(Name,Params,_,BPOS,TCall) :- | |
978 | % predicate and function call | |
979 | maplist(translate_e_p,Params,TParams) , | |
980 | maplist(strip_singleton_set_from_this,TParams,TTParams) , % identifier 'this' is added for fields which is already wrapped in a set extension | |
981 | TCall = definition(BPOS,Name,TTParams). | |
982 | ||
983 | % first: IF S_ord /= {} THEN {min(S_ord)} ELSE {} | |
984 | translate_ordering_function(first,[],_,TSignatureName,BPOS,if_then_else(BPOS,not_equal(BPOS,TSignatureName,empty_set(BPOS)),set_extension(BPOS,[min(BPOS,TSignatureName)]),empty_set(BPOS))) :- !. | |
985 | % last: IF S_ord /= {} THEN {max(S_ord)} ELSE {} | |
986 | translate_ordering_function(last,[],_,TSignatureName,BPOS,if_then_else(BPOS,not_equal(BPOS,TSignatureName,empty_set(BPOS)),set_extension(BPOS,[max(BPOS,TSignatureName)]),empty_set(BPOS))) :- !. | |
987 | % min[p]: IF p /= {} THEN {min(p)} ELSE {} | |
988 | % max[p]: IF p /= {} THEN {min(p)} ELSE {} | |
989 | translate_ordering_function(FunName,[Param],_,_,BPOS,TCall) :- | |
990 | (FunName == min ; FunName == max) , ! , | |
991 | translate_e_p(Param,TParam) , | |
992 | InnerCall =.. [FunName,BPOS,TParam] , | |
993 | TCall = if_then_else(BPOS,not_equal(BPOS,TParam,empty_set(BPOS)),set_extension(BPOS,[InnerCall]),empty_set(BPOS)). | |
994 | translate_ordering_function(FunName,[Param],SignatureName,_,BPOS,TCall) :- | |
995 | (FunName == next ; FunName == nexts ; FunName == prev ; FunName == prevs) , ! , | |
996 | get_ordering_definition_name(FunName,SignatureName,DefName) , | |
997 | translate_e_p(Param,TParam) , | |
998 | TCall = definition(BPOS,DefName,[TParam]). | |
999 | % larger[p1,p1]: IF p1 \/ p2 /= {} THEN {max(p1 \/ p2)} ELSE {} END | |
1000 | % smaller[p1,p2]: IF p1 \/ p2 /= {} THEN {min(p1 \/ p2)} ELSE {} END | |
1001 | translate_ordering_function(FunName,[P1,P2],_,_,BPOS,TCall) :- | |
1002 | (FunName == larger ; FunName == smaller) , | |
1003 | get_partial_b_functor_for_ordering(FunName,BFunctor) , | |
1004 | translate_e_p(P1,TP1) , | |
1005 | translate_e_p(P2,TP2) , | |
1006 | ParamUnion = union(BPOS,TP1,TP2) , | |
1007 | TInnerCall =.. [BFunctor,BPOS,ParamUnion] , | |
1008 | InnerCall = set_extension(BPOS,[TInnerCall]) , | |
1009 | TCall = if_then_else(BPOS,not_equal(BPOS,ParamUnion,empty_set(BPOS)),InnerCall,empty_set(BPOS)). | |
1010 | % lt[p1,p2]: (p1 = {}) or (p1 /= {} & p2 /= {} & p1 /= p2 & {min(p1 \/ p2)} = p1)) | |
1011 | % gt[p1,p2]: (p1 = {}) or (p1 /= {} & p2 /= {} & p1 /= p2 & {max(p1 \/ p2)} = p1)) | |
1012 | translate_ordering_function(FunName,[P1,P2],_,_,BPOS,TCall) :- | |
1013 | (FunName == lt ; FunName == gt) , | |
1014 | get_partial_b_functor_for_ordering(FunName,BFunctor) , | |
1015 | translate_e_p(P1,TP1) , | |
1016 | translate_e_p(P2,TP2) , | |
1017 | TInnerCall =.. [BFunctor,BPOS,union(BPOS,TP1,TP2)] , | |
1018 | InnerCall = set_extension(BPOS,[TInnerCall]) , | |
1019 | LHS = equal(BPOS,TP1,empty_set(BPOS)) , | |
1020 | RHS = conjunct(BPOS,conjunct(BPOS,conjunct(BPOS,not_equal(BPOS,TP1,empty_set(BPOS)),not_equal(BPOS,TP2,empty_set(BPOS))),not_equal(BPOS,TP1,TP2)),equal(BPOS,InnerCall,TP1)) , | |
1021 | TCall = disjunct(BPOS,LHS,RHS). | |
1022 | % lte[p1,p2]: (p1 = {}) or (p1 /= {} & p2 /= {} & {min(p1 \/ p2)} = p1) | |
1023 | % gte[p1,p2]: (p1 = {}) or (p1 /= {} & p2 /= {} & {max(p1 \/ p2)} = p1) | |
1024 | translate_ordering_function(FunName,[P1,P2],_,_,BPOS,TCall) :- | |
1025 | (FunName == lte ; FunName == gte) , | |
1026 | get_partial_b_functor_for_ordering(FunName,BFunctor) , | |
1027 | translate_e_p(P1,TP1) , | |
1028 | translate_e_p(P2,TP2) , | |
1029 | TInnerCall =.. [BFunctor,BPOS,union(BPOS,TP1,TP2)] , | |
1030 | InnerCall = set_extension(BPOS,[TInnerCall]) , | |
1031 | LHS = equal(BPOS,TP1,empty_set(BPOS)) , | |
1032 | RHS = conjunct(BPOS,conjunct(BPOS,not_equal(BPOS,TP1,empty_set(BPOS)),not_equal(BPOS,TP2,empty_set(BPOS))),equal(BPOS,InnerCall,TP1)) , | |
1033 | TCall = disjunct(BPOS,LHS,RHS). | |
1034 | translate_ordering_function(FunName,_,_,_,BPOS,empty_set(BPOS)) :- | |
1035 | add_error(translate_ordering_function,'Cannot translate ordering function',[FunName],BPOS). | |
1036 | ||
1037 | get_partial_b_functor_for_ordering(larger,max). | |
1038 | get_partial_b_functor_for_ordering(smaller,min). | |
1039 | get_partial_b_functor_for_ordering(lt,min). | |
1040 | get_partial_b_functor_for_ordering(lte,min). | |
1041 | get_partial_b_functor_for_ordering(gt,max). | |
1042 | get_partial_b_functor_for_ordering(gte,max). | |
1043 | ||
1044 | strip_singleton_set(set_extension(_,[identifier(Pos,Name)]),identifier(Pos,Name)) :- !. | |
1045 | strip_singleton_set(A,A). | |
1046 | ||
1047 | strip_singleton_set_from_this(set_extension(_,[identifier(Pos,this)]),identifier(Pos,this)) :- !. | |
1048 | strip_singleton_set_from_this(A,A). | |
1049 | ||
1050 | translate_cartesian(TPos,Arg1,Arg2,Res) :- | |
1051 | translate_e_p(Arg1,TArg1), | |
1052 | translate_cartesian2(TPos,TArg1,Arg2,Res). | |
1053 | ||
1054 | translate_cartesian2(TPos,TArg1,Arg2,Res) :- | |
1055 | translate_e_p(Arg2,TArg2), | |
1056 | translate_cartesian3(TPos,TArg1,Arg2,TArg2,Res). | |
1057 | % P -> Q --> P*Q | |
1058 | translate_cartesian3(TPos,TArg1,Arg2,TArg2,cartesian_product(TPos,TArg1,TArg2)) :- | |
1059 | is_unary_relation(Arg2), | |
1060 | !. | |
1061 | % P -> Q --> {c0, c1,...,ck | c0:P & (c1,...,ck):Q} | |
1062 | translate_cartesian3(TPos,TArg1,Arg2,TArg2,comprehension_set(TPos,[ID0|IDs2],conjunct(TPos,Mem1,Mem2))) :- | |
1063 | get_type_and_arity_from_alloy_term(Arg2,_Type,Arity), | |
1064 | gen_ids_and_couple(Arity,IDs2,Couple2), | |
1065 | gen_identifier(0,"_c_",ID0), | |
1066 | Mem1 = member(TPos,ID0,TArg1), | |
1067 | Mem2 = member(TPos,Couple2,TArg2). | |
1068 | ||
1069 | gen_ids_and_couple(Arity,[ID1|IDListRest],NestedCouple) :- | |
1070 | Arity>0, | |
1071 | gen_identifier(1,"_c_",ID1), | |
1072 | gen_ids_and_couple(2,Arity,IDListRest,ID1,NestedCouple). | |
1073 | ||
1074 | gen_ids_and_couple(Nr,Arity,L,Acc,Res) :- Nr>Arity,!, L=[], Res=Acc. | |
1075 | gen_ids_and_couple(Nr,Arity,[IDN|T],Acc,Res) :- | |
1076 | gen_identifier(Nr,"_c_",IDN), | |
1077 | N1 is Nr+1, | |
1078 | gen_ids_and_couple(N1,Arity,T,couple(none,Acc,IDN),Res). | |
1079 | ||
1080 | gen_identifier(Nr,Prefix,identifier(none,ID)) :- | |
1081 | number_codes(Nr,NrC), | |
1082 | append(Prefix,NrC,AC), | |
1083 | atom_codes(ID,AC). | |
1084 | ||
1085 | % ordering function calls like s.next.next are converted to fun_call | |
1086 | translate_join(_,Arg1,Arg2,TBinaryJoin) :- | |
1087 | Arg2 = fun_call(Name,[],Type,A2Pos) , | |
1088 | \+ atom_concat('integer',_,Name) , | |
1089 | translate_e_p(fun_call(Name,[Arg1],Type,A2Pos),TBinaryJoin). | |
1090 | % Translation of the dot join operator has several special cases depending on the arity of the arguments. | |
1091 | translate_join(Pos,Arg1,Arg2,TBinaryJoin) :- | |
1092 | translate_e_p(Arg1,TArg1), | |
1093 | translate_e_p(Arg2,TArg2), | |
1094 | %print(translate_join(Arg1,Arg2)),nl, | |
1095 | translate_join_aux(Pos,Arg1,Arg2,TArg1,TArg2,TBinaryJoin). | |
1096 | ||
1097 | % Note: N-ary relation are encoded in B as follows: | |
1098 | % { (e1 |-> (e2 |-> (e3 |-> ...))) ,... }, for example: | |
1099 | % {(tracy|->(spanish|->french)),(carol|->(spanish|->french)), ...} | |
1100 | ||
1101 | % univ.P --> ran(P) % this does NOT work for ternary,... relations | |
1102 | translate_join_aux(TPos,Arg1,Arg2,_TArg1,TArg2,range(TPos,TArg2)) :- | |
1103 | is_univ(Arg1), | |
1104 | is_binary_relation(Arg2), | |
1105 | !. | |
1106 | % P.univ --> dom(P) % this works for ternary,... relations | |
1107 | translate_join_aux(TPos,_Arg1,Arg2,TArg1,_TArg2,domain(TPos,TArg1)) :- | |
1108 | is_univ(Arg2), | |
1109 | !. | |
1110 | % {el}.R --> {R(el)} | |
1111 | translate_join_aux(Pos,Arg1,Arg2,TArg1,TArg2,set_extension(Pos,[function(Pos,TArg2,[TTArg1])])) :- | |
1112 | get_type_and_arity_from_alloy_term(Arg1,Type1,Arity), Arity=1, %is_unary_relation(Arg1), | |
1113 | is_binary_relation(Arg2), | |
1114 | is_total_function(TArg2,Type1), | |
1115 | can_remove_singleton_set(TArg1,TTArg1), | |
1116 | !. | |
1117 | % unary.R --> R[unary] | |
1118 | translate_join_aux(Pos,Arg1,Arg2,TArg1,TArg2,image(Pos,TArg2,TArg1)) :- % Unary.Arg2 --> Arg2[Unary] | |
1119 | is_unary_relation(Arg1), | |
1120 | is_binary_relation(Arg2), | |
1121 | !. | |
1122 | % binary.unary | |
1123 | % Next RULE is broken, can lead to Type errors and test is wrong: | |
1124 | %translate_join_aux(Pos,Arg1,Arg2,TArg1,TArg2,function(Pos,reverse(Pos,TArg1),[TTArg2])) :- | |
1125 | % % function call if lhs is a total function and rhs a unary relation | |
1126 | % is_binary_relation(Arg1), | |
1127 | % is_unary_relation(Arg2), | |
1128 | % is_total_function(TArg1) , ! , % TEST SHOULD BE SURJECTIVE and INJECTIVE !! | |
1129 | % remove_singleton_set(TArg2,TTArg2). | |
1130 | % Arg1.Unary --> Arg1~[Unary] | |
1131 | translate_join_aux(Pos,_Arg1,Arg2,TArg1,TArg2,image(Pos,reverse(Pos,TArg1),TArg2)) :- | |
1132 | is_unary_relation(Arg2), | |
1133 | !. | |
1134 | % binary.binary: Arg1.Arg2 --> (Arg1 ; Arg2) | |
1135 | translate_join_aux(Pos,Arg1,Arg2,TArg1,TArg2,composition(Pos,TArg1,TArg2)) :- | |
1136 | is_binary_relation(Arg1), | |
1137 | is_binary_relation(Arg2), | |
1138 | !. | |
1139 | translate_join_aux(Pos,Arg1,Arg2,TArg1,TArg2,comprehension_set(Pos,IDS,Body)) :- | |
1140 | Body = conjunct(Pos,TypingPred,exists(Pos,[JoinID],conjunct(Pos,JoinTypingPred,conjunct(Pos,Mem1,Mem2)))), | |
1141 | get_type_and_arity_from_alloy_term(Arg2,[JoinIDType|RTypes],Arity), % first type refers to outter variable | |
1142 | gen_ids_and_couple(Arity,IDs2,Couple2), IDs2 = [JoinID|Rest2], | |
1143 | get_typing_pred_for_ids(Pos,RTypes,Rest2,TypingPred) , | |
1144 | get_typing_pred_for_ids(Pos,[JoinIDType],[JoinID],JoinTypingPred) , | |
1145 | (is_univ(Arg1) -> | |
1146 | Mem1 = truth(TPos), IDS=Rest2 | |
1147 | ; is_unary_relation(Arg1) -> | |
1148 | strip_singleton_set_from_this(TArg1,TTArg1) , | |
1149 | Mem1 = member(TPos,JoinID,TTArg1), | |
1150 | IDS = Rest2 | |
1151 | ; gen_identifier(0,"_c_",ID0), | |
1152 | IDS = [ID0|Rest2], | |
1153 | Mem1 = member(TPos,couple(TPos,ID0,JoinID),TArg1) | |
1154 | ), | |
1155 | Mem2 = member(TPos,Couple2,TArg2). | |
1156 | translate_join_aux(Pos,Arg1,Arg2,_TArg1,_TArg2,empty_set(Pos)) :- | |
1157 | format('~nJoin not supported this way:~nLeft: ~w~nRight: ~w~n',[Arg1,Arg2]), | |
1158 | add_error(load_alloy_model,'Cannot translate this type of join yet',[Arg1,Arg2],Pos). | |
1159 | ||
1160 | % This predicate relies on the order of elements in 2. and 3. argument for typing. | |
1161 | % TO DO: improve | |
1162 | get_typing_pred_for_ids(Pos,[],[],truth(Pos)). | |
1163 | get_typing_pred_for_ids(Pos,[Type|TT],[ID|IT],TypingPred) :- | |
1164 | translate_e_p(Type,TType) , | |
1165 | get_typing_pred_for_ids_acc(Pos,TT,IT,member(Pos,ID,TType),TypingPred). | |
1166 | ||
1167 | get_typing_pred_for_ids_acc(_,[],[],Acc,Acc). | |
1168 | get_typing_pred_for_ids_acc(Pos,[Type|TT],[ID|IT],Acc,TypingPred):- | |
1169 | translate_e_p(Type,TType) , | |
1170 | get_typing_pred_for_ids_acc(Pos,TT,IT,conjunct(Pos,Acc,member(Pos,ID,TType)),TypingPred). | |
1171 | ||
1172 | % translate Alloy position to B position | |
1173 | translate_pos(pos(Col,Row),Res) :- !, Res=pos(0,1,Row,Col,Row,Col). | |
1174 | translate_pos(_,none). | |
1175 | ||
1176 | get_position(Term,BPos) :- functor(Term,_,Arity), Arity>0, arg(Arity,Term,Pos), !,translate_pos(Pos,BPos). | |
1177 | get_position(_,none). | |
1178 | ||
1179 | translate_quantified_e(Pos,no,TArg,equal(Pos,TArg,empty_set(none))). | |
1180 | translate_quantified_e(Pos,one,TArg,equal(Pos,card(none,TArg),integer(none,1))). | |
1181 | translate_quantified_e(Pos,some,TArg,greater(Pos,card(none,TArg),integer(none,0))). | |
1182 | translate_quantified_e(Pos,lone,TArg,less_equal(Pos,card(none,TArg),integer(none,1))). | |
1183 | ||
1184 | % Join a list of types using cartesian_product like ((A*B)*C) for types [A,B,C]. | |
1185 | create_cartesian_type([ID],TID) :- ! , | |
1186 | translate_unary_e_p(ID,TID). | |
1187 | create_cartesian_type([ID1,ID2],cartesian_product(none,TID1,TID2)) :- ! , | |
1188 | translate_unary_e_p(ID1,TID1) , | |
1189 | translate_unary_e_p(ID2,TID2). | |
1190 | create_cartesian_type([ID1,ID2|T],cartesian_product(none,cartesian_product(none,TID1,TID2),NT)) :- | |
1191 | translate_unary_e_p(ID1,TID1) , | |
1192 | translate_unary_e_p(ID2,TID2) , | |
1193 | create_cartesian_type(T,NT). | |
1194 | ||
1195 | % Field declarations have several special cases depending on the keywords set, one, some or lone. | |
1196 | % We are inside Signature TSignatureName sig NAME { field : DeclTerm } | |
1197 | translate_field_decl(BPOS,SignatureName,TSignatureName,DeclTerm,FieldID,TFieldID,TFieldPred) :- | |
1198 | %DeclTerm =.. [_,SetID|_], | |
1199 | replace_this_in_signature_field(DeclTerm,NewDeclTerm), | |
1200 | format('Translating Field ~w inside signature ~w,~n Term=~w,~n~n',[FieldID,SignatureName,NewDeclTerm]), | |
1201 | (translate_special_multiplicity_binary_e_p(NewDeclTerm,TFUNC) | |
1202 | -> %we could do: translate_cartesian2(BPOS,TSignatureName,NewDeclTerm,Cart), TFieldPred = subset(BPOS,TFieldID,Cart), and add predicate | |
1203 | % TO DO: better treatment, also detect nested special multiplicity annotations inside NewDeclTerm | |
1204 | ||
1205 | % generate forall x:SIG => x.field : TFUNC | |
1206 | ID = identifier(BPOS,'_x_'), AID = identifier('_x_',type([SignatureName],1),none), | |
1207 | (singleton_set('_x_') -> true ; assert_singleton_set('_x_')), | |
1208 | translate_e_p(AID,TAID), % will add set-extension wrapper | |
1209 | LHS = member(BPOS,ID,TSignatureName), | |
1210 | RHS = member(BPOS,TJoin,TFUNC), | |
1211 | TFieldPred = conjunct(BPOS,FieldTyping,forall(BPOS,[ID],implication(none,LHS,RHS))), | |
1212 | translate_join_aux(BPOS,AID,FieldID,TAID,TFieldID,TJoin), | |
1213 | get_type_and_arity_from_alloy_term(FieldID,TypeList,_) , | |
1214 | create_cartesian_type(TypeList,CartesianType) , | |
1215 | FieldTyping = member(Pos,TFieldID,pow_subset(Pos,CartesianType)) | |
1216 | ; translate_sig_field_rhs(FieldID,NewDeclTerm,BPOS,TSignatureName,TFieldID,FieldTypeExpr) | |
1217 | -> add_constraint_for_someof_field(NewDeclTerm,member(BPOS,TFieldID,FieldTypeExpr),TFieldPred) | |
1218 | ; add_error(alloy2b,'Field declaration not implemented:',NewDeclTerm,BPOS), | |
1219 | TFieldPred = truth(none) | |
1220 | ). | |
1221 | ||
1222 | add_constraint_for_someof_field(someof(_,_,_),TempPred,conjunct(BPOS,not_equal(BPOS,TFieldID,empty_set(BPOS)),TempPred)) :- ! , | |
1223 | TempPred = member(BPOS,TFieldID,_). | |
1224 | add_constraint_for_someof_field(_,Pred,Pred). | |
1225 | ||
1226 | % sig SIG { field : set Set} --> field : SIG <-> Set | |
1227 | translate_sig_field_rhs(_,setof(Set,_,_),_,SIG,_,relations(none,SIG,TSet)) :- | |
1228 | translate_e_p(Set,TSet). | |
1229 | % sig SIG { field : one Set} --> field : SIG --> Set | |
1230 | translate_sig_field_rhs(_,oneof(Set,_,_),_,SIG,TFieldID,total_function(none,SIG,TSet)) :- | |
1231 | translate_e_p(Set,TSet), | |
1232 | assert_total_function(TFieldID,SIG). | |
1233 | % sig SIG { field : lone Set} --> field : SIG +-> Set | |
1234 | translate_sig_field_rhs(_,loneof(Set,_,_),_,SIG,_,partial_function(none,SIG,TSet)) :- | |
1235 | translate_e_p(Set,TSet). | |
1236 | % sig SIG { field : some Set} --> field : SIG +-> Set | |
1237 | translate_sig_field_rhs(_,someof(Set,_,_),_,SIG,_,relations(none,SIG,TSet)) :- | |
1238 | translate_e_p(Set,TSet). | |
1239 | % sig SIG { field : seq Set} --> field : (SIG * Integer) +-> Set | |
1240 | translate_sig_field_rhs(FieldID,'isseq->lone'(_,Set,_,_),_,SIG,_,partial_function(none,cartesian_product(none,SIG,integer_set(none,'INTEGER')),TSet)) :- | |
1241 | assert(is_seq(FieldID)) , | |
1242 | translate_e_p(Set,TSet). | |
1243 | % sig SIG { field : FieldTerm} --> field : POW(SIG * FieldTerm) | |
1244 | translate_sig_field_rhs(_,FieldTerm,Pos,SIG,_,pow_subset(none,Cart)) :- | |
1245 | % TO DO: check whether lone, one, ... can appear inside FieldTerm | |
1246 | translate_cartesian2(Pos,SIG,FieldTerm,Cart). | |
1247 | ||
1248 | replace_this_in_signature_field(identifier('this',type([SignatureName],1),Pos),Res) :- !, | |
1249 | Res = identifier(SignatureName,type([SignatureName],1),Pos). | |
1250 | replace_this_in_signature_field(DeclTerm,NewDeclTerm) :- | |
1251 | DeclTerm =.. [Functor,Arg1,Type,Pos], !, | |
1252 | replace_this_in_signature_field(Arg1,NArg1) , | |
1253 | NewDeclTerm =.. [Functor,NArg1,Type,Pos]. | |
1254 | replace_this_in_signature_field(DeclTerm,NewDeclTerm) :- | |
1255 | DeclTerm =.. [Functor,Arg1,Arg2,Type,Pos], !, | |
1256 | replace_this_in_signature_field(Arg1,NArg1) , | |
1257 | replace_this_in_signature_field(Arg2,NArg2) , | |
1258 | NewDeclTerm =.. [Functor,NArg1,NArg2,Type,Pos]. | |
1259 | replace_this_in_signature_field(DeclTerm,DeclTerm). | |
1260 | ||
1261 | % Translate TFieldID: Declaration | |
1262 | fun_or_pred_decl_special_cases(setof(Expr,_,_),TFieldID,Pos,subset(Pos,TFieldID,TExpr),set) :- | |
1263 | translate_e_p(Expr,TExpr). | |
1264 | fun_or_pred_decl_special_cases(oneof(Expr,_,_),TFieldID,Pos,subset(Pos,TFieldID,TExpr),singleton) :- % Default | |
1265 | translate_e_p(Expr,TExpr). | |
1266 | fun_or_pred_decl_special_cases(loneof(Expr,_,_),TFieldID,Pos,conjunct(Pos,subset(Pos,TFieldID,TExpr),ExtraPred),set) :- | |
1267 | % x : lone S -> x <: S & card(x) <= 1 | |
1268 | ExtraPred = less_equal(Pos,card(Pos,TFieldID),integer(Pos,1)), | |
1269 | translate_e_p(Expr,TExpr). | |
1270 | fun_or_pred_decl_special_cases(someof(Expr,_,_),TFieldID,Pos,conjunct(Pos,subset(Pos,TFieldID,TExpr),ExtraPred),set) :- | |
1271 | % x : some S -> x <: S & x \= {} | |
1272 | ExtraPred = not_equal(Pos,TFieldID,empty_set(Pos)), | |
1273 | translate_e_p(Expr,TExpr). | |
1274 | fun_or_pred_decl_special_cases(Expr,TFieldID,Pos,Translation,IsSingleton) :- | |
1275 | % treat identifier, cartesian, union, ... use translate of TFieldID in Expr | |
1276 | translate_binary_in(TFieldID,Expr,Pos,Translation), | |
1277 | get_type_and_arity_from_alloy_term(Expr,_Type,Arity), | |
1278 | !, | |
1279 | (Arity=1 -> IsSingleton = singleton ; IsSingleton = set). | |
1280 | fun_or_pred_decl_special_cases(Term,_,Pos,falsity(Pos),set) :- | |
1281 | add_error(alloy2b,'Field declaration for function or predicate not implemented:',Term,Pos). | |
1282 | ||
1283 | alloy_to_b_operator(Op,BOp) :- | |
1284 | alloy_to_b_unary_operator(Op,BOp) , !. | |
1285 | alloy_to_b_operator(Op,BOp) :- | |
1286 | alloy_to_b_binary_operator(Op,BOp) , !. | |
1287 | alloy_to_b_operator(Op,Op) :- format('~n~nTRANSLATING ~w to B without modification!~n',[Op]). | |
1288 | ||
1289 | alloy_to_b_unary_operator(not,negation). | |
1290 | alloy_to_b_unary_operator(closure1,closure). | |
1291 | alloy_to_b_unary_operator(closure,reflexive_closure). | |
1292 | alloy_to_b_unary_operator(inverse,reverse). % works for binary relation only; indeed Alloy says: ~ can be used only with a binary relation. | |
1293 | ||
1294 | ||
1295 | alloy_to_b_binary_operator(in,subset). | |
1296 | alloy_to_b_binary_operator(not_in,not_subset). | |
1297 | alloy_to_b_binary_operator(plus,union). | |
1298 | alloy_to_b_binary_operator(or,disjunct). % actually treated as unary operator | |
1299 | alloy_to_b_binary_operator(and,conjunct). % actually treated as unary operator | |
1300 | alloy_to_b_binary_operator(minus,set_subtraction). | |
1301 | %alloy_to_b_binary_operator(cartesian,cartesian_product). % only works for X->UNARY ! | |
1302 | alloy_to_b_binary_operator(function,expression_definition). | |
1303 | alloy_to_b_binary_operator(predicate,predicate_definition). | |
1304 | alloy_to_b_binary_operator(not_equal,not_equal). | |
1305 | alloy_to_b_binary_operator(dom_restr,domain_restriction). % not ok for ternary, set must be unary | |
1306 | alloy_to_b_binary_operator(ran_restr,range_restriction). % also ok for ternary, ... relations | |
1307 | alloy_to_b_binary_operator(equal,equal). | |
1308 | alloy_to_b_binary_operator(conjunct,conjunct). | |
1309 | alloy_to_b_binary_operator(intersection,intersection). | |
1310 | alloy_to_b_binary_operator(implication,implication). | |
1311 | alloy_to_b_binary_operator(iff,equivalence). | |
1312 | alloy_to_b_binary_operator(override,overwrite). % ++ | |
1313 | ||
1314 | is_cartesian_product_term(Term,Arg1,Arg2,POS) :- functor(Term,Functor,4), | |
1315 | is_cartesian_product(Functor), | |
1316 | arg(1,Term,Arg1), arg(2,Term,Arg2), arg(4,Term,POS). | |
1317 | is_cartesian_product(cartesian). | |
1318 | is_cartesian_product(Special) :- % translate as Cartesian product for typing predicates ONLY ! (generates unsound translations on its own, needs to be augmented with predicates which check the multiplicity !) | |
1319 | alloy_to_b_special_multiplicity_type(Special,_,_,_,POS), | |
1320 | translate_pos(POS,BPOS), | |
1321 | add_warning(alloy2b,'Treating operator as Cartesian product (cannot translate nested multiplicity in signature yet):',Special,BPOS). | |
1322 | ||
1323 | alloy_to_b_special_multiplicity_type(total_function,total_function,set,one,ok). % TO DO: requires element rather than subset, fix, see birthday.als; can only be used in context of in, !in | |
1324 | alloy_to_b_special_multiplicity_type(partial_function,partial_function,set,lone,ok). | |
1325 | alloy_to_b_special_multiplicity_type(partial_injection,partial_injection,set,lone,ok). | |
1326 | alloy_to_b_special_multiplicity_type(total_bijection,total_bijection,one,one,ok). | |
1327 | alloy_to_b_special_multiplicity_type(total_injection,total_injection,lone,one,ok). | |
1328 | alloy_to_b_special_multiplicity_type(partial_surjection,partial_surjection,some,lone,ok). | |
1329 | alloy_to_b_special_multiplicity_type(total_surjection,total_surjection,some,one,ok). | |
1330 | % relations: | |
1331 | alloy_to_b_special_multiplicity_type(total_relation,total_relation,set,some,ok). | |
1332 | alloy_to_b_special_multiplicity_type(total_surjection_relation,total_surjection_relation,some,some,ok). | |
1333 | alloy_to_b_special_multiplicity_type(surjection_relation,surjection_relation,some,set,ok). | |
1334 | alloy_to_b_special_multiplicity_type(injection_relation,injection_relation,lone,set,not_supported). % "lone->" NOT SUPPORTED BY PROB | |
1335 | alloy_to_b_special_multiplicity_type(injection_surjection_relation,injection_surjection_relation,lone,some,not_supported). % "lone->some" NOT SUPPORTED BY PROB | |
1336 | alloy_to_b_special_multiplicity_type(total_bijection_relation,total_bijection_relation,one,some,not_supported). % "one->some" NOT SUPPORTED BY PROB | |
1337 | alloy_to_b_special_multiplicity_type(total_bijection_relation,bijection_relation,one,set,not_supported). % "one->" NOT SUPPORTED BY PROB | |
1338 | ||
1339 | ||
1340 | % predicates with integer arguments | |
1341 | alloy_to_b_integer_operator(less,less). | |
1342 | alloy_to_b_integer_operator(greater,greater). | |
1343 | alloy_to_b_integer_operator(less_equal,less_equal). | |
1344 | alloy_to_b_integer_operator(greater_equal,greater_equal). | |
1345 | ||
1346 | ||
1347 | %%% | |
1348 | % Accumulate the translated machine parts and signature names during the translation and build the machine AST afterwards. | |
1349 | % We may need the signature names later on if translating a global scope. | |
1350 | build_machine_ast(b_machine(ListOfMachineParts,_SignatureNames),machine(generated(none,AbstractMachine))) :- | |
1351 | % filter empty machine parts | |
1352 | findall(MachinePart,(member(MachinePart,ListOfMachineParts) , MachinePart =.. [_,_,L], | |
1353 | L \= []),NonEmptyMachineSections) , | |
1354 | % properties need to be conjoined | |
1355 | (select(properties(none,L),NonEmptyMachineSections,RestListOfUsedMachineParts) -> true | |
1356 | ; L=[], RestListOfUsedMachineParts=NonEmptyMachineSections), | |
1357 | join_predicates(conjunct,L,FlatL) , | |
1358 | AbstractMachine = abstract_machine(none,machine(none), | |
1359 | machine_header(none,alloytranslation,[]), | |
1360 | [properties(none,FlatL)|RestListOfUsedMachineParts]) , !. | |
1361 | ||
1362 | empty_machine_acc(b_machine([sets(none,[]),constants(none,[]), | |
1363 | definitions(none,[]),properties(none,[]), | |
1364 | assertions(none,[]),operations(none,[])],[])). | |
1365 | ||
1366 | % extend a machine section with a give list of conjuncts | |
1367 | extend_machine_with_conjuncts(_Section,[],Acc,Res) :- !, Res=Acc. | |
1368 | extend_machine_with_conjuncts(Section,Conjuncts,MAcc1,MAcc2) :- | |
1369 | join_untyped_ast_nodes(conjunct,Conjuncts,TPred), | |
1370 | extend_machine_acc(Section,MAcc1,TPred,MAcc2). | |
1371 | ||
1372 | extend_machine_acc(signatures,b_machine(MachineParts,SignatureNames),New, | |
1373 | b_machine(MachineParts,NewSignatureNames)) :- ! , | |
1374 | append(SignatureNames,New,TSignatureNames) , | |
1375 | remove_dups(TSignatureNames,NewSignatureNames). | |
1376 | extend_machine_acc(Functor,b_machine(MachineParts,SignatureNames),New, | |
1377 | b_machine([NewMachinePart|RestMachineParts],SignatureNames)) :- | |
1378 | MachinePart =.. [Functor,none,List] , | |
1379 | select(MachinePart,MachineParts,RestMachineParts), % print(add_new(Functor,New)),nl,nl, | |
1380 | append(List,[New],NewList), % keeps order, but is inefficient! | |
1381 | NewMachinePart =.. [Functor,none,NewList], !. | |
1382 | extend_machine_acc(Functor,_,_,_) :- | |
1383 | add_internal_error('Failed: ',extend_machine_acc(Functor,_,_,_) ),fail. | |
1384 | ||
1385 | get_signature_names_from_machine_acc(b_machine(_MachineParts,SignatureNames),SignatureNames). | |
1386 | ||
1387 | get_command_counter_atom(CommandCounterAtom) :- | |
1388 | command_counter(CommandCounter) , | |
1389 | number_codes(CommandCounter,CommandCounterCodes) , | |
1390 | atom_codes(CommandCounterAtom,CommandCounterCodes) , | |
1391 | retractall(command_counter(_)) , | |
1392 | NewCommandCounter is CommandCounter + 1 , | |
1393 | asserta(command_counter(NewCommandCounter)). | |
1394 | ||
1395 | finalize_extending_signatures(MAcc,NewMAcc) :- | |
1396 | extending_signatures(List), ! , | |
1397 | finalize_extending_signatures_aux(MAcc,List,NewMAcc). | |
1398 | finalize_extending_signatures(MAcc,MAcc). | |
1399 | ||
1400 | finalize_extending_signatures_aux(MAcc,[],MAcc). | |
1401 | finalize_extending_signatures_aux(MAcc,[(Parent,SubSigs)|T],NewMAcc) :- | |
1402 | length(SubSigs,AmountOfSubSigs) , | |
1403 | AmountOfSubSigs > 1 , ! , | |
1404 | maplist(translate_sub_sig,SubSigs,TSubSigs) , | |
1405 | translate_e_p(Parent,TParent) , | |
1406 | extend_machine_acc(properties,MAcc,partition(none,TParent,TSubSigs),MAcc2), | |
1407 | % equivalent to | |
1408 | % parent = sub1 \/ sub2 \/ ... \/ subN & sub1 /\ sub2 = {} & ... | |
1409 | findall(OneSub,member(OneSub/one,SubSigs),OneSubSigs), | |
1410 | length(OneSubSigs,AmountOneSubSigs), | |
1411 | (AmountOneSubSigs = AmountOfSubSigs % we basically have an enumerated set with only singleton elements | |
1412 | -> extend_machine_acc(properties,MAcc2,equal(none,card(none,TParent),integer(none,AmountOneSubSigs)),MAcc3) | |
1413 | ; extend_machine_acc(properties,MAcc2,greater_equal(none,card(none,TParent),integer(none,AmountOneSubSigs)),MAcc3) | |
1414 | ), | |
1415 | finalize_extending_signatures_aux(MAcc3,T,NewMAcc). | |
1416 | finalize_extending_signatures_aux(MAcc,[_|T],NewMAcc) :- | |
1417 | finalize_extending_signatures_aux(MAcc,T,NewMAcc). | |
1418 | %%% | |
1419 | ||
1420 | translate_sub_sig(Name/_One,B) :- translate_e_p(Name,B). | |
1421 | ||
1422 | assert_extending_signature(Name,Parent,One) :- | |
1423 | (is_sub_signature_of(Name,Parent,One) -> true | |
1424 | ; format('~w is sub signature of ~w (~w)~n',[Name,Parent,One]), | |
1425 | assert(is_sub_signature_of(Name,Parent,One))), | |
1426 | extending_signatures(List), | |
1427 | select((Parent,SubSigs),List,Rest), | |
1428 | !, | |
1429 | (\+ memberchk(Name/One,SubSigs) | |
1430 | -> retractall(extending_signatures(_)) , | |
1431 | asserta(extending_signatures([(Parent,[Name/One|SubSigs])|Rest])) | |
1432 | ; true). | |
1433 | assert_extending_signature(Name,Parent,One) :- | |
1434 | retract(extending_signatures(List)), | |
1435 | !, | |
1436 | asserta(extending_signatures([(Parent,[Name/One])|List])). | |
1437 | assert_extending_signature(Name,Parent,One) :- | |
1438 | asserta(extending_signatures([(Parent,[Name/One])])). | |
1439 | ||
1440 | assert_enumerated_set(Options,Name) :- | |
1441 | % singleton top-level signatures are defined as an enumerated set like S = {_S} | |
1442 | member(one,Options) , | |
1443 | % but extending singleton signatures are defined as constants and singleton subsets of their parent type | |
1444 | \+ member(subset(_),Options) , | |
1445 | \+ member(subsig(_),Options) , ! , | |
1446 | asserta(enumerated_set(Name)). | |
1447 | assert_enumerated_set(_,_). | |
1448 | ||
1449 | assert_singleton_set(Options,Name) :- | |
1450 | member(one,Options) , ! , | |
1451 | assert_singleton_set(Name). | |
1452 | assert_singleton_set(_,_). | |
1453 | ||
1454 | assert_singleton_set(Name) :- %format('Singleton set : ~w~n',[Name]),nl, | |
1455 | %\+ singleton_set(Name), | |
1456 | asserta(singleton_set(Name)), | |
1457 | !. | |
1458 | %assert_singleton_set(_). | |
1459 | ||
1460 | retract_singleton_set(BPOS,Name) :- | |
1461 | (retract(singleton_set(Name)) -> true ; | |
1462 | add_message(retract_singleton_set,'WARNING: no singleton_set fact for: ',Name,BPOS) % can be ok for non-singleton ids | |
1463 | ). | |
1464 | % retractall(singleton_set(Name)). | |
1465 | ||
1466 | retract_state :- | |
1467 | retractall(uses_seqs) , | |
1468 | retractall(enumerated_set(_)) , | |
1469 | retractall(current_command(_)) , | |
1470 | retractall(command_counter(_)) , | |
1471 | asserta(command_counter(0)) , | |
1472 | retractall(singleton_set(_)) , | |
1473 | retractall(ordered_signature(_)) , | |
1474 | retractall(total_function(_,_)) , | |
1475 | retractall(extending_signatures(_)) , | |
1476 | retractall(is_seq(_)) , | |
1477 | retractall(maxseq(_)) , | |
1478 | retractall(is_sub_signature_of(_,_,_)) , !. | |
1479 | ||
1480 | % an identifier which in B refers not to a set but an element of a set, representing a singleton set in Alloy | |
1481 | is_singleton_set_id(this). % this is always singleton (TO DO: check this ;-) | |
1482 | is_singleton_set_id(IDName) :- singleton_set(IDName). | |
1483 | ||
1484 | assert_total_function(identifier(_,Name),SIG) :- !, | |
1485 | assert_total_function(Name,SIG). | |
1486 | assert_total_function(Name,identifier(_,SIG)) :- !, | |
1487 | assert_total_function(Name,SIG). | |
1488 | assert_total_function(Name,SIG) :- format('Total function ~w over ~w~n',[Name,SIG]), | |
1489 | asserta(total_function(Name,SIG)). | |
1490 | ||
1491 | is_total_function(predecessor(_),_). % translation of prev | |
1492 | is_total_function(successor(_),_). % translation of next | |
1493 | is_total_function(function(_,ID,_),ArgType) :- !, | |
1494 | is_total_function(ID,ArgType). | |
1495 | is_total_function(identifier(_,Name),ArgType) :- !, | |
1496 | is_total_function(Name,ArgType). | |
1497 | is_total_function(Name,[ArgType]) :- | |
1498 | total_function(Name,FunType), % TO DO: check if FunctionType is Superset of ArgType | |
1499 | (strip_singleton_set(FunType,SFunType),SFunType=identifier(_,ArgType) | |
1500 | -> true | |
1501 | ; is_sub_signature_of(ArgType,FunType,_)). | |
1502 | ||
1503 | assert_ordered_sig_name(Name) :- | |
1504 | asserta(ordered_signature(Name)). | |
1505 | ||
1506 | is_ordered_signature(IDName) :- | |
1507 | ordered_signature(IDName). | |
1508 | is_ordered_signature('ordering\''). | |
1509 | ||
1510 | is_univ(identifier('univ',_,_)). % universe | |
1511 | ||
1512 | is_unary_relation(AlloyTerm) :- | |
1513 | get_type_and_arity_from_alloy_term(AlloyTerm,_Type,Arity) , | |
1514 | Arity == 1. | |
1515 | ||
1516 | is_binary_relation(AlloyTerm) :- | |
1517 | get_type_and_arity_from_alloy_term(AlloyTerm,_Type,Arity) , | |
1518 | Arity == 2. | |
1519 | ||
1520 | can_remove_singleton_set(set_extension(_,[Element]),Element). | |
1521 | %remove_singleton_set(AST,AST). | |
1522 | ||
1523 | get_type_and_arity_from_alloy_term(integer(_,_),Type,Arity) :- !, | |
1524 | Type=integer, Arity=1. % will get translated to singleton set | |
1525 | get_type_and_arity_from_alloy_term(and(_,_),Type,Arity) :- !, | |
1526 | Type=[untyped], Arity=0. % predicate | |
1527 | get_type_and_arity_from_alloy_term(or(_,_),Type,Arity) :- !, | |
1528 | Type=[untyped], Arity=0. % predicate | |
1529 | get_type_and_arity_from_alloy_term(iden(_),Type,Arity) :- !, | |
1530 | Type=univ, Arity=2. | |
1531 | get_type_and_arity_from_alloy_term(AlloyTerm,Type,NArity) :- | |
1532 | AlloyTerm =.. [_|Args] , | |
1533 | member(type(Type,Arity),Args) , | |
1534 | (is_primitive_type(Type,NArity) ; | |
1535 | (length(Type,LType) , LType == Arity , NArity = Arity)) , | |
1536 | !. | |
1537 | get_type_and_arity_from_alloy_term(AlloyTerm,Type,Arity) :- | |
1538 | add_warning(alloy2b,'Could not extract type and arity from Alloy term:',AlloyTerm), | |
1539 | Type=[untyped], Arity=0. % like predicate | |
1540 | ||
1541 | % TO DO: maybe there are more primitive types? | |
1542 | % primitive types have arity zero in Alloy for some reason | |
1543 | is_primitive_type(['PrimitiveBoolean'],1). | |
1544 | ||
1545 | %atom_or_identifier_term(ID,ID) :- atom(ID). | |
1546 | %atom_or_identifier_term(identifier(IDName,_,_),IDName). | |
1547 | ||
1548 | join_predicates(Op,TArgList,TBinaryP) :- | |
1549 | alloy_to_b_operator(Op,BOp) , | |
1550 | (BOp = conjunct ; BOp = disjunct) , | |
1551 | join_untyped_ast_nodes(BOp,TArgList,TBinaryP). | |
1552 | ||
1553 | join_untyped_ast_nodes(_,[],truth(none)). | |
1554 | join_untyped_ast_nodes(BOp,[H|T],Conjoined) :- | |
1555 | join_untyped_ast_nodes(BOp,T,H,Conjoined). | |
1556 | ||
1557 | join_untyped_ast_nodes(_,[],Acc,Acc). | |
1558 | join_untyped_ast_nodes(BOp,[H|T],Acc,Conjoined) :- | |
1559 | NewAcc =.. [BOp,none,Acc,H], | |
1560 | join_untyped_ast_nodes(BOp,T,NewAcc,Conjoined). | |
1561 | ||
1562 | ||
1563 | :- begin_tests(full_machine_translation). | |
1564 | ||
1565 | test(cards,[]) :- | |
1566 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/cards.pl'). | |
1567 | ||
1568 | test(filesystem,[]) :- | |
1569 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/filesystem.pl'). | |
1570 | ||
1571 | test(filesystem2,[]) :- | |
1572 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/filesystem2.pl'). | |
1573 | ||
1574 | test(self_grandpas,[]) :- | |
1575 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/selfgrandpas.pl'). | |
1576 | ||
1577 | test(queens2,[]) :- | |
1578 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/queens2.pl'). | |
1579 | ||
1580 | test(river_crossing,[]) :- | |
1581 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/rivercrossingpuzzle.pl'). | |
1582 | ||
1583 | test(enum_test,[]) :- | |
1584 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/enumtest.pl'). | |
1585 | ||
1586 | test(graphiso,[]) :- | |
1587 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/graphiso.pl'). | |
1588 | ||
1589 | test(disj_field_test,[]) :- | |
1590 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/disjfieldtest.pl'). | |
1591 | ||
1592 | test(crewAlloc,[]) :- | |
1593 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/crewalloc.pl'). | |
1594 | ||
1595 | test(sudoku1,[]) :- | |
1596 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/sudoku1.pl'). | |
1597 | ||
1598 | test(sequence_test,[]) :- | |
1599 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/sequence_test.pl'). | |
1600 | ||
1601 | test(http,[]) :- | |
1602 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/http.pl'). | |
1603 | ||
1604 | test(knights,[]) :- | |
1605 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/knights_and_knaves.pl'). | |
1606 | ||
1607 | test(hanoi,[]) :- | |
1608 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/hanoi.pl'). | |
1609 | ||
1610 | test(einstein,[]) :- | |
1611 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/einstein.pl'). | |
1612 | ||
1613 | test(slot_data,[]) :- | |
1614 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/slot_data_v2.pl'). | |
1615 | ||
1616 | test(job_puzzle,[]) :- | |
1617 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/job_puzzle.pl'). | |
1618 | ||
1619 | /* | |
1620 | test(family_v1,[]) :- | |
1621 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/family-v1.pl'). | |
1622 | ||
1623 | test(hanoi,[]) :- | |
1624 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/hanoi.pl'). | |
1625 | ||
1626 | test(knights,[]) :- | |
1627 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/knights_and_knaves.pl'). | |
1628 | ||
1629 | test(directctrl,[]) :- | |
1630 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/directctrl.pl'). | |
1631 | ||
1632 | test(views,[]) :- | |
1633 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/views.pl'). | |
1634 | ||
1635 | test(mutex,[]) :- | |
1636 | load_alloy_ast_prolog_file('../../prob_examples/public_examples/Alloy/Prolog/mutex.pl'). | |
1637 | */ | |
1638 | :- end_tests(full_machine_translation). |