1 % (c) 2009-2026 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(translate,
6 [print_bexpr_or_subst/1, l_print_bexpr_or_subst/1,
7 print_bexpr/1, debug_print_bexpr/1,
8 nested_print_bexpr/1, nested_print_bexpr_up_to/2,
9 nested_print_bexpr_as_classicalb/1,
10 print_bexpr_stream/2,
11 print_components/1,
12 print_bexpr_with_limit/2, print_bexpr_with_limit_and_typing/3,
13 print_unwrapped_bexpr_with_limit/1,print_bvalue/1, l_print_bvalue/1, print_bvalue_stream/2,
14 translate_params_for_dot/2, translate_params_for_dot_nl/2,
15 print_machine/1,
16 translate_machine/3,
17 set_unicode_mode/0, unset_unicode_mode/0, unicode_mode/0,
18 unicode_translation/2, % unicode translation of a symbol/keyword
19 set_latex_mode/0, unset_latex_mode/0, latex_mode/0,
20 set_atelierb_mode/1, unset_atelierb_mode/0,
21 set_force_eventb_mode/0, unset_force_eventb_mode/0,
22 get_translation_mode/1, set_translation_mode/1, unset_translation_mode/1,
23 with_translation_mode/2,
24 get_language_mode/1, set_language_mode/1, with_language_mode/2,
25 translate_bexpression_to_unicode/2,
26 translate_bexpression/2, translate_subst_or_bexpr_in_mode/3,
27 translate_bexpression_with_limit/3, translate_bexpression_with_limit/2,
28 translate_bexpression_to_codes/2,
29 translate_bexpr_to_parseable/2,
30 translate_predicate_into_machine/3, nested_print_sequent_as_classicalb/6,
31 get_bexpression_column_template/4,
32 translate_subst_or_bexpr/2, translate_subst_or_bexpr_with_limit/3,
33 translate_substitution/2, print_subst/1,
34 convert_and_ajoin_ids/2,
35 translate_bvalue/2, translate_bvalue_to_codes/2, translate_bvalue_to_codes_with_limit/3,
36 translate_bvalue_to_parseable_classicalb/2,
37 translate_bvalue_for_dot/2,
38 translate_bvalue_with_limit/3,
39 translate_bvalue_with_type/3, translate_bvalue_with_type_and_limit/4,
40 translate_bvalue_for_expression/3, translate_bvalue_for_expression_with_limit/4,
41 translate_bvalue_with_tlatype/3,
42 translate_bvalue_kind/2,
43 nested_print_bvalue/3,
44 print_state/1,
45 translate_bstate/2, translate_bstate_limited/2, translate_bstate_limited/3,
46 print_bstate/1, print_bstate_limited/3,
47 translate_b_state_to_comma_list/3,
48 translate_context/2, print_context/1,
49 translate_any_state/2,
50 print_value_variable/1,
51 print_cspm_state/1, translate_cspm_state/2,
52 print_csp_value/1, translate_csp_value/2,
53 translate_cspm_expression/2,
54 translate_properties_with_limit/2,
55 translate_event/2,translate_events/2,
56 translate_event_with_target_id/4,
57 translate_event_with_src_and_target_id/4, translate_event_with_src_and_target_id/5,
58 get_non_det_modified_vars_in_target_id/3,
59 translate_event_with_limit/3,
60 translate_state_errors/2,translate_state_error/2,
61 translate_event_error/2,
62 translate_call_stack/2, render_call_short/2,
63 translate_prolog_constructor/2, translate_prolog_constructor_in_mode/2,
64 get_texpr_top_level_symbol/4,
65 pretty_type/2, % pretty-prints a type (pp_type, translate_type)
66 explain_state_error/3, get_state_error_span/2,
67 explain_event_trace/3,
68 explain_transition_info/2,
69 generate_typing_predicates/2, % keeps sequence typing info
70
71 print_raw_machine_terms/1,
72 print_raw_bexpr/1, l_print_raw_bexpr/1,
73 translate_raw_bexpr/2, translate_raw_bexpr_with_limit/3,
74 transform_raw/2,
75
76 print_span/1, print_span_nl/1, translate_span/2,
77 translate_span_with_filename/2,
78 get_definition_context_from_span/2,
79
80 %set_type_to_maximal_texpr/2, type_set/2, % now in typing_tools as create_type_set
81
82 translate_error_term/2, translate_error_term/3,
83 translate_prolog_exception/2,
84 portray_open_streams/0, print_open_stream_stats/0,
85
86 set_translation_constants/1, set_translation_context/1,
87 clear_translation_constants/0,
88
89 set_print_type_infos/1,
90 set_print_type_infos/2, reset_print_type_infos/1,
91 suppress_rodin_positions/1, reset_suppress_rodin_positions/1,
92 add_normal_typing_predicates/3,
93
94 install_b_portray_hook/0,remove_b_portray_hook/0,
95
96 translate_eventb_to_classicalb/3,
97 translate_eventb_direct_definition_header/3, translate_eventb_direct_definition_body/2,
98 return_csp_closure_value/2,
99 latex_to_unicode/2, get_latex_keywords/1, get_latex_keywords_with_backslash/1,
100 ascii_to_unicode/2,
101
102 translate_xtl_value/2
103
104 ]).
105
106 :- meta_predicate call_pp_with_no_limit_and_parseable(0).
107 :- meta_predicate with_translation_mode(+, 0).
108 :- meta_predicate with_language_mode(+, 0).
109
110 :- use_module(tools).
111 :- use_module(tools_lists,[is_list_simple/1]).
112 :- use_module(extrasrc(json_parser), [json_write_stream/1]).
113
114 :- use_module(module_information).
115 :- module_info(group,tools).
116 :- module_info(description,'This module is responsible for pretty-printing B and CSP, source spans, ...').
117
118 :- use_module(library(lists)).
119 :- use_module(library(codesio)).
120 :- use_module(library(terms)).
121 :- use_module(library(avl)).
122
123 :- use_module(debug).
124 :- use_module(error_manager).
125 :- use_module(self_check).
126 :- use_module(b_global_sets).
127 :- use_module(specfile,[csp_with_bz_mode/0,process_algebra_mode/0,
128 animation_minor_mode/1,set_animation_minor_mode/1,
129 remove_animation_minor_mode/0,
130 animation_mode/1,set_animation_mode/1, csp_mode/0,
131 translate_operation_name/2]).
132 :- use_module(bsyntaxtree).
133 %:- use_module('smv/smv_trans',[smv_print_initialisation/2]).
134 :- use_module(preferences,[get_preference/2, set_preference/2, eclipse_preference/2]).
135 :- use_module(bmachine_structure).
136 :- use_module(avl_tools,[check_is_non_empty_avl/1]).
137
138 :- set_prolog_flag(double_quotes, codes).
139
140 % print a list of expressions or substitutions
141 l_print_bexpr_or_subst([]).
142 l_print_bexpr_or_subst([H|T]) :-
143 print_bexpr_or_subst(H),
144 (T=[] -> true
145 ; (get_texpr_type(H,Type),is_subst_type(Type) -> write('; ') ; write(', ')),
146 l_print_bexpr_or_subst(T)
147 ).
148
149 is_subst_type(T) :- var(T),!,fail.
150 is_subst_type(subst).
151 is_subst_type(op(_,_)).
152
153 print_bexpr_or_subst(E) :- get_texpr_type(E,T),is_subst_type(T),!, print_subst(E).
154 print_bexpr_or_subst(precondition(A,B)) :- !, print_subst(precondition(A,B)).
155 print_bexpr_or_subst(any(A,B,C)) :- !, print_subst(any(A,B,C)).
156 print_bexpr_or_subst(select(A)) :- !, print_subst(select(A)). % TO DO: add more cases ?
157 print_bexpr_or_subst(E) :- print_bexpr(E).
158
159 print_unwrapped_bexpr_with_limit(Expr) :- print_unwrapped_bexpr_with_limit(Expr,200).
160 print_unwrapped_bexpr_with_limit(Expr,Limit) :-
161 translate:print_bexpr_with_limit(b(Expr,pred,[]),Limit),nl.
162 debug_print_bexpr(E) :- debug_mode(off) -> true ; print_bexpr(E).
163 print_bexpr(Expr) :- translate_bexpression(Expr,R), write(R).
164 print_bexpr_with_limit(Expr,Limit) :- translate_bexpression_with_limit(Expr,Limit,R), write(R).
165 print_bvalue(Val) :- translate_bvalue(Val,TV), write(TV).
166 print_bexpr_stream(S,Expr) :- translate_bexpression(Expr,R), write(S,R).
167 print_bvalue_stream(S,Val) :- translate_bvalue(Val,R), write(S,R).
168
169 print_bexpr_with_limit_and_typing(Expr,Limit,TypeInfos) :-
170 set_print_type_infos(TypeInfos,CHNG),
171 (get_texpr_type(Expr,pred)
172 -> find_typed_identifier_uses(Expr, TUsedIds),
173 add_typing_predicates(TUsedIds,Expr,Expr2)
174 ; Expr2=Expr),
175 call_cleanup(print_bexpr_with_limit(Expr2,Limit),
176 reset_print_type_infos(CHNG)).
177
178 print_components(C) :- print_components(C,0).
179 print_components([],Nr) :- write('Nr of components: '),write(Nr),nl.
180 print_components([component(Pred,Vars)|T],Nr) :- N1 is Nr+1,
181 write('Component: '), write(N1), write(' over '), write(Vars),nl,
182 print_bexpr(Pred),nl,
183 print_components(T,N1).
184
185 l_print_bvalue([]).
186 l_print_bvalue([H|T]) :- print_bvalue(H), write(' : '),l_print_bvalue(T).
187
188 nested_print_bexpr_as_classicalb(E) :- nested_print_bexpr_as_classicalb2(E,0).
189
190 nested_print_bexpr_as_classicalb2(E,InitialPeanoIndent) :-
191 (animation_minor_mode(X)
192 -> remove_animation_minor_mode,
193 call_cleanup(nested_print_bexpr2(E,InitialPeanoIndent), set_animation_minor_mode(X))
194 ; nested_print_bexpr2(E,InitialPeanoIndent)).
195
196
197 nested_print_bexpr_up_to(State,ExpandAvlUpTo) :-
198 temporary_set_preference(expand_avl_upto,ExpandAvlUpTo,CHNG),
199 call_cleanup(nested_print_bexpr(State),
200 reset_temporary_preference(expand_avl_upto,CHNG)).
201
202 % can also print lists of predicates and lists of lists, ...
203 nested_print_bexpr(Expr) :- nested_print_bexpr2(Expr,0).
204
205 % a version where one can specify the initial indent in peano numbering
206 nested_print_bexpr2([],_) :- !.
207 nested_print_bexpr2([H],InitialIndent) :- !,nested_print_bexpr2(H,InitialIndent).
208 nested_print_bexpr2([H|T],II) :- !,
209 nested_print_bexpr2(H,II),
210 print_indent(II), write('&'),nl,
211 nested_print_bexpr2(T,II).
212 nested_print_bexpr2(Expr,II) :- nbp(Expr,conjunct,II).
213
214 nbp(b(E,_,Info),Type,Indent) :- !,nbp2(E,Type,Info,Indent).
215 nbp(E,Type,Indent) :- format(user_error,'Missing b/3 wrapper!~n',[]),
216 nbp2(E,Type,[],Indent).
217 nbp2(E,Type,_Info,Indent) :- get_binary_connective(E,NewType,Ascii,LHS,RHS),!,
218 inc_indent(NewType,Type,Indent,NIndent),
219 print_bracket(Indent,NIndent,'('),
220 nbp(LHS,NewType,NIndent),
221 print_indent(NIndent),
222 translate_in_mode(NewType,Ascii,Symbol), write(Symbol),nl,
223 (is_associative(NewType) -> NewTypeR=NewType % no need for parentheses if same operator on right
224 ; NewTypeR=right(NewType)),
225 nbp(RHS,NewTypeR,NIndent),
226 print_bracket(Indent,NIndent,')').
227 nbp2(lazy_let_pred(TID,LHS,RHS),Type,_Info,Indent) :-
228 def_get_texpr_id(TID,ID),!,
229 NewType=lazy_let_pred(TID),
230 inc_indent(NewType,Type,Indent,NIndent),
231 print_indent(Indent), format('LET ~w = (~n',[ID]),
232 nbp(LHS,NewType,NIndent),
233 print_indent(NIndent), write(') IN ('),nl,
234 nbp(RHS,NewType,NIndent),
235 print_indent(NIndent),write(')'),nl.
236 nbp2(negation(LHS),_Type,_Info,Indent) :- !,
237 inc_indent(negation,false,Indent,NIndent),
238 print_indent(Indent),
239 translate_in_mode(negation,'not',Symbol), format('~s(~n',[Symbol]),
240 nbp(LHS,negation,NIndent),
241 print_indent(Indent), write(')'),nl.
242 nbp2(let_predicate(Ids,Exprs,Pred),_Type,_Info,Indent) :- !,
243 inc_indent(let_predicate,false,Indent,NIndent),
244 pp_expr_ids_in_mode(Ids,_LR,Codes,[]),
245 print_indent(Indent),format('#~s.( /* LET */~n',[Codes]),
246 pp_expr_let_pred_exprs(Ids,Exprs,_LimitReached,Codes2,[]),
247 print_indent(Indent), format('~s~n',[Codes2]),
248 print_indent(NIndent), write('&'),nl,
249 nbp(Pred,let_predicate,NIndent),
250 print_indent(Indent), write(')'),nl.
251 nbp2(let_expression(Ids,Exprs,Pred),_Type,_Info,Indent) :- !,
252 inc_indent(let_expression,false,Indent,NIndent),
253 pp_expr_ids_in_mode(Ids,_LR,Codes,[]),
254 print_indent(Indent),format('LET ~s BE~n',[Codes]),
255 pp_expr_let_pred_exprs(Ids,Exprs,_LimitReached,Codes2,[]),
256 print_indent(Indent), format('~s~n',[Codes2]),
257 print_indent(NIndent), write('IN'),nl,
258 nbp(Pred,let_expression,NIndent),
259 print_indent(Indent), write('END'),nl.
260 nbp2(exists(Ids,Pred),_Type,_Infos,Indent) :- !,
261 inc_indent(exists,false,Indent,NIndent),
262 pp_expr_ids_in_mode(Ids,_LR,Codes,[]),
263 print_indent(Indent),
264 %(member(allow_to_lift_exists,_Infos) -> write('/* LIFT */ ') ; true),
265 exists_symbol(ExistsSymbol,[]), format('~s~s.(~n',[ExistsSymbol,Codes]),
266 nbp(Pred,exists,NIndent),
267 print_indent(Indent), write(')'),nl.
268 nbp2(forall(Ids,LHS,RHS),_Type,_Info,Indent) :- !,
269 inc_indent(forall,false,Indent,NIndent),
270 pp_expr_ids_in_mode(Ids,_LR,Codes,[]),
271 print_indent(Indent),
272 forall_symbol(ForallSymbol,[]), format('~s~s.(~n',[ForallSymbol,Codes]),
273 nbp(LHS,forall,NIndent),
274 print_indent(NIndent),
275 translate_in_mode(implication,'=>',Symbol),write(Symbol),nl,
276 nbp(RHS,forall,NIndent),
277 print_indent(Indent), write(')'),nl.
278 nbp2(IFTE,_Type,_Info,Indent) :- is_ifte(IFTE,Test,LHS,RHS), !,
279 inc_indent(if_then_else,false,Indent,NIndent),
280 print_indent(Indent), write('IF'),nl,
281 nbp(Test,if_then_else,NIndent),
282 print_indent(Indent), write('THEN'),nl,
283 nbp(LHS,if_then_else,NIndent),
284 print_indent(Indent), write('ELSE'),nl,
285 nbp(RHS,if_then_else,NIndent),
286 print_indent(Indent), write('END'),nl.
287 nbp2(BOP,_Type,_Info,Indent) :-
288 indent_binary_pred(BOP,LHS,RHS,NewType,Ascii),
289 get_texpr_id(LHS,_Id),
290 \+ simple_expr(RHS),
291 !,
292 print_indent(Indent),print_bexpr(LHS),write(' '),
293 translate_in_mode(NewType,Ascii,Symbol), write(Symbol),nl,
294 inc_indent(NewType,false,Indent,NIndent),
295 nbp(RHS,equal,NIndent). % do we need to put parentheses around this ?
296 nbp2(value(V),_,Info,Indent) :- !,
297 print_indent(Indent), print_bexpr(b(value(V),any,Info)),nl.
298 nbp2(E,_,Info,Indent) :-
299 print_indent(Indent), print_bexpr(b(E,pred,Info)),nl.
300
301 is_ifte(if_then_else(A,B,C),A,B,C).
302 is_ifte(if_predicate(A,B,C),A,B,C).
303
304 indent_binary_pred(equal(LHS,RHS),LHS,RHS,equal,'=').
305 indent_binary_pred(member(LHS,RHS),LHS,RHS,member,':').
306 %indent_binary_pred(couple(LHS,RHS),LHS,RHS,couple,'|->'). % TODO: process parentheses above
307 %indent_binary_pred(union(LHS,RHS),LHS,RHS,union,'\\/').
308 %indent_binary_pred(concat(LHS,RHS),LHS,RHS,concat,'^').
309 % ...
310
311 % simple texpr without subarguments
312 simple_expr(BExpr) :-
313 syntaxtraversion(BExpr,Expr,_Type,_Infos,Subs,_Names),
314 Subs=[],
315 (Expr=value(V),nonvar(V), V=closure(_,_,_) -> fail % closure value probably not simple; TODO: check for interval
316 ; true).
317
318 % all left-associative
319 get_binary_connective(conjunct(LHS,RHS),conjunct,'&',LHS,RHS).
320 get_binary_connective(disjunct(LHS,RHS),disjunct,'or',LHS,RHS).
321 get_binary_connective(implication(LHS,RHS),implication,'=>',LHS,RHS).
322 get_binary_connective(equivalence(LHS,RHS),equivalence,'<=>',LHS,RHS).
323
324 inc_indent(Type,CurType,I,NewI) :- (Type=CurType -> NewI=I ; NewI=s(I)).
325 def_inc_indent(I,s(I)).
326 print_bracket(I,I,_) :- !.
327 print_bracket(I,_NewI,Bracket) :-
328 print_indent(I), write(Bracket),nl.
329
330 print_indent(s(X)):- !,
331 write(' '),
332 print_indent(X).
333 print_indent(_).
334
335 print_indent(Stream,s(X)):- !,
336 write(Stream,' '),
337 print_indent(Stream,X).
338 print_indent(_,_).
339
340
341 /* =============================================== */
342 /* Translating expressions and values into strings */
343 /* =============================================== */
344
345 translate_params_for_dot(List,TransList) :-
346 translate_params_for_dot(List,TransList,3,-3).
347 translate_params_for_dot_nl(List,TransList) :- % newline after every entry
348 translate_params_for_dot(List,TransList,1,-1).
349
350 translate_params_for_dot([],'',_,_).
351 translate_params_for_dot([H|T],Res,Lim,Nr) :-
352 translate_property_with_limit(H,100,TH),
353 (Nr>=Lim -> N1=1 % Limit reached, add newline
354 ; N1 is Nr+1),
355 translate_params_for_dot(T,TT,Lim,N1),
356 string_concatenate(TH,TT,Res1),
357 (N1=1
358 -> string_concatenate(',\n',Res1,Res)
359 ; (Nr>(-Lim) -> string_concatenate(',',Res1,Res)
360 ; Res=Res1)).
361
362
363 translate_channel_values(X,['_'|T],T) :- var(X),!.
364 translate_channel_values([],S,S) :- !.
365 translate_channel_values([tuple([])|T],S,R) :- !,
366 translate_channel_values(T,S,R).
367 translate_channel_values([in(tuple([]))|T],S,R) :- !,
368 translate_channel_values(T,S,R).
369 translate_channel_values([H|T],['.'|S],R) :- !,
370 ((nonvar(H),H=in(X))
371 -> Y=X
372 ; Y=H
373 ),
374 pp_csp_value(Y,S,S2),
375 translate_channel_values(T,S2,R).
376 translate_channel_values(tail_in(X),S,T) :-
377 (X=[] ; X=[_|_]), !, translate_channel_values(X,S,T).
378 translate_channel_values(_X,['??'|S],S).
379
380
381
382 pp_single_csp_value(V,'_') :- var(V),!.
383 pp_single_csp_value(X,'_cyclic_') :- cyclic_term(X),!.
384 pp_single_csp_value(int(X),A) :- atomic(X),!,number_chars(X,Chars),atom_chars(A,Chars).
385
386 :- assert_must_succeed((translate_cspm_expression(listExp(rangeOpen(2)),R), R == '<2..>')).
387 :- assert_must_succeed((translate_cspm_expression(listFrom(2),R), R == '<2..>')).
388 :- assert_must_succeed((translate_cspm_expression(listFromTo(2,6),R), R == '<2..6>')).
389 :- assert_must_succeed((translate_cspm_expression(setFromTo(2,6),R), R == '{2..6}')).
390 :- assert_must_succeed((translate_cspm_expression('#'(listFromTo(2,6)),R), R == '#<2..6>')).
391 :- assert_must_succeed((translate_cspm_expression(inGuard(x,setFromTo(1,5)),R), R == '?x:{1..5}')).
392 :- assert_must_succeed((translate_cspm_expression(builtin_call(int(3)),R), R == '3')).
393 :- assert_must_succeed((translate_cspm_expression(set_to_seq(setValue([int(1),int(2)])),R), R == 'seq({1,2})')).
394 :- assert_must_succeed((translate_cspm_expression(diff(setValue([int(1)]),setValue([])),R), R == 'diff({1},{})')).
395 :- assert_must_succeed((translate_cspm_expression(inter(setValue([int(1)]),setValue([])),R), R == 'inter({1},{})')).
396 :- assert_must_succeed((translate_cspm_expression(lambda([x,y],'*'(x,y)),R), R == '\\ x,y @ (x*y)')).
397 :- assert_must_succeed((translate_cspm_expression(lambda([x,y],'/'(x,y)),R), R == '\\ x,y @ (x/y)')).
398 :- assert_must_succeed((translate_cspm_expression(lambda([x,y],'%'(x,y)),R), R == '\\ x,y @ (x%y)')).
399 :- assert_must_succeed((translate_cspm_expression(rename(x,y),R), R == 'x <- y')).
400 :- assert_must_succeed((translate_cspm_expression(link(x,y),R), R == 'x <-> y')).
401 :- assert_must_succeed((translate_cspm_expression(agent_call_curry(f,[[a,b],[c]]),R), R == 'f(a,b)(c)')).
402
403 translate_cspm_expression(Expr, Text) :-
404 (pp_csp_value(Expr,Atoms,[]) -> ajoin(Atoms,Text)
405 ; write('Pretty printing expression failed: '),print(Expr),nl).
406
407 pp_csp_value(X,[A|S],S) :- pp_single_csp_value(X,A),!.
408 pp_csp_value(setValue(L),['{'|S],T) :- !,pp_csp_value_l(L,',',S,['}'|T],inf).
409 pp_csp_value(setExp(rangeEnum(L)),['{'|S],T) :- !,pp_csp_value_l(L,',',S,['}'|T],inf).
410 pp_csp_value(setExp(rangeEnum(L),Gen),['{'|S],T) :- !,
411 copy_term((L,Gen),(L2,Gen2)), numbervars((L2,Gen2),1,_),
412 pp_csp_value_l(L2,',',S,['|'|S2],inf),
413 pp_csp_value_l(Gen2,',',S2,['}'|T],inf).
414 pp_csp_value(avl_set(A),['{'|S],T) :- !, check_is_non_empty_avl(A),
415 avl_domain(A,L),pp_csp_value_l(L,',',S,['}'|T],inf).
416 pp_csp_value(setExp(rangeClosed(L,U)),['{'|S],T) :- !, pp_csp_value(L,S,['..'|S2]),pp_csp_value(U,S2,['}'|T]).
417 pp_csp_value(setExp(rangeOpen(L)),['{'|S],T) :- !, pp_csp_value(L,S,['..}'|T]).
418 % TO DO: pretty print comprehensionGuard; see prints in coz-example.csp ; test 1846
419 pp_csp_value(comprehensionGenerator(Var,Body),S,T) :- !, pp_csp_value(Var,S,['<-'|S1]),
420 pp_csp_value(Body,S1,T).
421 pp_csp_value(listExp(rangeEnum(L)),['<'|S],T) :- !,pp_csp_value_l(L,',',S,['>'|T],inf).
422 pp_csp_value(listExp(rangeClosed(L,U)),['<'|S],T) :- !, pp_csp_value(L,S,['..'|S2]),pp_csp_value(U,S2,['>'|T]).
423 pp_csp_value(listExp(rangeOpen(L)),['<'|S],T) :- !, pp_csp_value(L,S,['..>'|T]).
424 pp_csp_value(setFromTo(L,U),['{'|S],T) :- !,
425 pp_csp_value(L,S,['..'|S2]),pp_csp_value(U,S2,['}'|T]).
426 pp_csp_value(setFrom(L),['{'|S],T) :- !,
427 pp_csp_value(L,S,['..}'|T]).
428 pp_csp_value(closure(L), ['{|'|S],T) :- !,pp_csp_value_l(L,',',S,['|}'|T],inf).
429 pp_csp_value(list(L),['<'|S],T) :- !,pp_csp_value_l(L,',',S,['>'|T],inf).
430 pp_csp_value(listFromTo(L,U),['<'|S],T) :- !,
431 pp_csp_value(L,S,['..'|S2]),pp_csp_value(U,S2,['>'|T]).
432 pp_csp_value(listFrom(L),['<'|S],T) :- !,
433 pp_csp_value(L,S,['..>'|T]).
434 pp_csp_value('#'(L),['#'|S],T) :- !,pp_csp_value(L,S,T).
435 pp_csp_value('^'(X,Y),S,T) :- !,pp_csp_value(X,S,['^'|S1]), pp_csp_value(Y,S1,T).
436 pp_csp_value(linkList(L),S,T) :- !,pp_csp_value_l(L,',',S,T,inf).
437 pp_csp_value(in(X),['?'|S],T) :- !,pp_csp_value(X,S,T).
438 pp_csp_value(inGuard(X,Set),['?'|S],T) :- !,pp_csp_value(X,S,[':'|S1]),
439 pp_csp_value(Set,S1,T).
440 pp_csp_value(out(X),['!'|S],T) :- !,pp_csp_value(X,S,T).
441 pp_csp_value(alsoPat(X,_Y),S,T) :- !,pp_csp_value(X,S,T).
442 pp_csp_value(appendPat(X,_Fun),S,T) :- !,pp_csp_value(X,S,T).
443 pp_csp_value(tuple(vclosure),S,T) :- !, S=T.
444 pp_csp_value(tuple([X]),S,T) :- !,pp_csp_value_in(X,S,T).
445 pp_csp_value(tuple([X|vclosure]),S,T) :- !,pp_csp_value_in(X,S,T).
446 pp_csp_value(tuple([H|TT]),S,T) :- !,pp_csp_value_in(H,S,['.'|S1]),pp_csp_value(tuple(TT),S1,T).
447 pp_csp_value(dotTuple([]),['unit_channel'|S],S) :- ! .
448 pp_csp_value(dotTuple([H]),S,T) :- !, pp_csp_value_in(H,S,T).
449 pp_csp_value(dotTuple([H|TT]),S,T) :- !, pp_csp_value_in(H,S,['.'|S1]),
450 pp_csp_value(dotTuple(TT),S1,T).
451 pp_csp_value(tupleExp(Args),S,T) :- !,pp_csp_args(Args,S,T,'(',')').
452 pp_csp_value(na_tuple(Args),S,T) :- !,pp_csp_args(Args,S,T,'(',')').
453 pp_csp_value(record(Name,Args),['('|S],T) :- !,pp_csp_value(tuple([Name|Args]),S,[')'|T]).
454 pp_csp_value(val_of(Name,_Span),S,T) :- !, pp_csp_value(Name,S,T).
455 pp_csp_value(builtin_call(X),S,T) :- !,pp_csp_value(X,S,T).
456 pp_csp_value(seq_to_set(X),['set('|S],T) :- !,pp_csp_value(X,S,[')'|T]).
457 pp_csp_value(set_to_seq(X),['seq('|S],T) :- !,pp_csp_value(X,S,[')'|T]).
458 %pp_csp_value('\\'(B,C,S),S1,T) :- !, pp_csp_process(ehide(B,C,S),S1,T).
459 pp_csp_value(agent_call(_Span,Agent,Parameters),['('|S],T) :- !,
460 pp_csp_value(Agent,S,S1),
461 pp_csp_args(Parameters,S1,[')'|T],'(',')').
462 pp_csp_value(agent_call_curry(Agent,Parameters),S,T) :- !,
463 pp_csp_value(Agent,S,S1),
464 pp_csp_curry_args(Parameters,S1,T).
465 pp_csp_value(lambda(Parameters,Body),['\\ '|S],T) :- !,
466 pp_csp_args(Parameters,S,[' @ '|S1],'',''),
467 pp_csp_value(Body,S1,T).
468 pp_csp_value(rename(X,Y),S,T) :- !,pp_csp_value(X,S,[' <- '|S1]),
469 pp_csp_value(Y,S1,T).
470 pp_csp_value(link(X,Y),S,T) :- !,pp_csp_value(X,S,[' <-> '|S1]),
471 pp_csp_value(Y,S1,T).
472 % binary operators:
473 pp_csp_value(Expr,['('|S],T) :- bynary_numeric_operation(Expr,E1,E2,OP),!,
474 pp_csp_value(E1,S,[OP|S2]),
475 pp_csp_value(E2,S2,[')'|T]).
476 % built-in functions for sets
477 pp_csp_value(empty(A),[empty,'('|S],T) :- !, pp_csp_value(A,S,[')'|T]).
478 pp_csp_value(card(A),[card,'('|S],T) :- !, pp_csp_value(A,S,[')'|T]).
479 pp_csp_value('Set'(A),['Set','('|S],T) :- !, pp_csp_value(A,S,[')'|T]).
480 pp_csp_value('Inter'(A1),['Inter','('|S],T) :- !,pp_csp_value(A1,S,[')'|T]).
481 pp_csp_value('Union'(A1),['Union','('|S],T) :- !,pp_csp_value(A1,S,[')'|T]).
482 pp_csp_value(diff(A1,A2),[diff,'('|S],T) :- !,pp_csp_args([A1,A2],S,[')'|T],'','').
483 pp_csp_value(inter(A1,A2),[inter,'('|S],T) :- !,pp_csp_args([A1,A2],S,[')'|T],'','').
484 pp_csp_value(union(A1,A2),[union,'('|S],T) :- !,pp_csp_args([A1,A2],S,[')'|T],'','').
485 pp_csp_value(member(A1,A2),[member,'('|S],T) :- !,pp_csp_args([A1,A2],S,[')'|T],'','').
486 % built-in functions for sequences
487 pp_csp_value(null(A),[null,'('|S],T) :- !, pp_csp_value(A,S,[')'|T]).
488 pp_csp_value(length(A),[length,'('|S],T) :- !, pp_csp_value(A,S,[')'|T]).
489 pp_csp_value(head(A),[head,'('|S],T) :- !, pp_csp_value(A,S,[')'|T]).
490 pp_csp_value(tail(A),[tail,'('|S],T) :- !, pp_csp_value(A,S,[')'|T]).
491 pp_csp_value(elem(A1,A2),[elem,'('|S],T) :- !,pp_csp_args([A1,A2],S,[')'|T],'','').
492 pp_csp_value(concat(A1,A2),[concat,'('|S],T) :- !,pp_csp_args([A1,A2],S,[')'|T],'','').
493 pp_csp_value('Seq'(A),['Seq','('|S],T) :- !, pp_csp_value(A,S,[')'|T]).
494 % vclosure
495 pp_csp_value(Expr,S,T) :- is_list(Expr),!,pp_csp_value(closure(Expr),S,T).
496 % Type expressions
497 pp_csp_value(dotTupleType([H]),S,T) :- !, pp_csp_value_in(H,S,T).
498 pp_csp_value(dotTupleType([H|TT]),S,T) :- !,pp_csp_value_in(H,S,['.'|S1]), pp_csp_value(dotTupleType(TT),S1,T).
499 pp_csp_value(typeTuple(Args),S,T) :- !, pp_csp_args(Args,S,T,'(',')').
500 pp_csp_value(dataType(T),[T|S],S) :- ! .
501 pp_csp_value(boolType,['Bool'|S],S) :- ! .
502 pp_csp_value(intType,['Int'|S],S) :- ! .
503 pp_csp_value(dataTypeDef([H]),S,T) :- !, pp_csp_value(H,S,T).
504 pp_csp_value(dataTypeDef([H|TT]),S,T) :- !, pp_csp_value(H,S,['|'|S1]),
505 pp_csp_value(dataTypeDef(TT),S1,T).
506 pp_csp_value(constructor(Name),[Name|S],S) :- ! .
507 pp_csp_value(constructorC(C,Type),[C,'('|S],T) :- !, pp_csp_value(Type,S,[')'|T]).
508 % Argument of function can be process
509
510 pp_csp_value(Expr,S,T) :- pp_csp_process(Expr,S,T),!. % pp_csp_process has a catch-all !!! TO DO: look at this
511 pp_csp_value(Expr,S,T) :- csp_with_bz_mode,!,pp_value(Expr,S,T).
512 pp_csp_value(X, [A|S], S) :- % ['<< ',A,' >>'|S],S) :- % the << >> pose problems when checking against FDR
513 write_to_codes(X,Codes),atom_codes_with_limit(A,Codes).
514
515 pp_csp_value_in(H,S,T) :- nonvar(H),H=in(X),!, pp_csp_value(X,S,T).
516 pp_csp_value_in(H,S,T) :- pp_csp_value(H,S,T).
517
518 print_csp_value(Val) :- pp_csp_value(Val,Atoms,[]), ajoin(Atoms,Text),
519 write(Text).
520
521 translate_csp_value(Val,Text) :- pp_csp_value(Val,Atoms,[]), ajoin(Atoms,Text).
522
523 return_csp_closure_value(closure(S),List) :- pp_csp_value_l1(S,List).
524 return_csp_closure_value(setValue(S),List) :- pp_csp_value_l1(S,List).
525
526 pp_csp_value_l1([Expr|Rest],List) :-
527 ( nonvar(Rest),Rest=[] ->
528 pp_csp_value(Expr,T,[]),ajoin(T,Value),List=[Value]
529 ; pp_csp_value_l1(Rest,R),pp_csp_value(Expr,T,[]),ajoin(T,Value),List=[Value|R]
530 ).
531
532 pp_csp_args([],T,T,_LPar,_RPar).
533 pp_csp_args([H|TT],[LPar|S],T,LPar,RPar) :- pp_csp_value(H,S,S1), pp_csp_args2(TT,S1,T,RPar).
534 pp_csp_args2([],[RPar|T],T,RPar).
535 pp_csp_args2([H|TT],[','|S],T,RPar) :- pp_csp_value(H,S,S1), pp_csp_args2(TT,S1,T,RPar).
536
537 pp_csp_curry_args([],T,T).
538 pp_csp_curry_args([H|TT],S,T) :- is_list(H), pp_csp_args(H,S,S1,'(',')'), pp_csp_curry_args(TT,S1,T).
539
540 pp_csp_value_l(V,_Sep,['...'|S],S,N) :- (var(V) ; (N \= inf -> N<1;fail)), !.
541 pp_csp_value_l([],_Sep,S,S,_).
542 pp_csp_value_l([Expr|Rest],Sep,S,T,Nr) :-
543 ( nonvar(Rest),Rest=[] ->
544 pp_csp_value(Expr,S,T)
545 ;
546 (Nr=inf -> N1 = Nr ; N1 is Nr-1),
547 pp_csp_value(Expr,S,[Sep|S1]),pp_csp_value_l(Rest,Sep,S1,T,N1)).
548
549 :- assert_must_succeed((translate:convert_set_into_sequence([(int(1),int(5))],Seq),
550 check_eqeq(Seq,[int(5)]))).
551 :- assert_must_succeed((translate:convert_set_into_sequence([(int(2),X),(int(1),int(5))],Seq),
552 check_eq(Seq,[int(5),X]))).
553
554 convert_set_into_sequence(Set,Seq) :-
555 nonvar(Set), \+ eventb_translation_mode,
556 convert_set_into_sequence1(Set,Seq).
557 convert_set_into_sequence1(avl_set(A),Seq) :- !, check_is_non_empty_avl(A),
558 avl_size(A,Sz),size_is_in_set_limit(Sz),convert_avlset_into_sequence(A,Seq).
559 convert_set_into_sequence1([],Seq) :- !, Seq=[].
560 convert_set_into_sequence1(Set,Seq) :-
561 convert_set_into_sequence2(Set,0,_,SetElems,Seq),ground(SetElems).
562 convert_set_into_sequence2([],_Max,([],[]),_,_Seq).
563 convert_set_into_sequence2([Pair|T],Max,Last,SetElems,Seq) :-
564 nonvar(Pair),nonvar(T),Pair=(Index,H),ground(Index),
565 Index=int(Nr),
566 insert_el_into_seq(Nr,H,Seq,SetElems,L),
567 (Nr>Max -> NMax=Nr,NLast=L ; NMax=Max,NLast=Last),
568 convert_set_into_sequence2(T,NMax,NLast,SetElems,Seq).
569 insert_el_into_seq(1,H,[H|L],[set|L2],(L,L2)) :- !.
570 insert_el_into_seq(N,H,[_|T],[_|T2],Last) :- N>1, N1 is N-1, insert_el_into_seq(N1,H,T,T2,Last).
571
572 convert_avlset_into_sequence(Avl,Sequence) :-
573 \+ eventb_translation_mode,
574 convert_avlset_into_sequence2(Avl,1,Sequence).
575 convert_avlset_into_sequence2(Avl,_Index,[]) :-
576 empty_avl(Avl),!.
577 convert_avlset_into_sequence2(Avl,Index,[Head|Tail]) :-
578 avl_del_min(Avl, Min, _ ,NewAvl),
579 nonvar(Min), Min=(L,Head),
580 ground(L), L=int(Index),
581 Index2 is Index + 1,
582 convert_avlset_into_sequence2(NewAvl,Index2,Tail).
583
584 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
585 % translate new syntax tree -- work in progress
586 :- assert_must_succeed((translate_cspm_state(lambda([x,y],'|~|'(prefix(_,[],x,skip(_),_),prefix(_,[],y,skip(_),_),_)),R), R == 'CSP: \\ x,y @ (x->SKIP) |~| (y->SKIP)')).
587 :- assert_must_succeed((translate_cspm_state(agent_call_curry('F',[[a,b],[c]]),R), R == 'CSP: F(a,b)(c)')).
588 :- assert_must_succeed((translate_cspm_state(ifte(bool_not('<'(x,3)),';'(esharing([a],'/\\'('P1','P2',span),procRenaming([rename(r,s)],'Q',span),span),lParallel([link(b,c)],'R','S',span),span),'[>'(elinkParallel([link(h1,h2)],'G1','G2',span),exception([a],'H1','H2',span),span),span1,span2,span3),R), R == 'CSP: if not((x<3)) then ((P1) /\\ (P2) [|{|a|}|] Q[[r <- s]]) ; (R [{|b <-> c|}] S) else (G1 [{|h1 <-> h2|}] G2) [> (H1 [|{|a|}|> H2)')).
589 :- assert_must_succeed((translate_cspm_state(aParallel([a,b],'P',[b,c],'Q',span),R), R == 'CSP: P [{|a,b|} || {|b,c|}] Q')).
590 :- assert_must_succeed((translate_cspm_state(eaParallel([a,b],'P',[b,c],'Q',span),R), R == 'CSP: P [{|a,b|} || {|b,c|}] Q')).
591 :- assert_must_succeed((translate_cspm_state(eexception([a,b],'P','Q',span),R), R == 'CSP: P [|{|a,b|}|> Q')).
592
593 print_cspm_state(State) :- translate_cspm_state(State,T), write(T).
594
595 translate_cspm_state(State,Text) :-
596 ( pp_csp_process(State,Atoms,[]) -> true
597 ; print(pp_csp_process_failed(State)),nl,Atoms=State),
598 ajoin(['CSP: '|Atoms],Text).
599
600 pp_csp_process(skip(_Span),S,T) :- !, S=['SKIP'|T].
601 pp_csp_process(stop(_Span),S,T) :- !, S=['STOP'|T].
602 pp_csp_process('CHAOS'(_Span,Set),['CHAOS('|S],T) :- !,
603 pp_csp_value(Set,S,[')'|T]).
604 pp_csp_process(val_of(Agent,_Span),S,T) :- !,
605 pp_csp_value(Agent,S,T).
606 pp_csp_process(builtin_call(X),S,T) :- !,pp_csp_process(X,S,T).
607 pp_csp_process(agent(F,Body,_Span),S,T) :- !,
608 F =.. [Agent|Parameters],
609 pp_csp_value(Agent,S,S1),
610 pp_csp_args(Parameters,S1,[' = '|S2],'(',')'),
611 pp_csp_value(Body,S2,T).
612 pp_csp_process(agent_call(_Span,Agent,Parameters),S,T) :- !,
613 pp_csp_value(Agent,S,S1),
614 pp_csp_args(Parameters,S1,T,'(',')').
615 pp_csp_process(agent_call_curry(Agent,Parameters),S,T) :- !,
616 pp_csp_value(Agent,S,S1),
617 pp_csp_curry_args(Parameters,S1,T).
618 pp_csp_process(lambda(Parameters,Body),['\\ '|S],T) :- !,
619 pp_csp_args(Parameters,S,[' @ '|S1],'',''),
620 pp_csp_value(Body,S1,T).
621 pp_csp_process('\\'(B,C,S),S1,T) :- !, pp_csp_process(ehide(B,C,S),S1,T).
622 pp_csp_process(ehide(Body,ChList,_Span),['('|S],T) :- !,
623 pp_csp_process(Body,S,[')\\('|S1]),
624 pp_csp_value(ChList,S1,[')'|T]).
625 pp_csp_process(let(Decls,P),['let '| S],T) :- !,
626 maplist(translate_cspm_state,Decls,Texts),
627 ajoin_with_sep(Texts,' ',Text),
628 S=[Text,' within '|S1],
629 pp_csp_process(P,S1,T).
630 pp_csp_process(Expr,['('|S],T) :- binary_csp_op(Expr,X,Y,Op),!,
631 pp_csp_process(X,S,[') ',Op,' ('|S1]),
632 pp_csp_process(Y,S1,[')'|T]).
633 pp_csp_process(Expr,S,T) :- sharing_csp_op(Expr,X,Middle,Y,Op1,Op2),!,
634 pp_csp_process(X,S,[Op1|S1]),
635 pp_csp_value(Middle,S1,[Op2|S2]),
636 pp_csp_process(Y,S2,T).
637 pp_csp_process(Expr,S,T) :- asharing_csp_op(Expr,X,MiddleX,MiddleY,Y,Op1,MOp,Op2),!,
638 pp_csp_process(X,S,[Op1|S1]),
639 pp_csp_value(MiddleX,S1,[MOp|S2]),
640 pp_csp_value(MiddleY,S2,[Op2|S3]),
641 pp_csp_process(Y,S3,T).
642 pp_csp_process(Expr,S,T) :- renaming_csp_op(Expr,X,RList,Op1,Op2),!,
643 pp_csp_process(X,S,[Op1|S1]),
644 pp_csp_value_l(RList,',',S1,[Op2|T],10).
645 pp_csp_process(prefix(_SPAN1,Values,ChannelExpr,CSP,_SPAN2),S,T) :- !,
646 pp_csp_value_l([ChannelExpr|Values],'',S,['->'|S2],20),
647 pp_csp_process(CSP,S2,T).
648 pp_csp_process('&'(Test,Then),S,T) :- !,
649 pp_csp_bool_expr(Test,S,['&'|S2]),
650 pp_csp_process(Then,S2,T).
651 pp_csp_process(ifte(Test,Then,Else,_SPAN1,_SPAN2,_SPAN3),[' if '|S],T) :- !,
652 pp_csp_bool_expr(Test,S,[' then '|S2]),
653 pp_csp_process(Then,S2,[' else '|S3]),
654 pp_csp_process(Else,S3,T).
655 pp_csp_process(head(A),[head,'('|S],T) :- !, pp_csp_process(A,S,[')'|T]).
656 pp_csp_process(X,[X|T],T).
657
658 pp_csp_bool_expr(bool_not(BE),['not('|S],T) :- !, pp_csp_bool_expr(BE,S,[')'|T]).
659 pp_csp_bool_expr(BE,['('|S],T) :- binary_bool_op(BE,BE1,BE2,OP), !,
660 pp_csp_bool_expr(BE1,S,[OP|S2]),
661 pp_csp_bool_expr(BE2,S2,[')'|T]).
662 pp_csp_bool_expr(BE,[OP,'('|S],T) :- binary_pred(BE,BE1,BE2,OP), !,
663 pp_csp_value(BE1,S,[','|S2]),
664 pp_csp_value(BE2,S2,[')'|T]).
665 pp_csp_bool_expr(BE,S,T) :- pp_csp_value(BE,S,T).
666
667 bynary_numeric_operation('+'(X,Y),X,Y,'+').
668 bynary_numeric_operation('-'(X,Y),X,Y,'-').
669 bynary_numeric_operation('*'(X,Y),X,Y,'*').
670 bynary_numeric_operation('/'(X,Y),X,Y,'/').
671 bynary_numeric_operation('%'(X,Y),X,Y,'%').
672
673 binary_pred('member'(X,Y),X,Y,member).
674 binary_pred('<'(X,Y),X,Y,'<').
675 binary_pred('>'(X,Y),X,Y,'>').
676 binary_pred('>='(X,Y),X,Y,'>=').
677 binary_pred('<='(X,Y),X,Y,'=<').
678 binary_pred('elem'(X,Y),X,Y,is_elem_list).
679 binary_pred('=='(X,Y),X,Y,equal_element).
680 binary_pred('!='(X,Y),X,Y,not_equal_element).
681
682
683 binary_bool_op('<'(X,Y),X,Y,'<').
684 binary_bool_op('>'(X,Y),X,Y,'>').
685 binary_bool_op('>='(X,Y),X,Y,'>=').
686 binary_bool_op('<='(X,Y),X,Y,'=<').
687 binary_bool_op('=='(X,Y),X,Y,'==').
688 binary_bool_op('!='(X,Y),X,Y,'!=').
689 binary_bool_op(bool_and(X,Y),X,Y,'&&').
690 binary_bool_op(bool_or(X,Y),X,Y,'||').
691
692 binary_csp_op('|||'(X,Y,_Span),X,Y,'|||').
693 binary_csp_op('[]'(X,Y,_Span),X,Y,'[]').
694 binary_csp_op('|~|'(X,Y,_Span),X,Y,'|~|').
695 binary_csp_op(';'(X,Y,_Span),X,Y,';').
696 binary_csp_op('[>'(P,Q,_SrcSpan),P,Q,'[>').
697 binary_csp_op('/\\'(P,Q,_SrcSpan),P,Q,'/\\').
698
699 sharing_csp_op(esharing(CList,X,Y,_SrcSpan),X,CList,Y,' [|','|] ').
700 sharing_csp_op(sharing(CList,X,Y,_SrcSpan),X,CList,Y,' [|','|] ').
701 sharing_csp_op(lParallel(LinkList,X,Y,_Span),X,LinkList,Y,' [','] ').
702 sharing_csp_op(elinkParallel(LinkList,X,Y,_Span),X,LinkList,Y,' [','] ').
703 sharing_csp_op(exception(CList,X,Y,_SrcSpan),X,CList,Y,' [|','|> ').
704 sharing_csp_op(eexception(CList,X,Y,_SrcSpan),X,CList,Y,' [|','|> ').
705
706 asharing_csp_op(aParallel(CListX,X,CListY,Y,_SrcSpan),X,CListX,CListY,Y,' [',' || ','] ').
707 asharing_csp_op(eaParallel(CListX,X,CListY,Y,_SrcSpan),X,CListX,CListY,Y,' [',' || ','] ').
708
709 renaming_csp_op(procRenaming(RenameList,X,_SrcSpan),X,RenameList,'[[',']]').
710 renaming_csp_op(eprocRenaming(RenameList,X,_SrcSpan),X,RenameList,'[[',']]').
711
712 :- use_module(bmachine,[b_get_machine_operation_parameter_types/2, b_is_operation_name/1]).
713
714 translate_events([],[]).
715 translate_events([E|Erest],[Out|Orest]) :-
716 translate_event(E,Out),
717 translate_events(Erest,Orest).
718
719
720 % a version of translate_event which has access to the target state id:
721 % this allows to translate setup_constants, intialise by inserting target constants or values
722
723 translate_event_with_target_id(Term,Dst,Limit,Str) :-
724 translate_event_with_src_and_target_id(Term,unknown,Dst,Limit,Str).
725 translate_event_with_src_and_target_id(Term,Src,Dst,Str) :-
726 translate_event_with_src_and_target_id(Term,Src,Dst,5000,Str).
727
728 translate_event_with_src_and_target_id(Term,Src,Dst,Limit,Str) :-
729 get_preference(expand_avl_upto,CurLim),
730 SetLim is Limit//2,% at least two symbols per element
731 (CurLim<0 ; SetLim < CurLim),!,
732 temporary_set_preference(expand_avl_upto,SetLim,CHNG),
733 call_cleanup(translate_event_with_target_id2(Term,Src,Dst,Limit,Str),
734 reset_temporary_preference(expand_avl_upto,CHNG)).
735 translate_event_with_src_and_target_id(Term,Src,Dst,Limit,Str) :-
736 translate_event_with_target_id2(Term,Src,Dst,Limit,Str).
737
738 setup_cst_functor('$setup_constants',"SETUP_CONSTANTS").
739 setup_cst_functor('$partial_setup_constants',"PARTIAL_SETUP_CONSTANTS").
740
741 translate_event_with_target_id2(Term,_,Dst,Limit,Str) :-
742 functor(Term,Functor,_),
743 setup_cst_functor(Functor,UI_Name),
744 get_preference(show_initialisation_arguments,true),
745 state_space:visited_expression(Dst,concrete_constants(State)),
746 get_non_det_constant(State,NonDetState),
747 !,
748 translate_b_state_to_comma_list_codes(UI_Name,NonDetState,Limit,Codes),
749 atom_codes_with_limit(Str,Limit,Codes).
750 translate_event_with_target_id2(Term,_,Dst,Limit,Str) :-
751 functor(Term,'$initialise_machine',_),
752 get_preference(show_initialisation_arguments,true),
753 ? bmachine:b_get_operation_non_det_modifies('$initialise_machine',NDModVars),
754 state_space:visited_expression(Dst,State), get_variables(State,VarsState),
755 (NDModVars \= []
756 ->
757 include(non_det_modified_var(NDModVars),VarsState,ModVarsState) % first show non-det variables
758 % we could add a preference for whether to show the deterministicly assigned variables at all
759 %exclude(non_det_modified_var(NDModVars),VarsState,ModVarsState2),
760 %append(ModVarsState1,ModVarsState2,ModVarsState)
761 ; ModVarsState = VarsState),
762 !,
763 translate_b_state_to_comma_list_codes("INITIALISATION",ModVarsState,Limit,Codes),
764 atom_codes_with_limit(Str,Limit,Codes).
765 translate_event_with_target_id2(Term,Src,Dst,Limit,Str) :-
766 atomic(Term), % only applied to operations without parameters
767 ? specfile:b_mode,
768 get_non_det_modified_vars_in_target_id(Term,Dst,ModVarsState0), % only show non-det variables
769 (Src \= unknown,
770 state_space:visited_expression(Src,SrcState), get_variables(SrcState,PriorVarsState)
771 -> exclude(var_not_really_modified(PriorVarsState),ModVarsState0,ModVarsState)
772 % we could also optionally filter out vars which have the same value for all outgoing transitions of Src
773 ; ModVarsState = ModVarsState0
774 ),
775 !,
776 atom_codes(Term,TermCodes),
777 translate_b_state_to_comma_list_codes(TermCodes,ModVarsState,Limit,Codes),
778 atom_codes_with_limit(Str,Limit,Codes).
779 translate_event_with_target_id2(Term,_,_,Limit,Str) :- translate_event_with_limit(Term,Limit,Str).
780
781
782 get_non_det_modified_vars_in_target_id(OpName,DstId,ModVarsState0) :-
783 bmachine:b_get_operation_non_det_modifies(OpName,NDModVars),
784 NDModVars \= [], % a variable is non-deterministically written
785 state_space:visited_expression(DstId,State), % TO DO: unpack only NModVars
786 get_variables(State,VarsState),
787 include(non_det_modified_var(NDModVars),VarsState,ModVarsState0).
788
789 :- use_module(library(ordsets)).
790 non_det_modified_var(NDModVars,bind(Var,_)) :- ord_member(Var,NDModVars).
791
792 var_not_really_modified(PriorState,bind(Var,Val)) :-
793 ? (member(bind(Var,PVal),PriorState) -> PVal=Val).
794
795 get_variables(const_and_vars(_,VarsState),S) :- !, S=VarsState.
796 get_variables(S,S).
797
798 :- dynamic non_det_constants/2.
799
800 % compute which constants are non-deterministically assigned and which ones not
801 % TODO: maybe move to state space and invalidate info in case execute operation by predicate used
802 get_non_det_constant(Template,Result) :- non_det_constants(A,B),!, (A,B)=(Template,Result).
803 get_non_det_constant(Template,Result) :-
804 ? state_space:transition(root,_,DstID),
805 state_space:visited_expression(DstID,concrete_constants(State)), %write(get_non_det_constant(DstID)),nl,
806 !,
807 findall(D,(state_space:transition(root,_,D),D \= DstID),OtherDst),
808 compute_non_det_constants2(OtherDst,State),
809 non_det_constants(Template,Result).
810 get_non_det_constant(A,A).
811
812 compute_non_det_constants2([],State) :- adapt_state(State,Template,Result),
813 (Result = [] -> assertz(non_det_constants(A,A)) % in case all variables are deterministic: just show them
814 ; assertz(non_det_constants(Template,Result))).
815 compute_non_det_constants2([Dst|T],State) :-
816 state_space:visited_expression(Dst,concrete_constants(State2)),
817 lub_state(State,State2,NewState),
818 compute_non_det_constants2(T,NewState).
819
820 lub_state([],[],[]).
821 lub_state([bind(V,H1)|T1],[bind(V,H2)|T2],[bind(V,H3)|T3]) :-
822 (H1==H2 -> H3=H1 ; H3='$NONDET'), lub_state(T1,T2,T3).
823
824 adapt_state([],[],[]).
825 adapt_state([bind(ID,Val)|T],[bind(ID,X)|TX],[bind(ID,X)|TY]) :- Val='$NONDET',!,
826 adapt_state(T,TX,TY).
827 adapt_state([bind(ID,_)|T],[bind(ID,_)|TX],TY) :- % Value is deterministic: do not copy
828 adapt_state(T,TX,TY).
829
830
831
832 % ------------------------------------
833
834 translate_event_with_limit(Event,Limit,Out) :-
835 translate_event2(Event,Atoms,[]),!,
836 ajoin_with_limit(Atoms,Limit,Out).
837 %,write(done),debug:print_debug_stats,nl.% , write(Out),nl.
838 translate_event_with_limit(Event,_,Out) :- add_error(translate_event_with_limit,'Could not translate event: ', Event),
839 Out = '???'.
840
841 translate_event(Event,Out) :- %write(translate),print_debug_stats,nl,
842 translate_event2(Event,Atoms,[]),!,
843 ajoin(Atoms,Out).
844 %,write(done),debug:print_debug_stats,nl.% , write(Out),nl.
845 translate_event(Event,Out) :-
846 add_error(translate_event,'Could not translate event: ', Event),
847 Out = '???'.
848
849 /* BEGIN CSP */
850 translate_event2(start_cspm(Process),['start_cspm('|S],T) :- process_algebra_mode,!,pp_csp_value(Process,S,[')'|T]).
851 %% translate_event2(i(_Span),['i'|T],T) :- process_algebra_mode,!. /* CSP */ %% deprecated
852 translate_event2(tick(_Span),['tick'|T],T) :- process_algebra_mode,!. /* CSP */
853 translate_event2(tau(hide(Action)),['tau(hide('|S],T) :- process_algebra_mode,nonvar(Action), !,
854 translate_event2(Action,S,['))'|T]). /* CSP */
855 translate_event2(tau(link(Action1,Action2)),['tau(link('|S],T) :- /* CSP */
856 nonvar(Action1), nonvar(Action2), process_algebra_mode, !,
857 translate_event2(Action1,S,['<->'|S1]),
858 translate_event2(Action2,S1,['))'|T]).
859 translate_event2(tau(Info),['tau(',Fun,')'|T],T) :-
860 nonvar(Info), process_algebra_mode,!, /* CSP */
861 translate_csp_tau(Info,Fun).
862 translate_event2(io(V,Ch,_Span),S,T) :- process_algebra_mode,!, /* CSP */
863 (csp_with_bz_mode ->
864 S=['CSP:'|S1],
865 translate_event2(io(V,Ch),S1,T)
866 ;
867 translate_event2(io(V,Ch),S,T)
868 ).
869 translate_event2(io(X,Channel),S,T) :- process_algebra_mode,!, /* CSP */
870 (X=[] -> translate_event2(Channel,S,T)
871 ; (translate_event2(Channel,S,S1),
872 translate_channel_values(X,S1,T))
873 ).
874 /* END CSP */
875 translate_event2(Op,[A|T],T) :-
876 % this clause must be after the CSP code, test 756 sets process_algebra_mode via prob_pragma_string
877 % this allows xtl interpreters to use tau,tick,io events
878 animation_mode(xtl),
879 !,
880 translate_xtl_value(Op,A). /* XTL transitions can be arbitrary terms */
881 translate_event2('$JUMP'(Name),[A|T],T) :- write_to_codes(Name,Codes),
882 atom_codes_with_limit(A,Codes).
883 translate_event2('-->'(Operation,ResultValues),S,T) :- nonvar(ResultValues),
884 ResultValues=[_|_],!,
885 translate_event2(Operation,S,['-->',ValuesStr|T]),
886 translate_bvalues(ResultValues,ValuesStr).
887 translate_event2(Op,S,T) :-
888 nonvar(Op), Op =.. [OpName|Args],
889 translate_b_operation_call(OpName,Args,S,T),!.
890 translate_event2(Op,[A|T],T) :-
891 %['<< ',A,' >>'|T],T) :- % the << >> pose problems when checking against FDR
892 write_to_codes(Op,Codes),
893 atom_codes_with_limit(A,Codes).
894
895 translate_csp_tau('$setup_constants',T) :- csp_with_bz_mode,!, T='SETUP_CONSTANTS'.
896 translate_csp_tau('$initialise_machine',T) :- csp_with_bz_mode, !, T='INITIALISATION'.
897 translate_csp_tau(TauTerm,Fun) :- functor(TauTerm,Fun,_).
898 %(translate_event(TauTerm,Fun) -> true ; functor(TauTerm,Fun,_)).
899
900
901 % translate a B operation call to list of atoms in dcg style
902 translate_b_operation_call(OpName,Args,[TOpName|S],T) :-
903 translate_operation_name(OpName,TOpName),
904 ( Args=[] -> S=T
905 ;
906 S=['(',ValuesStr,')'|T],
907 ( get_preference(show_eventb_any_arguments,false), % otherwise we have additional ANY parameters !
908 \+ is_init(OpName), % order of variables does not always correspond to Variable order used by b_get_machine_operation_parameter_types ! TO DO - Fix this in b_initialise_machine2 (see Interlocking.mch CSP||B model)
909 ? specfile:b_mode,
910 b_is_operation_name(OpName),
911 ? b_get_machine_operation_parameter_types(OpName,ParTypes),
912 ParTypes \= []
913 -> translate_bvalues_with_types(Args,ParTypes,ValuesStr)
914 %; is_init(OpName) -> b_get_machine_operation_typed_parameters(OpName,TypedParas),
915 ; translate_bvalues(Args,ValuesStr))
916 ).
917
918 % -----------------
919
920 % translate call stacks as stored in wait flag info fields
921 % (managed by push_wait_flag_call_stack_info)
922
923 translate_call_stack(Stack,Msg) :-
924 Opts = [detailed],
925 split_calls(Stack,DStack),
926 get_cs_avl_limit(ALimit),
927 temporary_set_preference(expand_avl_upto,ALimit,CHNG),
928 set_unicode_mode,
929 ? call_cleanup(render_call_stack(DStack,1,Opts,A,[]),
930 (unset_unicode_mode,
931 reset_temporary_preference(expand_avl_upto,CHNG))),
932 ajoin(['call stack: '|A],Msg).
933 render_call_stack([],_,_) --> [].
934 render_call_stack([H],Nr,Opts) --> !,
935 render_nr(Nr,H,_,Opts), render_call(H,Opts).
936 render_call_stack([H|T],Nr,Opts) -->
937 render_nr(Nr,H,Nr1,Opts),
938 ? render_call(H,Opts),
939 render_seperator(Opts),
940 render_call_stack(T,Nr1,Opts).
941
942 % render nr of call in call stack
943 render_nr(Pos,H,Pos1,Opts) --> {member(detailed,Opts)},!, ['\n '], render_pos_nr(Pos,H,Pos1).
944 render_nr(Pos,_,Pos,_) --> [].
945
946 render_pos_nr(Pos,definition_call(_,_),Pos) --> !,
947 [' ']. % definition calls are virtual and can appear multiple times for different entries in the call stack
948 % see e.g., public_examples/B/FeatureChecks/DEFINITIONS/DefCallStackDisplay2.mch
949 render_pos_nr(Pos,_,Pos1) --> [Pos] , {Pos1 is Pos+1}, [': '].
950
951 render_seperator(Opts) --> {member(detailed,Opts)},!. % we put newlines in render_nr
952 render_seperator(_Opts) -->
953 {call_stack_arrow_atom_symbol(Symbol)}, [Symbol].
954
955 render_call(definition_call(Name,Pos),Opts) --> !,
956 ['within DEFINITION call '],[Name],
957 render_span(Pos,Opts).
958 render_call(operation_call(Op,Paras,Pos),Opts) --> !,
959 translate_b_operation_call(Op,Paras), % TODO: limit size?
960 render_span(Pos,Opts).
961 render_call(using_state(Name,State),_Opts) --> !,
962 [Name], [' with state: '],
963 {get_cs_limit(Limit),translate_bstate_limited(State,Limit,Str)},
964 [Str].
965 render_call(after_event(OpTerm),_Opts) --> !,
966 ['after event: '],
967 {get_cs_limit(Limit),translate_event_with_limit(OpTerm,Limit,Str)},
968 [Str].
969 render_call(function_call(Fun,Paras,Pos),Opts) --> !,
970 render_function_call(Fun,Paras),
971 render_span(Pos,Opts).
972 render_call(b_operator_call(OP,Paras,Pos),Opts) --> !,
973 render_operator_arg(b_operator(OP,Paras)),
974 render_span(Pos,Opts).
975 render_call(id_equality_evaluation(ID,Kind,Pos),Opts) --> !,
976 ['equality for '],[Kind],[' '],[ID],
977 render_span(Pos,Opts).
978 render_call(b_operator_arg_evaluation(OP,PosNr,Args,Pos),Opts) --> !,
979 ['arg '],[PosNr],[' of '],
980 render_operator_arg(b_operator(OP,Args)),
981 render_span(Pos,Opts).
982 render_call(external_call(Name,Paras,Pos),Opts) --> !,
983 ['external call '], [Name],['('],
984 {get_cs_limit(Limit),translate_bvalues_with_limit(Paras,Limit,PS)},[PS], [')'],
985 render_span(Pos,Opts).
986 render_call(prob_command_context(Name,Pos),Opts) --> !,
987 ['checking '], render_prob_command(Name),
988 render_span(Pos,Opts).
989 render_call(quantifier_call(comprehension_set,ParaNames,ParaValues,Pos),Opts) --> % special case for lambda
990 {nth1(LPos,ParaNames,LambdaRes,RestParaNames),
991 is_lambda_result_name(LambdaRes,_),
992 nth1(LPos,ParaValues,LambdaVal,RestParaValues)},!, % we have found '_lambda_res_' amongst paras
993 render_quantifier(lambda), ['('],
994 render_paras(RestParaNames,RestParaValues),
995 ['|'], render_para_val(LambdaVal),
996 [')'],
997 render_span(Pos,Opts).
998 render_call(quantifier_call(Kind,ParaNames,ParaValues,Pos),Opts) --> !,
999 render_quantifier(Kind), ['('],
1000 render_paras(ParaNames,ParaValues), [')'],
1001 render_span(Pos,Opts).
1002 render_call(top_level_call(SpanPred),Opts) -->
1003 render_call(SpanPred,Opts).
1004 render_call(b_expr_call(Context,Expr),Opts) --> !,
1005 [Context],[': '],
1006 render_b_expr(Expr),
1007 render_span(Expr,Opts).
1008 render_call(b_subst_call(Context,Subst),Opts) --> !,
1009 [Context],[': '],
1010 render_b_subst(Subst),
1011 render_span(Subst,Opts).
1012 render_call(span_predicate(Pred,LS,S),Opts) --> % Pred can also be an expression like function/2
1013 % infos could contain was(extended_expr(Op)); special case for: assertion_expression
1014 {Pred=b(_,_,Pos),
1015 b_compiler:b_compile(Pred,[],LS,S,CPred,no_wf_available) % inline actual parameters
1016 },
1017 !,
1018 render_b_expr(CPred),
1019 render_function_name(Pred), % try show function name from uncompiled Expr
1020 render_span(Pos,Opts).
1021 render_call(Other,_) --> [Other].
1022
1023 % get a brief description of call in call_stack
1024 render_call_short(after_event(OpTerm,_),R) :- !,R=OpTerm.
1025 render_call_short(using_state(Name,_),R) :- !,R=Name.
1026 render_call_short(definition_call(Name,_,_),R) :- !,R=Name.
1027 render_call_short(operation_call(Name,_,_),R) :- !,R=Name.
1028 render_call_short(function_call(Name,_,_),R) :- !,R=Name.
1029 render_call_short(b_operator_call(Name,_,_),R) :- !,R=Name.
1030 render_call_short(b_operator_arg_evaluation(Name,_,_,_),R) :- !,R=Name.
1031 render_call_short(external_call(Name,_,_),R) :- !,R=Name.
1032 render_call_short(prob_command_context(Name,_),R) :- !,R=Name.
1033 render_call_short(quantifier_call(Kind,_,_,_),R) :- !, R=Kind.
1034 render_call_short(top_level_call(_),R) :- !, R=top_level.
1035 render_call_short(E,F) :- functor(E,F,_).
1036
1037
1038 %render_operator(OP) -->
1039 % {(unicode_translation(OP,Unicode) -> FOP=Unicode ; FOP=OP)}, [FOP].
1040
1041 % render b operator arguments/calls:
1042 render_operator_arg(Var) --> {var(Var)},!,['_VARIABLE_']. % should not happen
1043 render_operator_arg(b_operator(OP,[Arg1,Arg2])) -->
1044 {binary_infix_in_mode(OP,Symbol,_,_)},!,
1045 {(unicode_translation(OP,Unicode) -> FOP=Unicode ; FOP=Symbol)}, %TODO: add parentheses if necessary
1046 render_operator_arg(Arg1),
1047 [' '],[FOP], [' '],
1048 render_operator_arg(Arg2).
1049 render_operator_arg(b_operator(OP,Args)) --> !,
1050 {(unicode_translation(OP,Unicode) -> FOP=Unicode ; function_like(OP,FOP) -> true ; FOP=OP)},
1051 [FOP], ['('],
1052 render_operator_args(Args),
1053 [')'].
1054 render_operator_arg(bind(Name,Value)) --> !,
1055 [Name], ['='],
1056 render_operator_arg(Value).
1057 render_operator_arg(identifier(ID)) --> !, [ID].
1058 render_operator_arg(Val) --> render_para_val(Val).
1059
1060 render_operator_args([]) --> !, [].
1061 render_operator_args([H]) --> !, render_operator_arg(H).
1062 render_operator_args([H|T]) --> !, render_operator_arg(H), [','], render_operator_args(T).
1063 render_operator_args(A) --> {add_internal_error('Not a list: ',A)}, ['???'].
1064
1065 render_prob_command(check_pred_command(PredKind,Arg)) --> !, ['predicate '], render_pred_nr(Arg), ['of '],[PredKind].
1066 render_prob_command(eval_expr_command(Kind,Arg)) --> !, ['expression '], render_pred_nr(Arg), ['of '],[Kind].
1067 render_prob_command(trace_replay(OpName,FromId)) --> !, ['Trace replay predicate for '],[OpName], [' from '],[FromId].
1068 render_prob_command(Cmd) --> [Cmd].
1069
1070 render_pred_nr(0) --> !. % 0 is special value to indicate we have no number/id within outer kind
1071 render_pred_nr(Nr) --> {number(Nr)},!,['# '],[Nr],[' '].
1072 render_pred_nr('') --> !.
1073 render_pred_nr(AtomId) --> ['for '], [AtomId],[' '].
1074
1075 ?render_function_name(b(function(Fun,_),_,_)) --> {try_get_identifier(Fun,FID)},!,
1076 % TODO: other means of extracting name; maybe we should render anything that is not a value?
1077 ['\n (Function applied: '], [FID], [')'].
1078 render_function_name(b(_,_,Infos)) --> {member(was(extended_expr(OpID)),Infos)},!,
1079 ['\n (Theory operator applied: '], [OpID], [')'].
1080 render_function_name(_) --> [].
1081
1082 ?try_get_identifier(Expr,Id) :- (get_texpr_id(Expr,Id) -> true ; get_was_identifier(Expr,Id)).
1083
1084 render_span(Span,Opts) --> {member(detailed,Opts),translate_span(Span,Atom), Atom \= ''},!,
1085 ['\n '], [Atom],
1086 ({member(additional_descr,Opts),translate_additional_description(Span,Descr)}
1087 -> [' within ',Descr]
1088 ; []).
1089 render_span(_,_) --> [].
1090
1091 render_function_call(Fun,Paras) -->
1092 {(atomic(Fun) -> FS=Fun ; translate_bexpr_for_call_stack(Fun,FS))}, % memoization will only register atomic name
1093 [FS],['('], render_para_val(Paras), [')'].
1094
1095 render_b_expr(b(function(Fun,Paras),_,_)) --> !, % ensure we print both function and paras at least partially
1096 {translate_bexpr_for_call_stack(Fun,FS)}, [FS],['('],
1097 {translate_bexpr_for_call_stack(Paras,PS)},[PS], [')'].
1098 render_b_expr(b(assertion_expression(Pred,Msg,b(value(_),string,_)),_,_)) --> !,
1099 % Body is not source of error; probably better to use special call stack entry for assertion_expression
1100 ['ASSERT '],[Msg],['\n '],
1101 {translate_bexpr_for_call_stack(Pred,PS)}, [PS].
1102 render_b_expr(CPred) --> {translate_bexpr_for_call_stack(CPred,PS)}, [PS].
1103
1104 translate_bexpr_for_call_stack(Expr,TS) :-
1105 get_cs_limit(Limit),
1106 translate_bexpr_with_limit_tl(Expr,Limit,TS).
1107
1108 render_b_subst(CPred) --> % TODO: try and fit this on a single line ?
1109 {get_cs_limit(Limit),translate_subst_or_bexpr_with_limit(CPred,Limit,PS)}, [PS].
1110
1111 % a variation to ensure that top-level operator is guaranteed to be shown
1112 % does not yet guarantee propert parentheses around arguments !
1113 % useful for showing call stack so that we at least see the operator and part of both args
1114 translate_bexpr_with_limit_tl(b(Special,pred,_),Limit,TS) :-
1115 special_binary_op(Special,LHS,RHS,Op),
1116 binary_infix_in_mode(Op,Trans,_Prio,_Assoc),
1117 !, Lim2 is (Limit+1)//2,
1118 translate_bexpression_with_limit(LHS,Lim2,TS1),
1119 translate_bexpression_with_limit(RHS,Lim2,TS2),
1120 ajoin([TS1,' ',Trans,' ',TS2],TS).
1121 translate_bexpr_with_limit_tl(Expr,Limit,TS) :-
1122 translate_bexpression_with_limit(Expr,Limit,TS).
1123
1124 special_binary_op(member(LHS,RHS),LHS,RHS,member).
1125 special_binary_op(not_member(LHS,RHS),LHS,RHS,not_member).
1126 special_binary_op(equal(LHS,RHS),LHS,RHS,equal).
1127 special_binary_op(not_equal(LHS,RHS),LHS,RHS,not_equal).
1128 special_binary_op(subset(LHS,RHS),LHS,RHS,subset).
1129 special_binary_op(subset_strict(LHS,RHS),LHS,RHS,subset_strict).
1130
1131 get_cs_limit(2000) :- !.
1132 get_cs_limit(Limit) :- debug_mode(on),!, debug_level(Level), % 19 regular, 5 very verbose
1133 Limit is 1000 - Level*20.
1134 get_cs_limit(200) :- get_preference(provide_trace_information,true),!.
1135 get_cs_limit(100).
1136
1137 get_cs_avl_limit(40) :- debug_mode(on),!.
1138 get_cs_avl_limit(6) :- get_preference(provide_trace_information,true),!.
1139 get_cs_avl_limit(4).
1140
1141 get_call_stack_span(operation_call(_,_,Pos),Pos).
1142 %get_call_stack_span(after_event(_),unknown).
1143 get_call_stack_span(function_call(_,_,Pos),Pos).
1144 get_call_stack_span(id_equality_evaluation(_ID,_Kind,Pos),Pos).
1145 get_call_stack_span(quantifier_call(_,_,_,Pos),Pos).
1146 get_call_stack_span(definition_call(_,Pos),Pos).
1147 get_call_stack_span(external_call(_,_,Pos),Pos).
1148 get_call_stack_span(prob_command_context(_,Pos),Pos).
1149 get_call_stack_span(top_level_call(Pos),Pos).
1150 get_call_stack_span(b_operator_call(_,_,Pos),Pos).
1151 get_call_stack_span(b_operator_arg_evaluation(_,_,_,Pos),Pos).
1152 get_call_stack_span(b_expr_call(_,Expr),Expr).
1153 get_call_stack_span(b_subst_call(_,Expr),Expr).
1154 get_call_stack_span(span_predicate(A,B,C),span_predicate(A,B,C)).
1155
1156 nop_call(top_level_call(X)) :- \+ is_top_level_function_call(X).
1157 % just there to insert virtual DEFINITION calls at top-level of call-stack
1158 is_top_level_function_call(span_predicate(b(Expr,_,_),_,_)) :-
1159 Expr = function(_,_),
1160 get_preference(provide_trace_information,false).
1161 % otherwise we push function_calls onto the stack; see opt_push_wait_flag_call_stack_info
1162
1163 % expand the call stack by creating entries for the definition calls
1164 split_calls([],[]).
1165 split_calls([Call|T],NewCalls) :- nop_call(Call),!, %write(nop(Call)),nl,
1166 split_calls(T,NewCalls).
1167 split_calls([Call|T],NewCalls) :-
1168 get_call_stack_span(Call,Span),!,
1169 NewCalls = [Call|New2],
1170 extract_def_calls(Span,New2,ST),
1171 split_calls(T,ST).
1172 split_calls([Call|T],[Call|ST]) :-
1173 split_calls(T,ST).
1174
1175 extract_def_calls(Span) -->
1176 {extract_pos_context(Span,MainPos,Context,CtxtPos)},
1177 {Context = definition_call(Name)},
1178 !,
1179 extract_def_calls(MainPos),
1180 [definition_call(Name,CtxtPos)],
1181 extract_def_calls(CtxtPos). % do we need this??
1182 extract_def_calls(_) --> [].
1183
1184 % a shorter version of extract_additional_description only accepting definition_calls
1185 translate_additional_description(Span,Desc) :-
1186 extract_pos_context(Span,MainPos,Context,CtxtPos),
1187 translate_span(CtxtPos,CtxtAtom),
1188 extract_def_context_msg(Context,OuterCMsg),
1189 (translate_additional_description(MainPos,InnerCMsg)
1190 -> ajoin([InnerCMsg,' within ',OuterCMsg, ' ', CtxtAtom],Desc)
1191 ; ajoin([OuterCMsg, ' ', CtxtAtom],Desc)
1192 ).
1193
1194 % try and get an immediate definition call context for a position
1195 get_definition_context_from_span(Span,DefCtxtMsg) :-
1196 extract_pos_context(Span,_MainPos,Context,_CtxtPos),
1197 extract_def_context_msg(Context,DefCtxtMsg).
1198
1199 extract_def_context_msg(definition_call(Name),Msg) :- !, % static Definition macro expansion call stack
1200 ajoin(['DEFINITION call of ',Name],Msg).
1201
1202 render_paras([],[]) --> !, [].
1203 render_paras([],_Vals) --> ['...?...']. % should not happen
1204 render_paras([Name],[Val]) --> !, render_para_name(Name), ['='], render_para_val(Val).
1205 render_paras([Name|TN],[Val|TV]) --> !,
1206 render_para_name(Name), ['='], render_para_val(Val), [','],
1207 render_paras(TN,TV).
1208 render_paras([N|Names],[]) --> !, render_para_name(N), render_paras(Names,[]). % value list can be empty
1209
1210 render_para_val(E) --> {nonvar(E),E=b(_,_,_)}, !, % only used in special cases; e.g., image_for_special_operator
1211 {get_cs_limit(Limit),translate_bexpression_with_limit(E,Limit,VS)}, [VS].
1212 render_para_val(Val) --> {get_cs_limit(Limit),translate_bvalue_with_limit(Val,Limit,VS)}, [VS].
1213
1214 % accept typed and atomic ids
1215 render_para_name(b(identifier(ID),_,_)) --> !, {translated_identifier(ID,TID)},[TID].
1216 render_para_name(ID) --> {translated_identifier(ID,TID)},[TID].
1217
1218 render_quantifier(lambda) --> !, {unicode_translation(lambda,Symbol)},[Symbol]. % ['{|}'].
1219 render_quantifier(comprehension_set) --> !, ['{|}'].
1220 render_quantifier(comprehension_set(NegationContext)) --> !,
1221 render_negation_context(NegationContext), [' {|}'].
1222 render_quantifier(exists) --> !, {unicode_translation(exists,Symbol)},[Symbol].
1223 render_quantifier(let_quantifier) --> !, ['LET'].
1224 render_quantifier(optimize) --> !, ['#optimize'].
1225 render_quantifier(forall) --> !, {unicode_translation(forall,Symbol)},[Symbol].
1226 render_quantifier(not(Q)) --> !, {unicode_translation(negation,Symbol)}, % not(exists)
1227 [Symbol, '('], render_quantifier(Q), [')'].
1228 render_quantifier(Q) --> !, [Q].
1229
1230 render_negation_context(positive) --> !, ['one solution'].
1231 render_negation_context(negative) --> !, ['no solution'].
1232 render_negation_context(all_solutions) --> !,['all solutions'].
1233 render_negation_context(C) --> [C].
1234
1235 call_stack_arrow_atom_symbol(' \x2192\ '). % see total function
1236 %call_stack_arrow_atom_symbol('\x27FF\ '). % long rightwards squiggle arrow
1237
1238 % -----------------
1239
1240
1241 is_init('$initialise_machine').
1242 is_init('$setup_constants').
1243 is_init('$partial_setup_constants').
1244
1245 translate_bvalues_with_types(Values,Types,Output) :-
1246 %set_up_limit_reached(Codes,1000,LimitReached),
1247 pp_value_l_with_types(Values,',',Types,_LimitReached,Codes,[]),!,
1248 atom_codes_with_limit(Output,Codes).
1249 translate_bvalues_with_types(Values,T,Output) :-
1250 add_internal_error('Call failed: ',translate_bvalues_with_types(Values,T,Output)),
1251 translate_bvalues(Values,Output).
1252
1253 pp_value_l_with_types([],_Sep,[],_) --> !.
1254 pp_value_l_with_types([Expr|Rest],Sep,[TE|TT],LimitReached) -->
1255 ( {nonvar(Rest),Rest=[]} ->
1256 pp_value_with_type(Expr,TE,LimitReached)
1257 ;
1258 pp_value_with_type(Expr,TE,LimitReached),ppatom(Sep),
1259 pp_value_l_with_types(Rest,Sep,TT,LimitReached)).
1260
1261
1262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1263
1264 % pretty-print properties
1265 translate_properties_with_limit([],[]).
1266 translate_properties_with_limit([P|Prest],[Out|Orest]) :-
1267 translate_property_with_limit(P,320,Out), % reduced limit as we now have evaluation view + possibility to inspect all of value
1268 translate_properties_with_limit(Prest,Orest).
1269
1270 translate_property_with_limit(Prop,Limit,Output) :-
1271 (pp_property(Prop,Limit,Output) -> true ; (add_error(translate_property,'Could not translate property: ',Prop),Output='???')).
1272 pp_property(Prop,Limit,Output) :-
1273 pp_property_without_plugin(Prop,Limit,Output).
1274 pp_property_without_plugin(=(Key,Value),_,A) :-
1275 !,ajoin([Key,' = ',Value],A).
1276 pp_property_without_plugin(':'(Key,Value),_,A) :-
1277 !,ajoin([Key,' : ',Value],A).
1278 pp_property_without_plugin(info(I),_,I) :- !.
1279 pp_property_without_plugin(Prop,Limit,A) :-
1280 write_to_codes(Prop,Codes),
1281 atom_codes_with_limit(A,Limit,Codes).
1282
1283
1284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1285 :- use_module(tools_meta,[translate_term_into_atom_with_max_depth/3]).
1286
1287 % pretty-print errors belonging to a certain state
1288 translate_error_term(Term,S) :- translate_error_term(Term,unknown,S).
1289 translate_error_term(Var,_,S) :- var(Var),!,
1290 translate_term_into_atom_with_max_depth(Var,5,S).
1291 translate_error_term('@fun'(X,F),Span,S) :-
1292 translate_bvalue(X,TX),
1293 (get_function_from_span(Span,Fun,LocState,State),
1294 translate_bexpression_with_limit(Fun,200,TSF)
1295 -> % we managed to extract the function from the span_predicate
1296 (is_compiled_value(Fun)
1297 ? -> (get_was_identifier(Fun,WasFunId) -> Rest = [', function: ',WasFunId | Rest1]
1298 ; Rest = Rest1
1299 ),
1300 TVal=TSF % use as value
1301 ; Rest = [', function: ',TSF | Rest1],
1302 % try and extract value from span_predicate (often F=[] after traversing avl)
1303 (get_texpr_id(Fun,FID),
1304 ? (member(bind(FID,FVal),LocState) ; member(bind(FID,FVal),State))
1305 -> translate_bvalue(FVal,TVal)
1306 ; translate_bvalue(F,TVal)
1307 )
1308 )
1309 ; Rest=[], translate_bvalue(F,TVal)
1310 ),!,
1311 % translate_term_into_atom_with_max_depth('@fun'(TX,TVal),5,S).
1312 (get_error_span_for_value(F,NewSpanTxt) % triggers in test 953
1313 -> Rest1 = [' defined at ',NewSpanTxt]
1314 ; Rest1 = []
1315 ),
1316 ajoin(['Function argument: ',TX, ', function value: ',TVal | Rest],S).
1317 translate_error_term('@rel'(Arg,Res1,Res2),_,S) :-
1318 translate_bvalue(Arg,TA), translate_bvalue(Res1,R1),
1319 translate_bvalue(Res2,R2),!,
1320 ajoin(['Function argument: ',TA, ', two possible values: ',R1,', ',R2],S).
1321 translate_error_term([Op|T],_,S) :- T==[], nonvar(Op), Op=operation(Name,Env),
1322 translate_any_state(Env,TEnv), !,
1323 translate_term_into_atom_with_max_depth(operation(Name,TEnv),10,S).
1324 translate_error_term(error(E1,E2),_,S) :- !, translate_prolog_error(E1,E2,S).
1325 translate_error_term(b(B,T,I),_,S) :-
1326 translate_subst_or_bexpr_with_limit(b(B,T,I),1000,do_not_report_errors,S),!. % do not report errors, otherwise we end in an infinite loop of adding errors while adding errors
1327 translate_error_term([H|T],_,S) :- nonvar(H), H=b(_,_,_), % typically a list of typed ids
1328 E=b(sequence_extension([H|T]),any,[]),
1329 translate_subst_or_bexpr_with_limit(E,1000,do_not_report_errors,S),!.
1330 translate_error_term([H|T],_,S) :- nonvar(H), H=bind(_,_), % a store
1331 translate_bstate_limited([H|T],1000,S),!.
1332 translate_error_term(Term,_,S) :-
1333 is_bvalue(Term),
1334 translate_bvalue_with_limit(Term,1000,S),!.
1335 translate_error_term(T,_,S) :-
1336 (debug_mode(on) -> Depth = 20 ; Depth = 5),
1337 translate_term_into_atom_with_max_depth(T,Depth,S).
1338
1339 get_function_from_span(Var,Fun,_,_) :- var(Var), !,
1340 add_internal_error('Variable span:',get_function_from_span(Var,Fun)),fail.
1341 get_function_from_span(pos_context(Span,_,_),Fun,LS,S) :- get_function_from_span(Span,Fun,LS,S).
1342 get_function_from_span(span_predicate(b(function(Function,_Arg),_T,_I),LocalState,State),Function,LocalState,State).
1343
1344 is_compiled_value(b(value(_),_,_)).
1345
1346 ?get_was_identifier(b(_,_,Info),Id) :- member(was_identifier(Id),Info). % added e.g. by b_compiler
1347
1348 % TODO: complete this
1349 % for recognising B values as error terms and automatically translating them
1350 is_bvalue(V) :- var(V),!,fail.
1351 is_bvalue([]).
1352 is_bvalue(closure(_,_,_)).
1353 is_bvalue(fd(_,_)).
1354 is_bvalue(freetype(_)).
1355 is_bvalue(freeval(_,_,_)).
1356 is_bvalue(avl_set(_)).
1357 is_bvalue(int(_)).
1358 is_bvalue(global_set(_)).
1359 is_bvalue(pred_true).
1360 is_bvalue(pred_false).
1361 is_bvalue(string(_)).
1362 is_bvalue(term(_)). % typically term(floating(_))
1363 is_bvalue(rec(Fields)) :- nonvar(Fields), Fields=[F1|_], nonvar(F1),
1364 F1=field(_,V1), is_bvalue(V1).
1365 is_bvalue((A,B)) :-
1366 (nonvar(A) -> is_bvalue(A) ; true),
1367 (nonvar(B) -> is_bvalue(B) ; true).
1368
1369 % try and get error location for span:
1370 get_error_span_for_value(Var,_) :- var(Var),!,fail.
1371 get_error_span_for_value(closure(_,_,Body),Span) :- translate_span_with_filename(Body,Span), Span \= ''.
1372
1373
1374 % translate something that was caught with catch/3
1375 translate_prolog_exception(user_interrupt_signal,R) :- !, R='User-Interrupt (CTRL-C)'.
1376 translate_prolog_exception(enumeration_warning(_,_,_,_,_),R) :- !, R='Enumeration Warning'.
1377 translate_prolog_exception(error(E1,E2),S) :- !, translate_prolog_error(E1,E2,S).
1378 translate_prolog_exception(E1,S) :- translate_term_into_atom_with_max_depth(E1,8,S).
1379
1380 % translate a Prolog error(E1,E2) exception
1381 translate_prolog_error(existence_error(procedure,Pred),_,S) :- !,
1382 translate_term_into_atom_with_max_depth('Unknown Prolog predicate:'(Pred),8,S).
1383 translate_prolog_error(existence_error(source_sink,File),ExcTerm,S) :- !,
1384 (arg(1,ExcTerm,Call), functor(Call,process_create,_)
1385 -> ajoin(['Program does not exist: ',File],S)
1386 ; ajoin(['File does not exist: ',File],S)
1387 ).
1388 translate_prolog_error(permission_error(Action,source_sink,File),_,S) :- !, % Action = open, ...
1389 ajoin(['Permission denied to ',Action,' the file: ',File],S).
1390 translate_prolog_error(permission_error(Action,past_end_of_stream,File),_,S) :- !, % Action = open, ...
1391 ajoin(['Permission denied to ',Action,' past end of file: ',File],S).
1392 translate_prolog_error(resource_error(memory),_,S) :- !,
1393 S = 'Resource error: Out of memory'. % GLOBALSTKSIZE=500M probcli ... could help ???
1394 translate_prolog_error(resource_error(file_handle),_,S) :- !,
1395 (debug_mode(on) -> print_open_stream_stats ; true),
1396 S = 'Resource error: Too many open files'.
1397 translate_prolog_error(system_error,system_error('SPIO_E_NET_CONNRESET'),S) :- !,
1398 S = 'System error: connection to process lost (SPIO_E_NET_CONNRESET)'.
1399 translate_prolog_error(system_error,system_error('SPIO_E_ENCODING_UNMAPPABLE'),S) :- !,
1400 S = 'System error: illegal character or encoding encountered (SPIO_E_ENCODING_UNMAPPABLE)'.
1401 translate_prolog_error(system_error,system_error('SPIO_E_NET_HOST_NOT_FOUND'),S) :- !,
1402 S = 'System error: could not find host (SPIO_E_NET_HOST_NOT_FOUND)'.
1403 translate_prolog_error(system_error,system_error('SPIO_E_CHARSET_NOT_FOUND'),S) :- !,
1404 S = 'System error: could not find character set encoding'.
1405 translate_prolog_error(system_error,system_error('SPIO_E_OS_ERROR'),S) :- !,
1406 S = 'System error due to some OS/system call (SPIO_E_OS_ERROR)'.
1407 translate_prolog_error(system_error,system_error('SPIO_E_END_OF_FILE'),S) :- !,
1408 S = 'System error: end of file (SPIO_E_END_OF_FILE)'.
1409 translate_prolog_error(system_error,system_error('SPIO_E_TOO_MANY_OPEN_FILES'),S) :- !,
1410 S = 'System error: too many open files (SPIO_E_TOO_MANY_OPEN_FILES)'.
1411 % current_stream(File,Mode,_),write(f(File,Mode)),nl,fail.
1412 translate_prolog_error(system_error,system_error(dlopen(Msg)),S) :- !,
1413 translate_term_into_atom_with_max_depth(Msg,4,MS),
1414 ajoin(['System error: could not load dynamic library (you may have to right-click on the library and open it in the macOS Finder): ', MS],S).
1415 translate_prolog_error(system_error,system_error(Err),S) :- !,
1416 % or Err is an atom dlopen( mach-o file, but is an incompatible architecture ...)
1417 % E.g., SPIO_E_NOT_SUPPORTED when doing open('/usr',r,S)
1418 translate_term_into_atom_with_max_depth('System error:'(Err),8,S).
1419 translate_prolog_error(existence_error(procedure,Module:Pred/Arity),_,S) :- !,
1420 ajoin(['Prolog predicate does not exist: ',Module,':', Pred, '/',Arity],S).
1421 translate_prolog_error(instantiation_error,instantiation_error(Call,_ArgNo),S) :- !,
1422 translate_term_into_atom_with_max_depth('Prolog instantiation error:'(Call),8,S).
1423 translate_prolog_error(uninstantiation_error(_),uninstantiation_error(Call,_ArgNo,_Culprit),S) :- !,
1424 translate_term_into_atom_with_max_depth('Prolog uninstantiation error:'(Call),8,S).
1425 translate_prolog_error(evaluation_error(zero_divisor),evaluation_error(Call,_,_,_),S) :- !,
1426 translate_term_into_atom_with_max_depth('Division by zero error:'(Call),8,S).
1427 translate_prolog_error(evaluation_error(float_overflow),evaluation_error(Call,_,_,_),S) :- !,
1428 translate_term_into_atom_with_max_depth('Float overflow:'(Call),8,S).
1429 translate_prolog_error(representation_error(Err),representation_error(Call,_,_),S) :-
1430 memberchk(Err, ['CLPFD integer overflow','max_clpfd_integer','min_clpfd_integer']),!,
1431 translate_term_into_atom_with_max_depth('Prolog CLP(FD) overflow:'(Call),8,S).
1432 % TODO: domain_error(list_to_fdset(FDLIST,_989819),_,_,_L)
1433 translate_prolog_error(syntax_error(Err),_,S) :- !,
1434 translate_term_into_atom_with_max_depth('Prolog syntax error:'(Err),8,S).
1435 translate_prolog_error(_,resource_error(open(File,Mode,_),Kind),S) :- !, % Kind e.g. file_handle
1436 ajoin(['Resource error (',Kind,
1437 '), could not open file ',File,' in mode ',Mode],S).
1438 :- if(predicate_property(message_to_string(_, _), _)).
1439 translate_prolog_error(E1,E2,S) :-
1440 % SWI-Prolog way to translate an arbitrary message term (such as an exception) to a string,
1441 % the same way that the built-in message handling system would print it.
1442 message_to_string(error(E1,E2), String),
1443 !,
1444 atom_string(S, String).
1445 :- endif.
1446 translate_prolog_error(E1,_,S) :- translate_term_into_atom_with_max_depth(E1,8,S).
1447 % we also have permission_error, context_error, domain_error
1448
1449 portray_open_streams :- current_stream(File,Mode,Stream),
1450 format('~w file: ~w, stream: ~w~n',[Mode,File,Stream]),
1451 fail.
1452 portray_open_streams :- print_open_stream_stats.
1453
1454 :- use_module(tools_lists,[count_occurences/2]).
1455 print_open_stream_stats :- findall(Mode,current_stream(_,Mode,_),L),
1456 count_occurences(L,Occ),
1457 length(L,Nr), format('Open streams: ~w ~w~n',[Nr,Occ]).
1458
1459
1460 translate_state_errors([],[]).
1461 translate_state_errors([E|ERest],[Out|ORest]) :-
1462 ( E = eventerror(Event,EError,_) ->
1463 translate_event_error(EError,Msg),
1464 ajoin([Event,': ',Msg],Out)
1465 ; translate_state_error(E,Out) -> true
1466 ; functor(E,Out,_) ),
1467 translate_state_errors(ERest,ORest).
1468
1469 translate_error_context(E,TE) :- translate_error_context2(E,Codes,[]),
1470 atom_codes_with_limit(TE,Codes).
1471 translate_error_context2(span_context(Span,Context)) --> !,
1472 translate_error_context2(Context),
1473 translate_span(Span,only_subsidiary).
1474 translate_error_context2([H]) --> !,translate_error_context2(H).
1475 translate_error_context2(checking_invariant) --> !,
1476 {get_specification_description_codes(invariant,A)}, A. %"INVARIANT".
1477 translate_error_context2(checking_assertions) --> !,
1478 {get_specification_description_codes(assertions,A)}, A. %"ASSERTIONS".
1479 translate_error_context2(checking_negation_of_invariant(_State)) --> !,
1480 "not(INVARIANT)".
1481 translate_error_context2(operation(OpName,_State)) --> !,
1482 {translate_operation_name(OpName,TOp)},
1483 ppterm(TOp).
1484 translate_error_context2(checking_context(Check,Name)) --> !,
1485 ppterm(Check),ppterm(Name).
1486 translate_error_context2(loading_context(_Name)) --> !.
1487 translate_error_context2(visb_error_context(Class,SvgId,OpNameOrAttr,Span)) --> !,
1488 "VisB ", ppterm(Class), " for SVG ID ",
1489 ppterm(SvgId), " and attribute/event ",
1490 {translate_operation_name(OpNameOrAttr,TOp)},
1491 ppterm(TOp),
1492 translate_span(Span,only_subsidiary).
1493 translate_error_context2(X) --> "???:", ppterm(X).
1494
1495 print_span(Span) :- translate_span(Span,Atom), !, write(Atom).
1496 print_span(S) :- print(span(S)).
1497
1498 print_span_nl(Span) :- translate_span(Span,Atom), !,(Atom='' -> true ; write(Atom)),nl.
1499 print_span_nl(S) :- print(span(S)),nl.
1500
1501
1502 translate_span(Span,Atom) :- translate_span(Span,only_subsidiary,Codes,[]),
1503 atom_codes_with_limit(Atom,Codes).
1504 translate_span_with_filename(Span,Atom) :-
1505 translate_span(Span,always_print_filename,Codes,[]),
1506 atom_codes_with_limit(Atom,Codes).
1507
1508 translate_span(Span,_) --> {var(Span)},!, {add_internal_error('Variable span:',translate_span(Span,_))}, "_".
1509 translate_span(Span,PrintFileNames) --> {extract_line_col(Span,Srow,Scol,_Erow,_Ecol)},!,
1510 "(Line:",ppterm(Srow)," Col:",ppterm(Scol),
1511 %"-",ppterm(Erow),":",ppterm(Ecol),
1512 translate_span_file_opt(Span,PrintFileNames),
1513 % TO DO: print short version of extract_additional_description ?
1514 ")".
1515 translate_span(Span,_PrintFileNames) --> {extract_symbolic_label(Span,Label)},!, "(label @",ppterm(Label),")".
1516 translate_span(Span,PrintFileNames) -->
1517 % for Event-B, e.g., line-col fails but we can get a section/file name
1518 "(File:",translate_span_file(Span,PrintFileNames),!,")".
1519 translate_span(_,_PrintFileNames) --> "".
1520
1521 translate_span_file(Span,always_print_filename) -->
1522 {extract_tail_file_name(Span,Filename)},!,
1523 %{bmachine:b_get_main_filenumber(MainFN), Nr \= MainFN},!,
1524 " File:", ppterm(Filename).
1525 translate_span_file(Span,_) -->
1526 {extract_subsidiary_tail_file_name(Span,Filename)},
1527 %{bmachine:b_get_main_filenumber(MainFN), Nr \= MainFN},!,
1528 !,
1529 " File:", ppterm(Filename).
1530 translate_span_file_opt(Span,Print) --> translate_span_file(Span,Print),!.
1531 translate_span_file_opt(_,_) --> "".
1532
1533
1534 explain_span_file(Span) -->
1535 {extract_subsidiary_tail_file_name(Span,Filename)},
1536 %{bmachine:b_get_main_filenumber(MainFN), Nr \= MainFN},!,
1537 "\n### File: ", ppterm(Filename).
1538 explain_span_file(_) --> "".
1539
1540 explain_span(V) --> {var(V)},!, "Internal error: Illegal variable span".
1541 explain_span(span_predicate(Pred,LS,S)) --> !, explain_span2(span_predicate(Pred,LS,S)),
1542 explain_local_state(LS). %, explain_global_state(S).
1543 explain_span(Span) --> explain_span2(Span).
1544 explain_span2(Span) --> {extract_line_col(Span,Srow,Scol,Erow,Ecol)},!,
1545 "\n### Line: ", ppterm(Srow), ", Column: ", ppterm(Scol),
1546 " until Line: ", ppterm(Erow), ", Column: ", ppterm(Ecol),
1547 explain_span_file(Span),
1548 explain_span_context(Span).
1549 explain_span2(Span) --> {extract_symbolic_label_pos(Span,Msg)},!,
1550 "\n @label: ", ppterm(Msg),
1551 explain_span_context(Span).
1552 explain_span2(Span) --> explain_span_context(Span).
1553
1554 explain_span_context(Span) --> {extract_additional_description(Span,Msg),!},
1555 "\n### within ", ppterm(Msg). % context of span, such as definition call hierarchy
1556 explain_span_context(_) --> "".
1557
1558 explain_local_state([]) --> !, "".
1559 explain_local_state(LS) --> "\n Local State: ", pp_b_state(LS,1000).
1560 %explain_global_state([]) --> !, "".
1561 %explain_global_state(LS) --> "\n Global State: ", pp_b_state(LS).
1562
1563 translate_event_error(Error,Out) :-
1564 ( translate_event_error2(Error,Out) -> true
1565 ;
1566 functor(Error,F,_),
1567 ajoin(['** Unable to translate event error: ',F,' **'],Out)).
1568 translate_event_error2(no_witness_found(Type,Var,_Predicate),Out) :-
1569 def_get_texpr_id(Var,Id),
1570 ajoin(['no witness was found for ',Type,' ',Id],Out).
1571 translate_event_error2(simulation_error(_Events),Out) :-
1572 Out = 'no matching abstract event was found'.
1573 translate_event_error2(action_not_executable(_Action,WDErr),Out) :-
1574 (WDErr=wd_error_possible -> Out = 'action was not executable (maybe with WD error)'
1575 ; Out = 'action was not executable').
1576 translate_event_error2(invalid_modification(Var,_Pre,_Post),Out) :-
1577 def_get_texpr_id(Var,Id),
1578 ajoin(['modification of variable ', Id, ' not allowed'],Out).
1579 translate_event_error2(variant_negative(_CType,_Variant,_Value),Out) :-
1580 Out = 'enabled for negative variant'.
1581 translate_event_error2(invalid_variant(anticipated,_Expr,_Pre,_Post),Out) :-
1582 Out = 'variant increased'.
1583 translate_event_error2(invalid_variant(convergent,_Expr,_Pre,_Post),Out) :-
1584 Out = 'variant not decreased'.
1585 translate_event_error2(invalid_theorem_in_guard(_Theorem),Out) :-
1586 Out = 'theorem in guard evaluates to false'.
1587 translate_event_error2(event_wd_error(_TExpr,Source),Out) :-
1588 ajoin(['WD error for ',Source],Out).
1589 translate_event_error2(event_other_error(Msg),Out) :- Out=Msg.
1590
1591 translate_state_error(abort_error(_TYPE,Msg,ErrTerm,ErrorContext),Out) :- !,
1592 translate_error_term(ErrTerm,ES),
1593 translate_error_context(ErrorContext,EC),
1594 ajoin([EC,': ',Msg,': ',ES],Out).
1595 translate_state_error(clpfd_overflow_error(Context),Out) :- !, % 'CLPFD_integer_overflow'
1596 ajoin(['CLPFD integer overflow while ', Context],Out).
1597 translate_state_error(max_state_errors_reached(Nr),Out) :- !,
1598 ajoin(['Max. number of state errors reached: ', Nr],Out).
1599 translate_state_error(Unknown,Out) :-
1600 add_error(translate_state_error,'Unknown state error: ',Unknown),
1601 Out = '*** Unknown State Error ***'.
1602
1603
1604 get_span_from_context([H],Span) :- !, get_span_from_context(H,Span).
1605 get_span_from_context(span_context(Span,_),Res) :- !, Res=Span.
1606 get_span_from_context(_,unknown).
1607
1608 explain_error_context1([H]) --> !,explain_error_context1(H).
1609 explain_error_context1(span_context(Span,Context)) --> !,
1610 explain_span(Span),"\n",
1611 explain_error_context2(Context).
1612 explain_error_context1(Ctxt) --> explain_error_context2(Ctxt).
1613
1614 explain_error_context2([H]) --> !,explain_error_context2(H).
1615 explain_error_context2(span_context(Span,Context)) --> !,
1616 explain_span(Span),"\n",
1617 explain_error_context2(Context).
1618 explain_error_context2(checking_invariant) --> !,
1619 {get_specification_description_codes(invariant,I)}, I, ":\n ", %"INVARIANT:\n ",
1620 pp_current_state. % assumes explain is called in the right state ! ; otherwise we need to store the state id
1621 explain_error_context2(checking_assertions) --> !,
1622 {get_specification_description_codes(assertions,A)}, A, ":\n ", %"ASSERTIONS:\n ",
1623 pp_current_state. % assumes explain is called in the right state ! ; otherwise we need to store the state id
1624 explain_error_context2(checking_negation_of_invariant(State)) --> !,
1625 "not(INVARIANT):\n State: ",
1626 pp_b_state(State,1000).
1627 explain_error_context2(operation('$setup_constants',StateID)) --> !,
1628 {get_specification_description_codes(properties,P)}, P, ":\n State: ",
1629 pp_context_state(StateID).
1630 explain_error_context2(operation(OpName,StateID)) --> !,
1631 {get_specification_description_codes(operation,OP)}, OP, ": ", %"EVENT/OPERATION: ",
1632 {translate_operation_name(OpName,TOp)},
1633 ppterm(TOp), "\n ",
1634 pp_context_state(StateID).
1635 explain_error_context2(checking_context(Check,Name)) --> !,
1636 ppterm(Check),ppterm(Name), "\n ".
1637 explain_error_context2(loading_context(Name)) --> !,
1638 "Loading: ",ppterm(Name), "\n ".
1639 explain_error_context2(visb_error_context(Class,SvgId,OpNameOrAttr,Span)) --> !,
1640 translate_error_context2(visb_error_context(Class,SvgId,OpNameOrAttr,Span)).
1641 explain_error_context2(X) --> "UNKNOWN ERROR CONTEXT:\n ", ppterm(X).
1642
1643 :- use_module(specfile,[get_specification_description/2]).
1644 get_specification_description_codes(Tag,Codes) :- get_specification_description(Tag,Atom), atom_codes(Atom,Codes).
1645
1646 explain_state_error(Error,Span,Out) :-
1647 explain_state_error2(Error,Span,Out,[]),!.
1648 explain_state_error(_Error,unknown,"Sorry, the detailed output failed.\n").
1649
1650 explain_abort_error_type(well_definedness_error) --> !, "An expression was not well-defined.\n".
1651 explain_abort_error_type(card_overflow_error) --> !, "The cardinality of a finite set was too large to be represented.\n".
1652 explain_abort_error_type(while_variant_error) --> !, "A while-loop VARIANT error occurred.\n".
1653 explain_abort_error_type(while_invariant_violation) --> !, "A while-loop INVARIANT error occurred.\n".
1654 explain_abort_error_type(precondition_error) --> !, "A precondition (PRE) error occurred.\n".
1655 explain_abort_error_type(feasibility_error) --> !, "A feasibility error occurred.\n".
1656 explain_abort_error_type(assert_error) --> !, "An ASSERT error occurred.\n".
1657 explain_abort_error_type(Type) --> "Error occurred: ", ppterm(Type), "\n".
1658
1659 explain_state_error2(abort_error(TYPE,Msg,ErrTerm,ErrContext),Span) -->
1660 explain_abort_error_type(TYPE),
1661 "Reason: ", ppterm(Msg), "\n",
1662 {get_span_from_context(ErrContext,Span)},
1663 ({ErrTerm=''} -> ""
1664 ; "Details: ", {translate_error_term(ErrTerm,Span,ErrS)},ppterm(ErrS), "\n"
1665 ),
1666 "Context: ", explain_error_context1(ErrContext).
1667 explain_state_error2(max_state_errors_reached(Nr),unknown) -->
1668 "Too many error occurred for this state.\n",
1669 "Not all errors are shown.\n",
1670 "Number of errors is at least: ", ppterm(Nr).
1671 explain_state_error2(eventerror(_Event,Error,Trace),Span) --> % TO DO: also extract loc info ?
1672 {translate_event_error(Error,Msg)},
1673 ppatom(Msg),
1674 "\nA detailed trace containing the error:\n",
1675 "--------------------------------------\n",
1676 explain_event_trace(Trace,Span).
1677 explain_state_error2(clpfd_overflow_error(Context),unknown) --> % CLPFD_integer_overflow
1678 "An overflow occurred inside the CLP(FD) library.\n",
1679 "Context: ", ppterm(Context), "\n",
1680 "You may try and set the CLPFD preference to FALSE.\n".
1681
1682 % try and get span from state error:
1683 get_state_error_span(abort_error(_,_,_,Context),Span) :- get_span_context_span(Context,Span).
1684
1685 get_span_context_span(span_context(Span,_),Span).
1686 get_span_context_span([H],Span) :- get_span_context_span(H,Span).
1687
1688
1689
1690 show_parameter_values([],[]) --> !.
1691 show_parameter_values([P|Prest],[V|Vrest]) -->
1692 show_parameter_value(P,V),
1693 show_parameter_values(Prest,Vrest).
1694 show_parameter_value(P,V) -->
1695 " ",pp_expr(P,_,_LR)," = ",pp_value(V),"\n".
1696
1697 % translate an Event-B error trace (error occurred during multi-level animation)
1698 % into a textual description (Codes) and a span_predicate term which can be visualised
1699 explain_event_trace(Trace,Codes,Span) :-
1700 explain_event_trace(Trace,Span,Codes,[]).
1701
1702 explain_event_trace(Trace,span_predicate(SpanPred,[],[])) -->
1703 % evaluating the span predicate will require access to current state, which needs to be added later
1704 explain_event_trace4(Trace,'?','?',SpanPred).
1705
1706 explain_event_trace4([],_,_,b(truth,pred,[])) --> !.
1707 explain_event_trace4([event(Name,Section)|Trest],_,_,SpanPred) --> !,
1708 "\n",
1709 "Event ",ppterm(Name)," in model ",ppterm(Section),
1710 ":\n",
1711 % pass new current event name and section for processing tail:
1712 explain_event_trace4(Trest,Name,Section,SpanPred).
1713 explain_event_trace4([Step|Trest],Name,Section,SpanPred) -->
1714 "\n",
1715 ? ( explain_event_step4(Step,StepPred) -> ""
1716 ; {functor(Step,F,_)} ->
1717 " (no rule to explain event step ",ppatom(F),")\n"),
1718 explain_event_trace4(Trest,Name,Section,RestSpanPred),
1719 {combine_span_pred(StepPred,RestSpanPred,Name,Section,SpanPred)}.
1720
1721 % create a span predicate from the event error trace to display relevant values and predicates
1722 combine_span_pred(unknown,S,_,_,Res) :- !, Res=S.
1723 combine_span_pred(new_scope(Kind,Paras,Vals,P1),P2,Name,Section,Res) :- !,
1724 maplist(create_tvalue,Paras,Vals,TVals),
1725 add_span_label(Kind,Name,Section,P1,P1L),
1726 conjunct_predicates([P1L,P2],Body),
1727 (Paras=[] -> Res=Body ; Res = b(let_predicate(Paras,TVals,Body),pred,[])). % translate:print_bexpr(Res),nl.
1728 % we could also do: add_texpr_description
1729 combine_span_pred(P1,P2,_,_,Res) :-
1730 conjunct_predicates([P1,P2],Res).
1731
1732 add_span_label(Kind,Name,Section,Pred,NewPred) :-
1733 (Kind=[Label] -> true % already has position info
1734 ; create_label(Kind,Name,Section,Label)),
1735 add_labels_to_texpr(Pred,[Label],NewPred).
1736 create_label(Kind,Name,Section,Label) :- ajoin([Kind,' in ',Section,':',Name],Label).
1737
1738 create_tvalue(b(_,Type,_),Value,b(value(Value),Type,[])).
1739
1740 explain_event_step4(true_guard(Parameters,Values,Guard),new_scope('guard true',Parameters,Values,Guard)) --> !,
1741 ( {Parameters==[]} -> ""
1742 ; " for the parameters:\n",
1743 show_parameter_values(Parameters,Values)),
1744 " the guard is true:",
1745 explain_predicate(Guard,4),"\n".
1746 explain_event_step4(eval_witness(Type,Id,Value,Predicate),new_scope('witness',[Id],[Value],Predicate)) -->
1747 witness_intro(Id,Predicate,Type),
1748 " found witness:\n",
1749 " ", pp_expr(Id,_,_LR), " = ", pp_value(Value), "\n".
1750 explain_event_step4(simulation_error(Errors),SpanPred) -->
1751 " no guard of a refined event was satisfiable:\n",
1752 explain_simulation_errors(Errors,Guards),
1753 {disjunct_predicates(Guards,SpanPred)}.
1754 explain_event_step4(invalid_theorem_in_guard(Theorem),new_scope('false theorem',[],[],Theorem)) -->
1755 " the following theorem evaluates to false:",
1756 explain_predicate(Theorem,4),"\n".
1757 explain_event_step4(invalid_modification(Var,Pre,Post),
1758 new_scope('invalid modification',[Var],[Post],b(falsity,pred,[]))) -->
1759 " the variable ", pp_expr(Var,_,_LR), " has been modified.\n",
1760 " The event is not allowed to modify the variable because its abstract event does not modify it.\n",
1761 " Old value: ", pp_value(Pre), "\n",
1762 " New value: ", pp_value(Post), "\n".
1763 explain_event_step4(action_not_executable(TAction,WDErr),new_scope('action not executable',[],[],Equalities)) -->
1764 {exctract_span_pred_from_subst(TAction,Equalities)},
1765 explain_action_not_executable(TAction,WDErr).
1766 explain_event_step4(Step,unknown) -->
1767 explain_event_step(Step).
1768 % TODO: add span predicates for the errors below:
1769
1770 extract_equality(Infos,TID,NewExpr,b(equal(TID,NewExpr),pred,Infos)). % TODO: introduce TID' primed?
1771 exctract_span_pred_from_subst(b(assign(TIDs,Exprs),subst,Infos),SpanPred) :-
1772 maplist(extract_equality(Infos),TIDs,Exprs,List),
1773 conjunct_predicates(List,SpanPred).
1774 % todo: becomes_such, ...
1775
1776 explain_event_step(variant_checked_pre(CType,Variant,Value)) -->
1777 " ",ppatom(CType)," event: checking if the variant is non-negative:\n",
1778 " variant: ",pp_expr(Variant,_,_LR),"\n",
1779 " its value: ",pp_value(Value),"\n".
1780 explain_event_step(variant_negative(CType,Variant,Value)) -->
1781 explain_event_step(variant_checked_pre(CType,Variant,Value)),
1782 " ERROR: variant is negative\n".
1783 explain_event_step(variant_checked_post(CType,Variant,EntryValue,ExitValue)) -->
1784 " ",ppatom(CType)," event: checking if the variant is ",
1785 ( {CType==convergent} -> "decreased:\n" ; "not increased:\n"),
1786 " variant: ", pp_expr(Variant,_,_LR), "\n",
1787 " its value before: ", pp_value(EntryValue),"\n",
1788 " its value after: ", pp_value(ExitValue),"\n".
1789 explain_event_step(invalid_variant(CType,Variant,EntryValue,ExitValue)) -->
1790 explain_event_step(variant_checked_post(CType,Variant,EntryValue,ExitValue)),
1791 " ERROR: variant has ",
1792 ({CType==convergent} -> "not been decreased\n"; "has been increased\n").
1793 explain_event_step(no_witness_found(Type,Id,Predicate)) -->
1794 witness_intro(Id,Predicate,Type),
1795 " ERROR: no solution for witness predicate found!\n".
1796 explain_event_step(action(Lhs,_Rhs,Values)) -->
1797 " executing an action:\n",
1798 show_assignments(Lhs,Values).
1799 explain_event_step(action_set(Lhs,_Rhs,ValueSet,Values)) -->
1800 " executing an action:\n ",
1801 pp_expr_l(Lhs,_LR)," :: ",pp_value(ValueSet),"\n choosing\n",
1802 show_assignments(Lhs,Values).
1803 explain_event_step(action_pred(Ids,Pred,Values)) -->
1804 " executing an action:\n ",
1805 pp_expr_l(Ids,_LR1)," :| ",pp_expr(Pred,_,_LR2),"\n choosing\n",
1806 show_assignments(Ids,Values).
1807 explain_event_step(error(Error,_Id)) -->
1808 % the error marker serves to link to a stored state-error by its ID
1809 explain_event_step(Error).
1810 explain_event_step(event_wd_error(TExpr,Source)) -->
1811 " Well-Definedness ERROR for ", ppatom(Source), "\n",
1812 " ", pp_expr(TExpr,_,_LR), "\n".
1813 explain_event_step(event_other_error(Msg)) --> ppatom(Msg).
1814
1815 explain_action_not_executable(TAction,no_wd_error) --> {is_assignment_to(TAction,IDs)},!,
1816 " ERROR: the following assignment to ", ppatoms(IDs),"was not executable\n",
1817 " (probably in conflict with another assignment, check SIM or EQL PO):", % or WD error
1818 translate_subst_with_indention_and_label(TAction,4).
1819 explain_action_not_executable(TAction,wd_error_possible) --> !,
1820 " ERROR: the following action was not executable\n",
1821 " (possibly due to a WD error):",
1822 translate_subst_with_indention_and_label(TAction,4).
1823 explain_action_not_executable(TAction,_WDErr) -->
1824 " ERROR: the following action was not executable:",
1825 translate_subst_with_indention_and_label(TAction,4).
1826
1827 is_assignment_to(b(assign(LHS,_),_,_),IDs) :- get_texpr_ids(LHS,IDs).
1828 is_assignment_to(b(assign_single_id(LHS,_),_,_),IDs) :- get_texpr_ids([LHS],IDs).
1829
1830
1831 witness_intro(Id,Predicate,Type) -->
1832 " evaluating witness for abstract ", ppatom(Type), " ", pp_expr(Id,_,_LR1), "\n",
1833 " witness predicate: ", pp_expr(Predicate,_,_LR2), "\n".
1834
1835 show_assignments([],[]) --> !.
1836 show_assignments([Lhs|Lrest],[Val|Vrest]) -->
1837 " ",pp_expr(Lhs,_,_LimitReached), " := ", pp_value(Val), "\n",
1838 show_assignments(Lrest,Vrest).
1839
1840 /* unused at the moment:
1841 explain_state([]) --> !.
1842 explain_state([bind(Varname,Value)|Rest]) --> !,
1843 " ",ppterm(Varname)," = ",pp_value(Value),"\n",
1844 explain_state(Rest).
1845 explain_guards([]) --> "".
1846 explain_guards([Event|Rest]) -->
1847 {get_texpr_expr(Event,rlevent(Name,_Section,_Status,_Params,Guard,_Theorems,_Act,_VWit,_PWit,_Unmod,_Evt))},
1848 "\n",ppatom(Name),":",
1849 explain_predicate(Guard),
1850 explain_guards(Rest).
1851 explain_predicate(Guard,I,O) :-
1852 explain_predicate(Guard,2,I,O).
1853 */
1854 explain_predicate(Guard,Indention,I,O) :-
1855 pred_over_lines(0,'@grd',Guard,(Indention,I),(_,O)).
1856
1857 explain_simulation_errors([],[]) --> !.
1858 explain_simulation_errors([Error|Rest],[Grd|Gs]) -->
1859 explain_simulation_error(Error,Grd),
1860 explain_simulation_errors(Rest,Gs).
1861 explain_simulation_error(event(Name,Section,Guard),SpanPred) -->
1862 {add_span_label('guard false',Name,Section,Guard,SpanPred)},
1863 " guard for event ", ppatom(Name),
1864 " in ", ppatom(Section), ":",
1865 explain_predicate(Guard,6),"\n".
1866
1867
1868 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1869
1870 % explain a b_interpreter Classical B Path transition info
1871
1872 explain_transition_info(eventtrace(Trace),Codes) :- explain_event_trace(Trace,Codes,_Span).
1873 explain_transition_info(path(Trace),Codes) :- explain_classicb_path(Trace,0,Codes,[]).
1874
1875 explain_classicb_path(skip,I) --> indent_ws(I), "skip".
1876 explain_classicb_path(parallel(L),I) --> indent_ws(I), "BEGIN\n", {I1 is I+1}, explain_parallel(L,I1), " END".
1877 explain_classicb_path(sequence(A,B),I) --> explain_classicb_path(A,I), " ;\n", explain_classicb_path(B,I).
1878 explain_classicb_path(if_skip,I) --> indent_ws(I), "IF skipped (no branch applicable)".
1879 explain_classicb_path(if(CaseNr,Path),I) --> indent_ws(I), "IF branch ", ppnumber(CaseNr),"\n",
1880 {I1 is I+1}, explain_classicb_path(Path,I1).
1881 explain_classicb_path(pre(Cond,Path),I) --> indent_ws(I), "PRE ",
1882 {translate_bvalue_with_limit(Cond,50,CS),I1 is I+1}, ppatom(CS), " THEN\n", explain_classicb_path(Path,I1).
1883 explain_classicb_path(let(Path),I) --> indent_ws(I), "LET\n", {I1 is I+1}, explain_classicb_path(Path,I1).
1884 explain_classicb_path(assertion_violated,I) --> indent_ws(I), "ASSERT FALSE".
1885 explain_classicb_path(assertion(Path),I) --> indent_ws(I), "ASSERT TRUE THEN\n",
1886 {I1 is I+1}, explain_classicb_path(Path,I1).
1887 explain_classicb_path(witness(Path),I) --> indent_ws(I), "WITNESS TRUE THEN\n",
1888 {I1 is I+1}, explain_classicb_path(Path,I1).
1889 explain_classicb_path(any(_,Path),I) --> indent_ws(I), "ANY\n", {I1 is I+1}, explain_classicb_path(Path,I1).
1890 explain_classicb_path(var(Names,Path),I) --> indent_ws(I), "VAR ",
1891 {convert_and_ajoin_ids(Names,NS),I1 is I+1}, ppatom(NS), " IN\n", explain_classicb_path(Path,I1).
1892 explain_classicb_path(select(Nr,Path),I) --> indent_ws(I),
1893 "SELECT branch ", ({Nr=else} -> "ELSE" ; ppnumber(Nr)), "\n",
1894 {I1 is I+1}, explain_classicb_path(Path,I1).
1895 explain_classicb_path(choice(Nr,Path),I) --> indent_ws(I), "CHOICE branch ", ppnumber(Nr), "\n",
1896 {I1 is I+1}, explain_classicb_path(Path,I1).
1897 explain_classicb_path(while(Variant,while_bpath(LoopCount,LastIterPath)),I) --> indent_ws(I), {translate_bvalue_with_limit(Variant,400,VS)},
1898 "WHILE (VARIANT = ", ppatom(VS), ", iterations=", ppnumber(LoopCount), ")",
1899 ({LastIterPath=none} -> ""
1900 ; " DO (last iteration)\n", {I1 is I+1}, explain_classicb_path(LastIterPath,I1)).
1901 explain_classicb_path(assign_single_id(ID,Value),I) --> {translate_bvalue_with_limit(Value,400,VS)},
1902 indent_ws(I), ppatom(ID), " := ", ppatom(VS).
1903 explain_classicb_path(assign(LHS,Vals),I) -->
1904 {translate_bexpression_with_limit(LHS,LS),translate_bvalues_with_limit(Vals,400,VS)},
1905 indent_ws(I), ppatom(LS), " := ", ppatom(VS).
1906 explain_classicb_path(becomes_element_of(LHS,Value),I) -->
1907 {translate_bexpression_with_limit(LHS,LS),translate_bvalue_with_limit(Value,400,VS)},
1908 indent_ws(I), ppatom(LS), " :: {", ppatom(VS), "}".
1909 explain_classicb_path(becomes_such(Names,Values),I) --> indent_ws(I),
1910 {convert_and_ajoin_ids(Names,NS),translate_bvalues_with_limit(Values,400,VS)},
1911 ppatom(NS), " : ( ", ppatom(VS)," )".
1912 explain_classicb_path(operation_call(Name,ResultNames,Paras,Results, IPath),I) --> indent_ws(I),
1913 {translate_bvalues_with_limit(Paras,400,PS)},
1914 ({Results=[_|_],translate_bvalues_with_limit(Results,400,RS),
1915 translate_bexpression_with_limit(ResultNames,RNS)}
1916 -> ppatom(RNS), " := ", ppatom(RS)," <-- " ; ""),
1917 ppatom(Name), "(", ppatom(PS), ") == BEGIN\n", explain_classicb_path(IPath,I), "\n",
1918 indent_ws(I), "END".
1919 explain_classicb_path(external_subst(Name),I) --> indent_ws(I), ppatom(Name).
1920 explain_classicb_path([H|T],I) -->
1921 {member(path(Path),[H|T]),I1 is I+1},!,explain_classicb_path(Path,I1). % inner path of operation_call
1922 explain_classicb_path(P,_I) --> {write(unknown_path(P)),nl}, "??".
1923
1924 explain_parallel([],_I) --> "".
1925 explain_parallel([H],I) --> !, explain_classicb_path(H,I).
1926 explain_parallel([H|T],I) --> explain_classicb_path(H,I), " ||\n", explain_parallel(T,I).
1927
1928 indent_ws(N) --> {N<1},!,"".
1929 indent_ws(L) --> " ", {L1 is L-1}, indent_ws(L1).
1930
1931
1932 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1933 % pretty-print a state
1934
1935
1936 print_state(State) :- b_state(State), !,print_bstate(State).
1937 print_state(csp_and_b_root) :- csp_with_bz_mode, !,
1938 write('(MAIN || B)').
1939 print_state(csp_and_b(CSPState,BState)) :- csp_with_bz_mode, !,
1940 print_bstate(BState), translate_cspm_state(CSPState,Text), write(Text).
1941 print_state(CSPState) :- csp_mode,!,translate_cspm_state(CSPState,Text), write(Text).
1942 print_state(State) :- animation_mode(xtl),!,translate_xtl_value(State,Text), write(Text).
1943 print_state(State) :- write('*** Unknown state: '),print(State).
1944
1945 b_state(root).
1946 b_state(concrete_constants(_)).
1947 b_state(const_and_vars(_,_)).
1948 b_state(expanded_const_and_vars(_,_,_,_)).
1949 b_state(expanded_vars(_,_)).
1950 b_state([bind(_,_)|_]).
1951 b_state([]).
1952
1953 print_bstate(State) :- print_bstate_limited(State,1000,-1).
1954 print_bstate_limited(State,VarLimit,OverallLimit) :-
1955 translate_bstate_limited(State,VarLimit,OverallLimit,Output),
1956 write(' '),write(Output).
1957
1958 translate_any_state(State,Output) :-
1959 get_pp_state_limit(Limit),
1960 pp_any_state(State,Limit,Codes,[]),
1961 atom_codes_with_limit(Output,Codes).
1962 translate_bstate(State,Output) :-
1963 get_pp_state_limit(Limit),
1964 pp_b_state(State,Limit,Codes,[]),
1965 atom_codes_with_limit(Output,Codes).
1966
1967 get_pp_state_limit(Limit) :-
1968 (get_preference(expand_avl_upto,-1) -> Limit = -1 ; Limit = 1000).
1969
1970 % a version which tries to generate smaller strings
1971 translate_bstate_limited(State,Output) :-
1972 temporary_set_preference(expand_avl_upto,2,CHNG),
1973 call_cleanup(translate_bstate_limited(State,200,Output),
1974 reset_temporary_preference(expand_avl_upto,CHNG)).
1975
1976 translate_bstate_limited(State,Limit,Output) :-
1977 translate_bstate_limited(State,Limit,Limit,Output).
1978 translate_bstate_limited(State,VarLimit,Limit,Output) :-
1979 pp_b_state(State,VarLimit,Codes,[]), % this limit VarLimit applies to every variable
1980 atom_codes_with_limit(Output,Limit,Codes). % Limit applies to the full translation
1981
1982 pp_b_state(X,Limit) --> try_pp_b_state(X,Limit),!.
1983 pp_b_state(X,_Limit) --> {add_error(pp_b_state,'Could not translate state: ',X)}.
1984
1985 % Limit is pretty-print limit for every value printed
1986 try_pp_b_state(VAR,_) --> {var(VAR)},!, "_?VAR?_", {add_error(pp_b_state,'Variable state: ',VAR)}.
1987 try_pp_b_state(root,_) --> !, "root".
1988 try_pp_b_state(csp_and_b_root,_) --> !, "CSP||B root".
1989 try_pp_b_state(concrete_constants(Constants),Limit) --> !,"Constants: ",
1990 pp_b_state(Constants,Limit).
1991 try_pp_b_state(const_and_vars(ID,Vars),Limit) --> !,
1992 "Constants:",ppterm(ID),", Vars:",
1993 {set_translation_constants(ID)}, /* extract constants which stand for deferred set elements */
1994 pp_b_state(Vars,Limit),
1995 {clear_translation_constants}.
1996 try_pp_b_state(expanded_const_and_vars(ID,Vars,_,_Infos),Limit) --> !, "EXPANDED ",
1997 try_pp_b_state(const_and_vars(ID,Vars),Limit).
1998 try_pp_b_state(expanded_vars(Vars,_Infos),Limit) --> !, "EXPANDED ",
1999 try_pp_b_state(Vars,Limit).
2000 try_pp_b_state([],_) --> !, "/* empty state */".
2001 try_pp_b_state([bind(Varname,Value)|Rest],Limit) --> !,
2002 "( ",ppterm(Varname),"=",
2003 dcg_set_up_limit_reached(Limit,LimitReached),
2004 pp_value(Value,LimitReached),
2005 ({Rest = []} -> []; " ",and_symbol,"\n "),
2006 pp_b_state_list(Rest,Limit).
2007
2008
2009 pp_b_state_list([],_) --> !, " )".
2010 pp_b_state_list([bind(Varname,Value)|Rest],Limit) --> !,
2011 ppterm(Varname),"=",
2012 dcg_set_up_limit_reached(Limit,LimitReached),
2013 pp_value(Value,LimitReached),
2014 ({Rest = []} -> [] ; " ",and_symbol,"\n "),
2015 pp_b_state_list(Rest,Limit).
2016 pp_b_state_list(X,_) --> {add_error(pp_b_state_list,'Could not translate: ',X)}.
2017
2018 % a version of pp which generates no newline; can be used for printing SETUP_CONSTANTS, INITIALISATION
2019 pp_b_state_comma_list([],_,_) --> !, ")".
2020 pp_b_state_comma_list(_,Cur,Limit) --> {Cur >= Limit}, !, "...".
2021 pp_b_state_comma_list([bind(Varname,Value)|Rest],Cur,Limit) --> !,
2022 %{write(c(Varname,Cur,Limit)),nl},
2023 start_size(Ref),
2024 ppterm(Varname),"=",
2025 pp_value(Value),
2026 ({Rest = []}
2027 -> ")"
2028 ; ",",
2029 end_size(Ref,Size), % compute size increase wrt Ref point
2030 {Cur1 is Cur+Size},
2031 pp_b_state_comma_list(Rest,Cur1,Limit)
2032 ).
2033 pp_b_state_comma_list(X,_,_) --> {add_error(pp_b_state_comma_list,'Could not translate: ',X)}.
2034
2035 start_size(X,X,X).
2036 end_size(RefVar,Len,X,X) :- % compute how many chars the dcg has added wrt start_size
2037 len(RefVar,X,Len).
2038 len(Var,X,Len) :- (var(Var) ; Var==X),!, Len=0.
2039 len([],_,0).
2040 len([_|T],X,Len) :- len(T,X,L1), Len is L1+1.
2041
2042 % can be used e.g. for setup_constants, initialise
2043 translate_b_state_to_comma_list_codes(FUNCTORCODES,State,Limit,ResCodes) :-
2044 pp_b_state_comma_list(State,0,Limit,Codes,[]),
2045 append("(",Codes,C0),
2046 append(FUNCTORCODES,C0,ResCodes).
2047
2048 % translate to a single line without newlines
2049 translate_b_state_to_comma_list(State,Limit,ResAtom) :-
2050 pp_b_state_comma_list(State,0,Limit,Codes,[]),
2051 append("(",Codes,C0),
2052 atom_codes(ResAtom,C0).
2053
2054 % ----------------
2055
2056 % printing and translating error contexts
2057 print_context(State) :- translate_context(State,Output), write(Output).
2058
2059 translate_context(Context,Output) :-
2060 pp_b_context(Context,Codes,[]),
2061 atom_codes_with_limit(Output,250,Codes).
2062
2063 pp_b_context([]) --> !.
2064 pp_b_context([C|Rest]) --> !,
2065 pp_b_context(C),
2066 pp_b_context(Rest).
2067 pp_b_context(translate_context) --> !, " ERROR CONTEXT: translate_context". % error occurred within translate_context
2068 pp_b_context(span_context(Span,Context)) --> !,
2069 pp_b_context(Context), " ", translate_span(Span,only_subsidiary).
2070 pp_b_context(operation(Name,StateID)) --> !,
2071 " ERROR CONTEXT: ",
2072 {get_specification_description_codes(operation,OP)}, OP, ":", % "OPERATION:"
2073 ({var(Name)} -> ppterm('ALL') ; {translate_operation_name(Name,TName)},ppterm(TName)),
2074 ",",pp_context_state(StateID).
2075 pp_b_context(checking_invariant) --> !,
2076 " ERROR CONTEXT: INVARIANT CHECKING,", pp_cur_context_state.
2077 pp_b_context(checking_negation_of_invariant(State)) --> !,
2078 " ERROR CONTEXT: NEGATION_OF_INVARIANT CHECKING, State:", pp_b_state(State,1000).
2079 pp_b_context(checking_assertions) --> !,
2080 " ERROR CONTEXT: ASSERTION CHECKING,", pp_cur_context_state.
2081 pp_b_context(checking_context(Check,Name)) --> !,
2082 " ERROR CONTEXT: ", ppterm(Check),ppterm(Name).
2083 pp_b_context(loading_context(_FName)) --> !.
2084 pp_b_context(unit_test_context(Module,TotNr,Line,Call)) --> !,
2085 " ERROR CONTEXT: Unit Test ", ppterm(TotNr), " in module ", ppterm(Module),
2086 " at line ", ppterm(Line), " calling ", pp_functor(Call).
2087 pp_b_context(visb_error_context(Class,ID,OpNameOrAttr,Span)) --> !,
2088 " ERROR CONTEXT: VisB ", ppterm(Class), " with ID ", ppterm(ID),
2089 ({OpNameOrAttr='all_attributes'} -> ""
2090 ; " and attribute/event ", ppterm(OpNameOrAttr)
2091 ),
2092 " ", translate_span(Span,only_subsidiary).
2093 pp_b_context(C) --> ppterm(C),pp_cur_context_state.
2094
2095 pp_functor(V) --> {var(V)},!, ppterm(V).
2096 pp_functor(T) --> {functor(T,F,N)}, ppterm(F),"/",ppterm(N).
2097
2098 pp_cur_context_state --> {state_space:get_current_context_state(ID)}, !,pp_context_state(ID).
2099 pp_cur_context_state --> ", unknown context state.".
2100
2101 % assumes we are in the right state:
2102 pp_current_state --> {state_space:current_expression(ID,_)}, !,pp_context_state(ID).
2103 pp_current_state --> ", unknown current context state.".
2104
2105 % TO DO: limit length/size of generated error description
2106 pp_context_state(ID) --> {state_space:visited_expression(ID,State)},!, % we have a state ID
2107 " State ID:", ppterm(ID),
2108 pp_context_state2(State).
2109 pp_context_state(State) --> pp_context_state3(State).
2110
2111 pp_context_state2(_) --> {debug_mode(off)},!.
2112 pp_context_state2(State) --> ",", pp_context_state3(State).
2113
2114 pp_context_state3(State) --> " State: ",pp_any_state_with_limit(State,10).
2115
2116 pp_any_state_with_limit(State,Limit) -->
2117 { get_preference(expand_avl_upto,CurLim),
2118 (CurLim<0 ; Limit < CurLim),
2119 !,
2120 temporary_set_preference(expand_avl_upto,Limit,CHNG),
2121 VarLimit is Limit*10
2122 },
2123 pp_any_state(State,VarLimit),
2124 {reset_temporary_preference(expand_avl_upto,CHNG)}.
2125 pp_any_state_with_limit(State,_Limit) -->
2126 {get_preference(expand_avl_upto,CurLim), VarLimit is CurLim*10},
2127 pp_any_state(State,VarLimit).
2128
2129 pp_any_state(X,VarLimit) --> try_pp_b_state(X,VarLimit),!.
2130 pp_any_state(csp_and_b(P,B),VarLimit) --> "CSP: ",{pp_csp_process(P,Atoms,[])},!,atoms_to_codelist(Atoms),
2131 " || B: ", try_pp_b_state(B,VarLimit).
2132 pp_any_state(X,_) --> {animation_mode(xtl)}, !, "XTL: ",pp_xtl_value(X). % XTL/CSP state
2133 pp_any_state(P,_) --> "CSP: ",{pp_csp_process(P,Atoms,[])},!,atoms_to_codelist(Atoms).
2134 pp_any_state(X,_) --> "Other formalism: ",ppterm(X). % CSP state
2135
2136 atoms_to_codelist([]) --> [].
2137 atoms_to_codelist([Atom|T]) --> ppterm(Atom), atoms_to_codelist(T).
2138
2139 % ----------------
2140
2141 :- dynamic deferred_set_constant/3.
2142
2143 set_translation_context(const_and_vars(ConstID,_)) :- !,
2144 %% print_message(setting_translation_constants(ConstID)),
2145 set_translation_constants(ConstID).
2146 set_translation_context(expanded_const_and_vars(ConstID,_,_,_)) :- !,
2147 set_translation_constants(ConstID).
2148 set_translation_context(_).
2149
2150 set_translation_constants(_) :- clear_translation_constants,
2151 get_preference(dot_print_use_constants,false),!.
2152 set_translation_constants(ConstID) :- var(ConstID),!,
2153 add_error(set_translation_constants,'Variable used as ConstID: ',ConstID).
2154 set_translation_constants(ConstID) :-
2155 state_space:visited_expression(ConstID,concrete_constants(ConstantsStore)),!,
2156 %% print_message(setting_constants(ConstID)),%%
2157 (treat_constants(ConstantsStore) -> true ; print_message(fail)).
2158 set_translation_constants(ConstID) :-
2159 add_error(set_translation_constants,'Unknown ConstID: ',ConstID).
2160
2161 clear_translation_constants :- %print_message(clearing),%%
2162 retractall(deferred_set_constant(_,_,_)).
2163
2164 treat_constants([]).
2165 treat_constants([bind(CstName,Val)|T]) :-
2166 ((Val=fd(X,GSet),b_global_deferred_set(GSet))
2167 -> (deferred_set_constant(GSet,X,_)
2168 -> true /* duplicate def of value */
2169 ; assertz(deferred_set_constant(GSet,X,CstName))
2170 )
2171 ; true
2172 ),
2173 treat_constants(T).
2174
2175
2176
2177 translate_bvalue_with_tlatype(Value,Type,Output) :-
2178 ( pp_tla_value(Type,Value,Codes,[]) ->
2179 atom_codes_with_limit(Output,Codes)
2180 ; add_error(translate_bvalue,'Could not translate TLA value: ',Value),
2181 Output='???').
2182
2183 pp_tla_value(function(_Type1,_Type2),[]) --> !,
2184 ppcodes("<<>>").
2185 pp_tla_value(function(integer,T2),avl_set(Set)) -->
2186 {convert_avlset_into_sequence(Set,Seq)}, !,
2187 pp_tla_with_sep("<< "," >>",",",T2,Seq).
2188 pp_tla_value(function(T1,T2),Set) -->
2189 {is_printable_set(Set,Values)},!,
2190 pp_tla_with_sep("(",")"," @@ ",function_value(T1,T2),Values).
2191 pp_tla_value(function_value(T1,T2),(L,R)) -->
2192 !,pp_tla_value(T1,L),":>",pp_tla_value(T2,R).
2193 pp_tla_value(set(Type),Set) -->
2194 {is_printable_set(Set,Values)},!,
2195 pp_tla_with_sep("{","}",",",Type,Values).
2196 pp_tla_value(tuple(Types),Value) -->
2197 {pairs_to_list(Types,Value,Values,[]),!},
2198 pp_tla_with_sep("<< "," >>",",",Types,Values).
2199 pp_tla_value(record(Fields),rec(FieldValues)) -->
2200 % TODO: Check if we can safely assume that Fields and FieldValues have the
2201 % same order
2202 !, {sort_tla_fields(Fields,FieldValues,RFields,RFieldValues)},
2203 pp_tla_with_sep("[","]",", ",RFields,RFieldValues).
2204 pp_tla_value(field(Name,Type),field(_,Value)) -->
2205 !, ppatom_opt_scramble(Name)," |-> ",pp_tla_value(Type,Value).
2206 pp_tla_value(_Type,Value) -->
2207 % fallback: use B's pretty printer
2208 pp_value(Value).
2209
2210 is_printable_set(avl_set(A),List) :- avl_domain(A,List).
2211 is_printable_set([],[]).
2212 is_printable_set([H|T],[H|T]).
2213
2214 pairs_to_list([_],Value) --> !,[Value].
2215 pairs_to_list([_|Rest],(L,R)) -->
2216 pairs_to_list(Rest,L),[R].
2217
2218
2219 sort_tla_fields([],_,[],[]).
2220 sort_tla_fields([Field|RFields],ValueFields,RFieldTypes,ResultValueFields) :-
2221 ( Field=field(Name,Type) -> true
2222 ; Field= opt(Name,Type) -> true),
2223 ( selectchk(field(Name,Value),ValueFields,RestValueFields),
2224 field_value_present(Field,Value,Result) ->
2225 % Found the field in the record value
2226 RFieldTypes = [field(Name,Type) |RestFields],
2227 ResultValueFields = [field(Name,Result)|RestValues],
2228 sort_tla_fields(RFields,RestValueFields,RestFields,RestValues)
2229 ;
2230 % didn't found the field in the value -> igore
2231 sort_tla_fields(RFields,ValueFields,RFieldTypes,ResultValueFields)
2232 ).
2233 field_value_present(field(_,_),RecValue,RecValue). % Obligatory fields are always present
2234 field_value_present(opt(_,_),OptValue,Value) :-
2235 % Optional fields are present if the field is of the form TRUE |-> Value.
2236 ( is_printable_set(OptValue,Values) -> Values=[(_TRUE,Value)]
2237 ;
2238 add_error(translate,'exptected set for TLA optional record field'),
2239 fail
2240 ).
2241
2242 pp_tla_with_sep(Start,End,Sep,Type,Values) -->
2243 ppcodes(Start),pp_tla_with_sep_aux(Values,End,Sep,Type).
2244 pp_tla_with_sep_aux([],End,_Sep,_Type) -->
2245 ppcodes(End).
2246 pp_tla_with_sep_aux([Value|Rest],End,Sep,Type) -->
2247 % If a single type is given, we interpret it as the type
2248 % for each element of the list, if it is a list, we interpret
2249 % it one different type for every value in the list.
2250 { (Type=[CurrentType|RestTypes] -> true ; CurrentType = Type, RestTypes=Type) },
2251 pp_tla_value(CurrentType,Value),
2252 ( {Rest=[_|_]} -> ppcodes(Sep); {true} ),
2253 pp_tla_with_sep_aux(Rest,End,Sep,RestTypes).
2254
2255
2256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2257 % pretty-print a value
2258
2259 translate_bvalue_for_dot(string(S),Translation) :- !,
2260 % normal quotes confuse dot
2261 %ajoin(['''''',S,''''''],Translation).
2262 string_escape(S,ES),
2263 ajoin(['\\"',ES,'\\"'],Translation).
2264 translate_bvalue_for_dot(Val,ETranslation) :-
2265 translate_bvalue(Val,Translation),
2266 string_escape(Translation,ETranslation).
2267
2268 translate_bvalue_to_codes(V,Output) :-
2269 ( pp_value(V,_LimitReached,Codes,[]) ->
2270 Output=Codes
2271 ; add_error(translate_bvalue_to_codes,'Could not translate bvalue: ',V),
2272 Output="???").
2273 translate_bvalue_to_codes_with_limit(V,Limit,Output) :-
2274 set_up_limit_reached(Codes,Limit,LimitReached), % TODO: also limit expand_avl_upto
2275 ( pp_value(V,LimitReached,Codes,[]) ->
2276 Output=Codes
2277 ; add_error(translate_bvalue_to_codes,'Could not translate bvalue: ',V),
2278 Output="???").
2279
2280 translate_bvalue(V,Output) :-
2281 %set_up_limit_reached(Codes,1000000,LimitReached), % we could set a very high-limit, like max_atom_length
2282 ( pp_value(V,_LimitReached,Codes,[]) ->
2283 atom_codes_with_limit(Output,Codes) % just catches representation error
2284 ; add_error(translate_bvalue,'Could not translate bvalue: ',V),
2285 Output='???').
2286 :- use_module(preferences).
2287 translate_bvalue_with_limit(V,Limit,Output) :-
2288 get_preference(expand_avl_upto,Max),
2289 ((Max > Limit % no sense in printing larger AVL trees
2290 ; (Max < 0, Limit >= 0)) % or setting limit to -1 for full value
2291 -> temporary_set_preference(expand_avl_upto,Limit,CHNG)
2292 ; CHNG=false),
2293 call_cleanup(translate_bvalue_with_limit_aux(V,Limit,Output),
2294 reset_temporary_preference(expand_avl_upto,CHNG)).
2295 translate_bvalue_with_limit_aux(V,Limit,OutputAtom) :-
2296 set_up_limit_reached(Codes,Limit,LimitReached),
2297 ( pp_value(V,LimitReached,Codes,[]) ->
2298 atom_codes_with_limit(OutputAtom,Limit,Codes)
2299 % ,length(Codes,Len), (Len>Limit -> format('pp(~w) codes:~w, limit:~w, String=~s~n~n',[LimitReached,Len,Limit,Codes]) ; true)
2300 ; add_error(translate_bvalue_with_limit,'Could not translate bvalue: ',V),
2301 OutputAtom='???').
2302
2303 translate_bvalues(Values,Output) :-
2304 translate_bvalues_with_limit(Values,no_limit,Output). % we could set a very high-limit, like max_atom_length
2305
2306 translate_bvalues_with_limit(Values,Limit,Output) :-
2307 (Limit==no_limit -> true %
2308 ; set_up_limit_reached(Codes,Limit,LimitReached)
2309 ),
2310 pp_value_l(Values,',',LimitReached,Codes,[]),!,
2311 atom_codes_with_limit(Output,Codes).
2312 translate_bvalues_with_limit(Values,Limit,O) :-
2313 add_internal_error('Call failed: ',translate_bvalues(Values,Limit,O)), O='??'.
2314
2315 translate_bvalue_for_expression(Value,TExpr,Output) :-
2316 animation_minor_mode(tla),
2317 expression_has_tla_type(TExpr,TlaType),!,
2318 translate_bvalue_with_tlatype(Value,TlaType,Output).
2319 translate_bvalue_for_expression(Value,TExpr,Output) :-
2320 get_texpr_type(TExpr,Type),
2321 translate_bvalue_with_type(Value,Type,Output).
2322
2323 translate_bvalue_for_expression_with_limit(Value,TExpr,_Limit,Output) :-
2324 animation_minor_mode(tla),
2325 expression_has_tla_type(TExpr,TlaType),!,
2326 translate_bvalue_with_tlatype(Value,TlaType,Output). % TO DO: treat Limit
2327 translate_bvalue_for_expression_with_limit(Value,TExpr,Limit,Output) :-
2328 get_texpr_type(TExpr,Type),
2329 translate_bvalue_with_type_and_limit(Value,Type,Limit,Output).
2330
2331 expression_has_tla_type(TExpr,Type) :-
2332 get_texpr_info(TExpr,Infos),
2333 memberchk(tla_type(Type),Infos).
2334
2335
2336 translate_bvalue_to_parseable_classicalb(Val,Str) :-
2337 % corresponds to set_print_type_infos(needed)
2338 temporary_set_preference(translate_force_all_typing_infos,false,CHNG),
2339 temporary_set_preference(translate_print_typing_infos,true,CHNG2),
2340 (animation_minor_mode(X)
2341 -> remove_animation_minor_mode,
2342 call_cleanup(translate_bvalue_to_parseable_aux(Val,Str),
2343 (reset_temporary_preference(translate_force_all_typing_infos,CHNG),
2344 reset_temporary_preference(translate_print_typing_infos,CHNG2),
2345 set_animation_minor_mode(X)))
2346 ; call_cleanup(translate_bvalue_to_parseable_aux(Val,Str),
2347 (reset_temporary_preference(translate_force_all_typing_infos,CHNG),
2348 reset_temporary_preference(translate_print_typing_infos,CHNG2)))
2349 ).
2350 translate_bvalue_to_parseable_aux(Val,Str) :-
2351 call_pp_with_no_limit_and_parseable(translate_bvalue(Val,Str)).
2352
2353
2354 translate_bexpr_to_parseable(Expr,Str) :-
2355 call_pp_with_no_limit_and_parseable(translate_bexpression(Expr,Str)).
2356
2357 % a more refined pretty printing: takes Type information into account; useful for detecting sequences
2358 translate_bvalue_with_type(Value,_,Output) :- var(Value),!,
2359 translate_bvalue(Value,Output).
2360 translate_bvalue_with_type(Value,Type,Output) :-
2361 adapt_value_according_to_type(Type,Value,NewValue),
2362 translate_bvalue(NewValue,Output).
2363
2364 translate_bvalue_with_type_and_limit(Value,Type,Limit,Output) :-
2365 (Limit < 0 -> SetLim = -1 ; SetLim is Limit//2), % at least two symbols per element
2366 get_preference(expand_avl_upto,CurLim),
2367 ((CurLim < 0, SetLim >= 0) ; SetLim < CurLim),!,
2368 temporary_set_preference(expand_avl_upto,SetLim,CHNG),
2369 translate_bvalue_with_type_and_limit2(Value,Type,Limit,Output),
2370 reset_temporary_preference(expand_avl_upto,CHNG).
2371 translate_bvalue_with_type_and_limit(Value,Type,Limit,Output) :-
2372 translate_bvalue_with_type_and_limit2(Value,Type,Limit,Output).
2373 translate_bvalue_with_type_and_limit2(Value,_,Limit,Output) :- var(Value),!,
2374 translate_bvalue_with_limit(Value,Limit,Output).
2375 translate_bvalue_with_type_and_limit2(Value,Type,Limit,Output) :-
2376 adapt_value_according_to_type(Type,Value,NewValue),
2377 translate:translate_bvalue_with_limit(NewValue,Limit,Output).
2378 %debug:watch(translate:translate_bvalue_with_limit(NewValue,Limit,Output)).
2379
2380 adapt_value_according_to_type(T,V,R) :-
2381 (adapt_value_according_to_type3(T,V,R) -> true
2382 ; add_error(translate,'Value does not have the expected type:',V),
2383 R=V
2384 ).
2385 :- use_module(avl_tools,[quick_avl_approximate_size/2]).
2386 adapt_value_according_to_type3(_,Var,R) :- var(Var),!,R=Var.
2387 adapt_value_according_to_type3(T,V,R) :- var(T),!,
2388 add_internal_error('Variable type: ',adapt_value_according_to_type3(T,V,R)),
2389 R=V.
2390 adapt_value_according_to_type3(integer,V,R) :- !,R=V.
2391 adapt_value_according_to_type3(string,V,R) :- !,R=V.
2392 adapt_value_according_to_type3(boolean,V,R) :- !,R=V.
2393 adapt_value_according_to_type3(global(_),V,R) :- !,R=V.
2394 adapt_value_according_to_type3(couple(TA,TB),(VA,VB),R) :- !, R=(RA,RB),
2395 adapt_value_according_to_type(TA,VA,RA),
2396 adapt_value_according_to_type(TB,VB,RB).
2397 adapt_value_according_to_type3(set(Type),avl_set(A),Res) :- check_is_non_empty_avl(A),
2398 quick_avl_approximate_size(A,S),S<20,
2399 custom_explicit_sets:expand_custom_set_to_list(avl_set(A),List),!,
2400 maplist(adapt_value_according_to_type3(Type),List,Res).
2401 adapt_value_according_to_type3(set(_Type),V,R) :- !,R=V.
2402 adapt_value_according_to_type3(seq(Type),V,R) :- !, % the type tells us it is a sequence
2403 (convert_set_into_sequence(V,VS)
2404 -> l_adapt_value_according_to_type3(VS,Type,AVS),
2405 R=sequence(AVS)
2406 ; R=V).
2407 adapt_value_according_to_type3(record(Fields),rec(Values),R) :- !,
2408 R=rec(AdaptedValues),
2409 % fields and values should be in the same (alphabetical) order
2410 maplist(adapt_record_field_according_to_type,Fields,Values,AdaptedValues).
2411 adapt_value_according_to_type3(freetype(_),Value,R) :-
2412 Value = freeval(ID,_,Term),
2413 nonvar(Term), Term=term(ID), % not a constructor, just a value
2414 !,
2415 R = Value.
2416 adapt_value_according_to_type3(freetype(_),freeval(ID,Case,SubValue),R) :- nonvar(Case),
2417 !,
2418 R = freeval(ID,Case,AdaptedSubValue),
2419 (kernel_freetypes:get_freeval_type(ID,Case,SubType)
2420 -> adapt_value_according_to_type(SubType,SubValue,AdaptedSubValue)
2421 ; write(could_not_get_freeval_type(ID,Case)),nl,
2422 AdaptedSubValue = SubValue
2423 ).
2424 adapt_value_according_to_type3(freetype(_),Value,R) :- !, R=Value.
2425 adapt_value_according_to_type3(any,Value,R) :- !, R=Value.
2426 adapt_value_according_to_type3(pred,Value,R) :- !, R=Value.
2427 adapt_value_according_to_type3(_,term(V),R) :- !, R=term(V). % appears for unknown values (no_value_for) when ALLOW_INCOMPLETE_SETUP_CONSTANTS is true
2428 adapt_value_according_to_type3(Type,Value,R) :- write(adapt_value_according_to_type_unknown(Type,Value)),nl,
2429 R=Value.
2430
2431 l_adapt_value_according_to_type3([],_Type,R) :- !,R=[].
2432 l_adapt_value_according_to_type3([H|T],Type,[AH|AT]) :-
2433 adapt_value_according_to_type3(Type,H,AH),
2434 l_adapt_value_according_to_type3(T,Type,AT).
2435
2436 adapt_record_field_according_to_type(field(Name,HTy),field(Name2,H),field(Name,R)) :-
2437 (Name=Name2 -> adapt_value_according_to_type3(HTy,H,R)
2438 ; ajoin(['Record field ',Name,' does not match expected name from type:'],Msg),
2439 add_error(translate,Msg,Name2),fail
2440 ).
2441
2442 % ----------------------
2443
2444 % a simple way to print a B value in an indented fashion to a stream
2445 % currently only supports sets at top-level
2446 nested_print_bvalue(Stream,Value,ExpandAvlUpTo) :-
2447 temporary_set_preference(expand_avl_upto,ExpandAvlUpTo,CHNG),
2448 call_cleanup(nested_print_bvalue3(Stream,Value,0),
2449 reset_temporary_preference(expand_avl_upto,CHNG)).
2450
2451 nested_print_bvalue3(Stream,Value,Indent) :- nonvar(Value), Value=avl_set(A), !, % TODO: also detect sequences
2452 avl_domain(A,List),
2453 def_inc_indent(Indent,NIndent),
2454 print_indent(Stream,NIndent),write(Stream,'{'), nl(Stream),
2455 l_nested_print_bvalue(List,Stream,',',NIndent),
2456 print_indent(Stream,NIndent),write(Stream,'}'), nl(Stream).
2457 nested_print_bvalue3(Stream,Value,Indent) :-
2458 translate_bvalue_to_codes(Value,Codes),
2459 print_indent(Stream,Indent), format(Stream,'~s',[Codes]).
2460
2461 l_nested_print_bvalue([],Stream,_,_) :- nl(Stream).
2462 l_nested_print_bvalue([H|T],Stream,Sep,Indent) :-
2463 nested_print_bvalue3(Stream,H,Indent),
2464 (T=[] -> nl(Stream)
2465 ; format(Stream,'~w~n',[Sep]),
2466 l_nested_print_bvalue(T,Stream,Sep,Indent)).
2467
2468 % -----------------------
2469 pp_value_with_type(E,T,LimitReached) --> {adapt_value_according_to_type(T,E,AdaptedE)},
2470 pp_value(AdaptedE,LimitReached).
2471
2472 pp_value(V,In,Out) :-
2473 set_up_limit_reached(In,1000,LimitReached),
2474 pp_value(V,LimitReached,In,Out).
2475
2476 % LimitReached is a flag: when it is grounded to limit_reached this instructs pp_value to stop generating output
2477 pp_value(_,LimitReached) --> {LimitReached==limit_reached},!, "...".
2478 pp_value(V,_) --> {var(V)},!, pp_variable(V).
2479 pp_value('$VAR'(N),_) --> !,pp_numberedvar(N).
2480 pp_value(fd(X,GSet),_) --> {var(X)},!,
2481 ppatom(GSet),":", ppnumber(X). %":??".
2482 pp_value(fd(X,GSet),_) -->
2483 {b_global_sets:is_b_global_constant_hash(GSet,X,Res)},!,
2484 pp_identifier(Res).
2485 pp_value(fd(X,GSet),_) --> {deferred_set_constant(GSet,X,Cst)},!,
2486 pp_identifier(Cst).
2487 pp_value(fd(X,M),_) --> !,ppatom_opt_scramble(M),ppnumber(X).
2488 pp_value(int(X),_) --> !,ppnumber(X).
2489 pp_value(term(floating(X)),_) --> !,ppnumber(X).
2490 pp_value(string(X),_) --> !,string_start_symbol,ppstring_opt_scramble(X),string_end_symbol.
2491 pp_value(global_set(X),_) --> {atomic(X),integer_set_mapping(X,Kind,Y)},!,
2492 ({Kind=integer_set} -> ppatom(Y) ; ppatom_opt_scramble(X)).
2493 pp_value(term(X),_) --> {var(X)},!,"term(",pp_variable(X),")".
2494 pp_value(freetype(X),_) --> {pretty_freetype(X,P)},!,ppatom_opt_scramble(P).
2495 pp_value(pred_true /* bool_true */,_) --> %!,"TRUE". % TO DO: in latex_mode: surround by mathit
2496 {constants_in_mode(pred_true,Symbol)},!,ppatom(Symbol).
2497 pp_value(pred_false /* bool_false */,_) --> %!,"FALSE".
2498 {constants_in_mode(pred_false,Symbol)},!,ppatom(Symbol).
2499 %pp_value(bool_true) --> !,"TRUE". % old version; still in some test traces which are printed
2500 %pp_value(bool_false) --> !,"FALSE".
2501 pp_value([],_) --> !,empty_set_symbol.
2502 pp_value(closure(Variables,Types,Predicate),LimitReached) --> !,
2503 pp_closure_value(Variables,Types,Predicate,LimitReached).
2504 pp_value(avl_set(A),LimitReached) --> !,
2505 {check_is_non_empty_avl(A),
2506 avl_size(A,Sz) % we could use quick_avl_approximate_size for large sets
2507 },
2508 {set_brackets(LBrace,RBrace)},
2509 ( {size_is_in_set_limit(Sz),
2510 %(Sz>2 ; get_preference(translate_print_all_sequences,true)),
2511 get_preference(translate_print_all_sequences,true), % no longer try and convert any sequence longer than 2 to sequence notation
2512 avl_max(A,(int(Sz),_)), % a sequence has minimum int(1) and maximum int(Sz)
2513 convert_avlset_into_sequence(A,Seq)} ->
2514 pp_sequence(Seq,LimitReached)
2515 ;
2516 ( {Sz=0} -> left_set_bracket," /* empty avl_set */ ",right_set_bracket
2517 ; {(size_is_in_set_limit(Sz) ; Sz < 3)} -> % if Sz 3 we will print at least two elements anyway
2518 {avl_domain(A,List)},
2519 ppatom(LBrace),pp_value_l(List,',',LimitReached),ppatom(RBrace)
2520 ; {(Sz<5 ; \+ size_is_in_set_limit(4))} ->
2521 {avl_min(A,Min),avl_max(A,Max)},
2522 hash_card_symbol, % "#"
2523 ppnumber(Sz),":", left_set_bracket,
2524 pp_value(Min,LimitReached),",",ldots,",",pp_value(Max,LimitReached),right_set_bracket
2525 ;
2526 {avl_min(A,Min),avl_next(Min,A,Nxt),avl_max(A,Max),avl_prev(Max,A,Prev)},
2527 hash_card_symbol, % "#",
2528 ppnumber(Sz),":", left_set_bracket,
2529 pp_value(Min,LimitReached),",",pp_value(Nxt,LimitReached),",",ldots,",",
2530 pp_value(Prev,LimitReached),",",pp_value(Max,LimitReached),right_set_bracket )).
2531 pp_value( (A,B) ,LimitReached) --> !,
2532 "(",pp_inner_value(A,LimitReached),
2533 maplet_symbol,
2534 pp_value(B,LimitReached),")".
2535 pp_value(field(Name,Value),LimitReached) --> !,
2536 pp_identifier(Name),":",pp_value(Value,LimitReached). % : for fields has priority 120 in French manual
2537 pp_value(rec(Rec),LimitReached) --> !,
2538 {function_like_in_mode(rec,Symbol)},
2539 ppatom(Symbol), "(",pp_value_l(Rec,',',LimitReached),")".
2540 pp_value(struct(Rec),LimitReached) --> !,
2541 {function_like_in_mode(struct,Symbol)},
2542 ppatom(Symbol), "(", pp_value_l(Rec,',',LimitReached),")".
2543 % check for cyclic after avl_set / closure case: AVL sets can be huge !
2544 pp_value(X,_) --> {cyclic_term(X),functor(X,F,_N)},!,
2545 underscore_symbol,"cyclic",underscore_symbol,
2546 ppatom(F),underscore_symbol.
2547 pp_value(sequence(List),LimitReached) --> !,
2548 ({List=[]} -> pp_empty_sequence ; pp_sequence_with_limit(List,LimitReached)).
2549 pp_value([Head|Tail],LimitReached) --> {get_preference(translate_print_all_sequences,true),
2550 convert_set_into_sequence([Head|Tail],Elements)},
2551 !,
2552 pp_sequence(Elements,LimitReached).
2553 pp_value([Head|Tail],LimitReached) --> !, {set_brackets(L,R)},
2554 ppatom(L),
2555 pp_value_l_with_limit([Head|Tail],',',LimitReached),
2556 ppatom(R).
2557 %pp_value([Head|Tail]) --> !,
2558 % {( convert_set_into_sequence([Head|Tail],Elements) ->
2559 % (Start,End) = ('[',']')
2560 % ;
2561 % Elements = [Head|Tail],
2562 % (Start,End) = ('{','}'))},
2563 % ppatom(Start),pp_value_l(Elements,','),ppatom(End).
2564 pp_value(term(no_value_for(Id)),_) --> !,
2565 "undefined ",ppatom(Id).
2566 pp_value(freeval(Freetype,Case,Value),LimitReached) --> !,
2567 ({ground(Case),ground(Value),Value=term(Case)} -> ppatom_opt_scramble(Case)
2568 ; {ground(Case)} -> ppatom_opt_scramble(Case),"(",pp_value(Value,LimitReached),")"
2569 ; {pretty_freetype(Freetype,P)},
2570 "FREEVALUE[",ppatom_opt_scramble(P),
2571 ",",write_to_codes(Case),
2572 "](",pp_value(Value,LimitReached),")"
2573 ).
2574 pp_value(X,_) --> {animation_mode(xtl)},!,
2575 write_to_codes(X).
2576 pp_value(term('$MATCH'),_) --> !, gen_term_color(magenta),"*",gen_term_color(reset). % MATCH found by find_value
2577 pp_value(term('$FUZZYMATCH'(S)),_) --> !, gen_term_color(magenta), % ditto find_value
2578 "*",ppatom(S),"*",gen_term_color(reset).
2579 pp_value(X,_) --> % the << >> pose problems when checking against FDR
2580 "<< ",write_to_codes(X)," >>".
2581
2582 pp_variable(V) --> write_to_codes(V). %underscore_symbol.
2583
2584 :- use_module(closures,[is_recursive_closure/3]).
2585
2586 pp_closure_value(Ids,Type,B,_LimitReached) -->
2587 {var(Ids) ; var(Type) ; var(B)},!,
2588 add_internal_error('Illegal value: ',pp_value_illegal_closure(Ids,Type,B)),
2589 "<< ILLEGAL ",write_to_codes(closure(Ids,Type,B))," >>".
2590 pp_closure_value(Variables,Types,Predicate,LimitReached) --> {\+ size_is_in_set_limit(1)},
2591 !, % do not print body; just print hash value
2592 {make_closure_ids(Variables,Types,Ids), term_hash(Predicate,PH)},
2593 left_set_bracket, % { Ids | #PREDICATE#(HASH) }
2594 pp_expr_l_pair_in_mode(Ids,LimitReached),
2595 pp_such_that_bar,
2596 " ",hash_card_symbol,"PREDICATE",hash_card_symbol,"(",ppnumber(PH),") ", right_set_bracket.
2597 pp_closure_value(Variables,Types,Predicate,LimitReached) -->
2598 {get_preference(translate_ids_to_parseable_format,true),
2599 is_recursive_closure(Variables,Types,Predicate),
2600 get_texpr_info(Predicate,Infos),
2601 member(prob_annotation(recursive(TID)),Infos),
2602 def_get_texpr_id(TID,ID)}, !,
2603 % write recursive let for f as : CHOOSE(.) or MU({f|f= SET /*@desc letrec */ })
2604 % an alternate syntax could be RECLET f BE f = SET IN f END
2605 "MU({", pp_identifier(ID), % TODO: we can now use the post-fix mu_operator '?'
2606 "|",
2607 pp_identifier(ID)," = ",
2608 pp_closure_value2(Variables,Types,Predicate,LimitReached),
2609 "/*@desc letrec */ }) ".
2610 pp_closure_value([Id],[Type],Membership,LimitReached) -->
2611 { get_texpr_expr(Membership,member(Elem,Set)),
2612 get_texpr_id(Elem,Id),
2613 \+ occurs_in_expr(Id,Set), % detect things like {s|s : 1 .. card(s) --> T} (test 1030)
2614 get_texpr_type(Elem,Type),
2615 !},
2616 pp_expr_m(Set,299,LimitReached).
2617 pp_closure_value(Variables,Types,Predicate,LimitReached) --> pp_closure_value2(Variables,Types,Predicate,LimitReached).
2618
2619 pp_closure_value2(Variables,Types,Predicate,LimitReached) --> !,
2620 {make_closure_ids(Variables,Types,Ids)},
2621 pp_comprehension_set(Ids,Predicate,[],LimitReached). % TODO: propagate LimitReached
2622
2623 % avoid printing parentheses:
2624 % (x,y,z) = ((x,y),z)
2625 pp_inner_value( AB , LimitReached) --> {nonvar(AB),AB=(A,B)}, !, % do not print parentheses in this context
2626 pp_inner_value(A,LimitReached),maplet_symbol,
2627 pp_value(B,LimitReached).
2628 pp_inner_value( Value , LimitReached) --> pp_value( Value , LimitReached).
2629
2630 size_is_in_set_limit(Size) :- get_preference(expand_avl_upto,Max),
2631 (Max<0 -> true /* no limit */
2632 ; Size =< Max).
2633
2634 dcg_set_up_limit_reached(Limit,LimitReached,InList,InList) :- set_up_limit_reached(InList,Limit,LimitReached).
2635
2636 % instantiate LimitReached argument as soon as a list exceeds a certain limit
2637 set_up_limit_reached(_,Neg,_) :- Neg<0,!. % negative number means unlimited
2638 set_up_limit_reached(_,0,LimitReached) :- !, LimitReached = limit_reached.
2639 set_up_limit_reached(List,Limit,LimitReached) :-
2640 block_set_up_limit_reached(List,Limit,LimitReached).
2641 :- block block_set_up_limit_reached(-,?,?).
2642 block_set_up_limit_reached([],_,_).
2643 block_set_up_limit_reached([_|T],Limit,LimitReached) :-
2644 (Limit<1 -> LimitReached=limit_reached
2645 ; L1 is Limit-1, block_set_up_limit_reached(T,L1,LimitReached)).
2646
2647 % pretty print LimitReached, requires %:- block block_set_up_limit_reached(-,?,-).
2648 /*
2649 pp_lr(LR) --> {LR==limit_reached},!, " *LR* ".
2650 pp_lr(LR) --> {frozen(LR,translate:block_set_up_limit_reached(_,Lim,_))},!, " ok(", ppnumber(Lim),") ".
2651 pp_lr(LR) --> {frozen(LR,G)},!, " ok(", ppterm(G),") ".
2652 pp_lr(_) --> " ok ".
2653 */
2654
2655
2656 pp_value_l_with_limit(V,Sep,LimitReached) --> {get_preference(expand_avl_upto,Max)},
2657 pp_value_l(V,Sep,Max,LimitReached).
2658 pp_value_l(V,Sep,LimitReached) --> pp_value_l(V,Sep,-1,LimitReached).
2659
2660 pp_value_l(V,_Sep,_,_) --> {var(V)},!,"...".
2661 pp_value_l(_,_,_,LimitReached) --> {LimitReached==limit_reached},!,"...".
2662 pp_value_l('$VAR'(N),_Sep,_,_) --> !,"}\\/{",pp_numberedvar(N),"}".
2663 pp_value_l([],_Sep,_,_) --> !.
2664 pp_value_l([Expr|Rest],Sep,Limit,LimitReached) -->
2665 ( {nonvar(Rest),Rest=[]} ->
2666 pp_value(Expr,LimitReached)
2667 ; {Limit=0} -> "..."
2668 ;
2669 pp_value(Expr,LimitReached),
2670 % no separator for closure special case
2671 ({nonvar(Rest) , Rest = closure(_,_,_)} -> {true} ; ppatom(Sep)) ,
2672 {L1 is Limit-1} ,
2673 % convert avl_set(_) in a list's tail to a Prolog list
2674 {nonvar(Rest) , Rest = avl_set(_) -> custom_explicit_sets:expand_custom_set_to_list(Rest,LRest) ; LRest = Rest} ,
2675 pp_value_l(LRest,Sep,L1,LimitReached)).
2676 pp_value_l(avl_set(A),_Sep,_,LimitReached) --> pp_value(avl_set(A),LimitReached).
2677 pp_value_l(closure(A,B,C),_Sep,_,LimitReached) --> "}\\/", pp_value(closure(A,B,C),LimitReached).
2678
2679 make_closure_ids([],[],[]).
2680 make_closure_ids([V|Vrest],[T|Trest],[TExpr|TErest]) :-
2681 (var(V) -> V2='_', format('Illegal variable identifier in make_closure_ids: ~w~n',[V])
2682 ; V2=V),
2683 create_texpr(identifier(V2),T,[],TExpr),
2684 make_closure_ids(Vrest,Trest,TErest).
2685
2686 % symbol for starting and ending a sequence:
2687 pp_begin_sequence --> {animation_minor_mode(tla)},!,"<<".
2688 pp_begin_sequence --> {get_preference(translate_print_cs_style_sequences,true)},!,"".
2689 pp_begin_sequence --> "[".
2690 pp_end_sequence --> {animation_minor_mode(tla)},!,">>".
2691 pp_end_sequence --> {get_preference(translate_print_cs_style_sequences,true)},!,"".
2692 pp_end_sequence --> "]".
2693
2694 pp_separator_sequence('') :- get_preference(translate_print_cs_style_sequences,true),!.
2695 pp_separator_sequence(',').
2696
2697 % string for empty sequence
2698 pp_empty_sequence --> {animation_minor_mode(tla)},!, "<< >>".
2699 pp_empty_sequence --> {get_preference(translate_print_cs_style_sequences,true)},!,
2700 ( {latex_mode} -> "\\lambda" ; [955]). % 955 is lambda symbol in Unicode
2701 pp_empty_sequence --> {atelierb_mode(prover(_))},!, "{}".
2702 pp_empty_sequence --> "[]".
2703
2704 % symbols for function application:
2705 pp_function_left_bracket --> {animation_minor_mode(tla)},!, "[".
2706 pp_function_left_bracket --> "(".
2707
2708 pp_function_right_bracket --> {animation_minor_mode(tla)},!, "]".
2709 pp_function_right_bracket --> ")".
2710
2711 pp_sequence(Elements,LimitReached) --> {pp_separator_sequence(Sep)},
2712 pp_begin_sequence,
2713 pp_value_l(Elements,Sep,LimitReached),
2714 pp_end_sequence.
2715 pp_sequence_with_limit(Elements,LimitReached) --> {pp_separator_sequence(Sep)},
2716 pp_begin_sequence,
2717 pp_value_l_with_limit(Elements,Sep,LimitReached),
2718 pp_end_sequence.
2719
2720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2721 % machines
2722
2723 :- use_module(eventhandling,[register_event_listener/3]).
2724 :- register_event_listener(clear_specification,reset_translate,
2725 'Reset Translation Caches.').
2726 reset_translate :- retractall(bugly_scramble_id_cache(_,_)), retractall(non_det_constants(_,_)).
2727 %reset_translate :- set_print_type_infos(none),
2728 % set_preference(translate_suppress_rodin_positions_flag,false).
2729
2730 suppress_rodin_positions(CHNG) :- set_suppress_rodin_positions(true,CHNG).
2731 set_suppress_rodin_positions(Value,CHNG) :-
2732 temporary_set_preference(translate_suppress_rodin_positions_flag,Value,CHNG).
2733 reset_suppress_rodin_positions(CHNG) :-
2734 reset_temporary_preference(translate_suppress_rodin_positions_flag,CHNG).
2735
2736 set_print_type_infos(none) :- !,
2737 set_preference(translate_force_all_typing_infos,false),
2738 set_preference(translate_print_typing_infos,false).
2739 set_print_type_infos(needed) :- !,
2740 set_preference(translate_force_all_typing_infos,false),
2741 set_preference(translate_print_typing_infos,true).
2742 set_print_type_infos(all) :- !,
2743 set_preference(translate_force_all_typing_infos,true),
2744 set_preference(translate_print_typing_infos,true).
2745 set_print_type_infos(Err) :-
2746 add_internal_error('Illegal typing setting: ',set_print_type_infos(Err)).
2747
2748 type_info_setting(none,false,false).
2749 type_info_setting(needed,false,true).
2750 type_info_setting(all,true,true).
2751
2752 set_print_type_infos(Setting,[CHNG1,CHNG2]) :-
2753 type_info_setting(Setting,Value1,Value2),!,
2754 temporary_set_preference(translate_force_all_typing_infos,Value1,CHNG1),
2755 temporary_set_preference(translate_print_typing_infos,Value2,CHNG2).
2756 set_print_type_infos(Err,_) :-
2757 add_internal_error('Illegal typing setting: ',set_print_type_infos(Err,_)),fail.
2758 reset_print_type_infos([CHNG1,CHNG2]) :-
2759 reset_temporary_preference(translate_force_all_typing_infos,CHNG1),
2760 reset_temporary_preference(translate_print_typing_infos,CHNG2).
2761
2762 :- use_module(tools_files,[put_codes/2]).
2763 print_machine(M) :-
2764 nl, translate_machine(M,Msg,true), put_codes(Msg,user_output), nl,
2765 flush_output(user_output),!.
2766 print_machine(M) :- add_internal_error('Printing failed: ',print_machine(M)).
2767
2768 %
2769 translate_machine(M,Codes,AdditionalInfo) :-
2770 retractall(print_additional_machine_info),
2771 (AdditionalInfo=true -> assertz(print_additional_machine_info) ; true),
2772 call_pp_with_no_limit_and_parseable(translate_machine1(M,(0,Codes),(_,[]))).
2773
2774 % perform a call by forcing parseable output and removing limit to set
2775 call_pp_with_no_limit_and_parseable(PP_Call) :-
2776 temporary_set_preference(translate_ids_to_parseable_format,true,CHNG),
2777 temporary_set_preference(expand_avl_upto,-1,CHNG2),
2778 call_cleanup(call(PP_Call),
2779 (reset_temporary_preference(translate_ids_to_parseable_format,CHNG),
2780 reset_temporary_preference(expand_avl_upto,CHNG2))).
2781
2782
2783 % useful if we wish to translate just a selection of sections without MACHINE/END
2784 translate_section_list(SL,Codes) :- init_machine_translation,
2785 translate_machine2(SL,SL,no_end,(0,Codes),(_,[])).
2786
2787 translate_machine1(machine(Name,Sections)) -->
2788 indent('MACHINE '), {adapt_machine_name(Name,AName), pp_identifier(AName,CName,[])}, insertcodes(CName),
2789 {init_machine_translation},
2790 translate_machine2(Sections,Sections,end).
2791 translate_machine2([],_,end) --> !, insertstr('\nEND\n').
2792 translate_machine2([],_,_) --> !, insertstr('\n').
2793 translate_machine2([P|Rest],All,End) -->
2794 translate_mpart(P,All),
2795 translate_machine2(Rest,All,End).
2796
2797 adapt_machine_name('dummy(uses)',R) :- !,R='MAIN'.
2798 adapt_machine_name(X,X).
2799
2800 :- dynamic section_header_generated/1.
2801 :- dynamic print_additional_machine_info/0.
2802 print_additional_machine_info.
2803
2804 init_machine_translation :- retractall(section_header_generated(_)).
2805
2806 % start a part of a section
2807 mpstart(Title,I) -->
2808 insertstr('\n'),insertstr(Title),
2809 indention_level(I,I2), {I2 is I+2}.
2810 % end a part of a section
2811 mpend(I) -->
2812 indention_level(_,I).
2813
2814 mpstart_section(Section,Title,AltTitle,I,In,Out) :-
2815 (\+ section_header_generated(Section)
2816 -> mpstart(Title,I,In,Out), assertz(section_header_generated(Section))
2817 ; mpstart(AltTitle,I,In,Out) /* use alternative title; section header already generated */
2818 ).
2819
2820 translate_mpart(Section/I,All) --> %{write(Section),nl},
2821 ( {I=[]} -> {true}
2822 ; translate_mpart2(Section,I,All) -> {true}
2823 ;
2824 insertstr('\nSection '),insertstr(Section),insertstr(': '),
2825 insertstr('<< pretty-print failed >>')
2826 ).
2827 translate_mpart2(deferred_sets,I,_) -->
2828 mpstart_section(sets,'SETS /* deferred */',' ; /* deferred */',P),
2829 indent_expr_l_sep(I,';'),mpend(P).
2830 translate_mpart2(enumerated_sets,_I,_) --> []. % these are now pretty printed below
2831 %mpstart('ENUMERATED SETS',P),indent_expr_l_sep(I,';'),mpend(P).
2832 translate_mpart2(enumerated_elements,I,_) --> %{write(enum_els(I)),nl},
2833 {translate_enums(I,[],Res)},
2834 mpstart_section(sets,'SETS /* enumerated */',' ; /* enumerated */',P),
2835 indent_expr_l_sep(Res,';'),mpend(P).
2836 translate_mpart2(parameters,I,_) --> mpstart('PARAMETERS',P),indent_expr_l_sep(I,','),mpend(P).
2837 translate_mpart2(internal_parameters,I,_) --> {print_additional_machine_info},!,
2838 mpstart('/* INTERNAL_PARAMETERS',P),indent_expr_l_sep(I,','),insertstr(' */'),mpend(P).
2839 translate_mpart2(internal_parameters,_I,_) --> [].
2840 translate_mpart2(abstract_variables,I,_) --> mpstart('ABSTRACT_VARIABLES',P),indent_exprs(I),mpend(P).
2841 translate_mpart2(concrete_variables,I,_) --> mpstart('CONCRETE_VARIABLES',P),indent_exprs(I),mpend(P).
2842 translate_mpart2(abstract_constants,I,_) --> mpstart('ABSTRACT_CONSTANTS',P),indent_exprs(I),mpend(P).
2843 translate_mpart2(concrete_constants,I,_) --> mpstart('CONCRETE_CONSTANTS',P),indent_exprs(I),mpend(P).
2844 translate_mpart2(promoted,I,_) --> {print_additional_machine_info},!,
2845 mpstart('/* PROMOTED OPERATIONS',P),indent_expr_l_sep(I,','),insertstr(' */'),mpend(P).
2846 translate_mpart2(promoted,_I,_) --> [].
2847 translate_mpart2(unpromoted,I,_) --> {print_additional_machine_info},!,
2848 mpstart('/* NOT PROMOTED OPERATIONS',P),indent_expr_l_sep(I,','),insertstr(' */'),mpend(P).
2849 translate_mpart2(unpromoted,_I,_) --> [].
2850 translate_mpart2(constraints,I,All) --> mpart_typing(constraints,[parameters],All,I).
2851 translate_mpart2(invariant,I,All) --> mpart_typing(invariant, [abstract_variables,concrete_variables],All,I).
2852 translate_mpart2(linking_invariant,_I,_) --> [].
2853 translate_mpart2(properties,I,All) --> mpart_typing(properties,[abstract_constants,concrete_constants],All,I).
2854 translate_mpart2(assertions,I,_) -->
2855 mpstart_spec_desc(assertions,P),
2856 %indent_expr_l_sep(I,';'),
2857 preds_over_lines(1,'@thm','; ',I),
2858 mpend(P). % TO DO:
2859 translate_mpart2(initialisation,S,_) --> mpstart_spec_desc(initialisation,P),translate_inits(S),mpend(P).
2860 ?translate_mpart2(definitions,Defs,_) --> {(standard_library_required(Defs,_) ; set_pref_used(Defs))},!,
2861 mpstart('DEFINITIONS',P),
2862 insertstr('\n'),
2863 {findall(Lib,standard_library_required(Defs,Lib),Libs)},
2864 insert_library_usages(Libs),
2865 translate_set_pref_defs(Defs),
2866 mpend(P),
2867 translate_other_defpart(Defs).
2868 translate_mpart2(definitions,Defs,_) --> !, translate_other_defpart(Defs).
2869 translate_mpart2(operation_bodies,Ops,_) --> mpstart_spec_desc(operations,P),translate_ops(Ops),mpend(P).
2870 translate_mpart2(used,Used,_) --> {print_additional_machine_info},!,
2871 mpstart('/* USED',P),translate_used(Used),insertstr(' */'),mpend(P).
2872 translate_mpart2(used,_Used,_) --> [].
2873 translate_mpart2(freetypes,Freetypes,_) -->
2874 mpstart('FREETYPES',P),translate_freetypes(Freetypes),mpend(P).
2875 translate_mpart2(meta,_Infos,_) --> [].
2876 translate_mpart2(operators,Operators,_) -->
2877 insertstr('\n/* Event-B operators:'), % */
2878 indention_level(I,I2), {I2 is I+2},
2879 translate_eventb_operators(Operators),
2880 indention_level(I2,I),
2881 insertstr('\n*/').
2882 translate_mpart2(values,Values,_) -->
2883 mpstart('VALUES',P),indent_expr_l_sep(Values,';'),mpend(P).
2884
2885 indent_exprs(I) --> {force_eventb_rodin_mode},!, indent_expr_l_sep(I,' '). % Event-B Camille style
2886 indent_exprs(I) --> indent_expr_l_sep(I,',').
2887
2888
2889 % Add typing predicates to a predicate
2890 mpart_typing(Title,Section,Sections,PredI) -->
2891 {mpart_typing2(Section,Sections,PredI,PredO)},
2892 ( {is_truth(PredO)} -> [] % TO DO: in animation_minor_mode(z) for INVARIANT: force adding typing predicates (translate_print_typing_infos)
2893 ;
2894 mpstart_spec_desc(Title,P),
2895 section_pred_over_lines(0,Title,PredO),
2896 mpend(P)).
2897
2898 mpstart_spec_desc(Title,P) --> {get_specification_description(Title,Atom)},!, mpstart(Atom,P).
2899 mpstart_spec_desc(Title,P) --> mpstart(Title,P).
2900
2901 mpart_typing2(Sections,AllSections,PredI,PredO) :-
2902 get_preference(translate_print_typing_infos,true),!,
2903 get_all_ids(Sections,AllSections,Ids),
2904 add_typing_predicates(Ids,PredI,PredO).
2905 mpart_typing2(_Section,_Sections,Pred,Pred).
2906
2907 get_all_ids([],_Sections,[]).
2908 get_all_ids([Section|Srest],Sections,Ids) :-
2909 memberchk(Section/Ids1,Sections),
2910 append(Ids1,Ids2,Ids),
2911 get_all_ids(Srest,Sections,Ids2).
2912
2913 add_optional_typing_predicates(Ids,In,Out) :-
2914 ( get_preference(translate_print_typing_infos,true) -> add_typing_predicates(Ids,In,Out)
2915 ? ; is_truth(In) -> add_typing_predicates(Ids,In,Out)
2916 ; In=Out).
2917
2918 add_normal_typing_predicates(Ids,In,Out) :- % used to call add_typing_predicates directly
2919 ? (add_optional_typing_predicates(Ids,In,Out) -> true
2920 ; add_internal_error('Failed: ',add_normal_typing_predicates(Ids)), In=Out).
2921
2922 add_typing_predicates([],P,P) :- !.
2923 add_typing_predicates(Ids,Pin,Pout) :-
2924 remove_already_typed_ids(Pin,Ids,UntypedIds),
2925 KeepSeq=false,
2926 ? generate_typing_predicates(UntypedIds,KeepSeq,Typing),
2927 conjunction_to_list(Pin,Pins),
2928 remove_duplicate_predicates(Typing,Pins,Typing2),
2929 append(Typing2,[Pin],Preds),
2930 conjunct_predicates(Preds,Pout).
2931
2932 remove_already_typed_ids(_TExpr,Ids,Ids) :-
2933 get_preference(translate_force_all_typing_infos,true),!.
2934 remove_already_typed_ids(TExpr,Ids,UntypedIds) :-
2935 get_texpr_expr(TExpr,Expr),!,
2936 remove_already_typed_ids2(Expr,Ids,UntypedIds).
2937 remove_already_typed_ids(TExpr,Ids,Res) :-
2938 add_internal_error('Not a typed expression: ',remove_already_typed_ids(TExpr,Ids,_)),
2939 Res=Ids.
2940 remove_already_typed_ids2(conjunct(A,B),Ids,UntypedIds) :- !,
2941 remove_already_typed_ids(A,Ids,I1),
2942 remove_already_typed_ids(B,I1,UntypedIds).
2943 remove_already_typed_ids2(lazy_let_pred(_,_,A),Ids,UntypedIds) :- !,
2944 remove_already_typed_ids(A,Ids,UntypedIds). % TO DO: check for variable clases with lazy_let ids ???
2945 remove_already_typed_ids2(Expr,Ids,UntypedIds) :-
2946 is_typing_predicate(Expr,Id),
2947 create_texpr(identifier(Id),_,_,TId),
2948 ? select(TId,Ids,UntypedIds),!.
2949 remove_already_typed_ids2(_,Ids,Ids).
2950 is_typing_predicate(member(A,_),Id) :- get_texpr_id(A,Id).
2951 is_typing_predicate(subset(A,_),Id) :- get_texpr_id(A,Id).
2952 is_typing_predicate(subset_strict(A,_),Id) :- get_texpr_id(A,Id).
2953
2954 remove_duplicate_predicates([],_Old,[]).
2955 remove_duplicate_predicates([Pred|Prest],Old,Result) :-
2956 (is_duplicate_predicate(Pred,Old) -> Result = Rest ; Result = [Pred|Rest]),
2957 remove_duplicate_predicates(Prest,Old,Rest).
2958 is_duplicate_predicate(Pred,List) :-
2959 ? remove_all_infos(Pred,Pattern),
2960 memberchk(Pattern,List).
2961
2962 :- use_module(typing_tools,[create_type_set/3]).
2963 generate_typing_predicates(TIds,Preds) :-
2964 generate_typing_predicates(TIds,true,Preds).
2965 generate_typing_predicates(TIds,KeepSeq,Preds) :-
2966 ? maplist(generate_typing_predicate(KeepSeq), TIds, Preds).
2967 generate_typing_predicate(KeepSeq,TId,Pred) :-
2968 get_texpr_type(TId,Type),
2969 remove_all_infos_and_ground(TId,TId2), % clear all infos
2970 (create_type_set(Type,KeepSeq,TSet) -> create_texpr(member(TId2,TSet),pred,[],Pred)
2971 ? ; TId = b(_,any,[raw]) -> is_truth(Pred) % this comes from transform_raw
2972 ; add_error(generate_typing_predicate,'Illegal type in identifier: ',Type,TId),
2973 is_truth(Pred)
2974 ).
2975
2976
2977
2978
2979 % translate enumerated constant list into enumerate set definition
2980 translate_enums([],Acc,Acc).
2981 translate_enums([EnumCst|T],Acc,Res) :- %get_texpr_id(EnumCst,Id),
2982 get_texpr_type(EnumCst,global(GlobalSet)),
2983 insert_enum_cst(Acc,EnumCst,GlobalSet,Acc2),
2984 translate_enums(T,Acc2,Res).
2985
2986 insert_enum_cst([],ID,Type,[enumerated_set_def(Type,[ID])]).
2987 insert_enum_cst([enumerated_set_def(Type,Lst)|T],ID,Type2,[enumerated_set_def(Type,Lst2)|TT]) :-
2988 (Type=Type2
2989 -> Lst2 = [ID|Lst], TT=T
2990 ; Lst2 = Lst, insert_enum_cst(T,ID,Type2,TT)
2991 ).
2992
2993 % pretty-print the initialisation section of a machine
2994 translate_inits(Inits) -->
2995 ( {is_list_simple(Inits)} ->
2996 translate_inits2(Inits)
2997 ;
2998 indention_level(I,I2),{I2 is I+2},
2999 translate_subst_begin_end(Inits),
3000 indention_level(_,I)).
3001 translate_inits2([]) --> !.
3002 translate_inits2([init(Name,Subst)|Rest]) -->
3003 indent('/* '),insertstr(Name),insertstr(': */ '),
3004 translate_subst_begin_end(Subst),
3005 translate_inits2(Rest).
3006
3007 translate_other_defpart(Defs) --> {print_additional_machine_info},!,
3008 mpstart('/* DEFINITIONS',P),translate_defs(Defs),insertstr(' */'),mpend(P).
3009 translate_other_defpart(_) --> [].
3010
3011 % pretty-print the definitions of a machine
3012 translate_defs([]) --> !.
3013 translate_defs([Def|Rest]) --> translate_def(Def),translate_defs(Rest).
3014 translate_def(definition_decl(Name,_,_DefType,_Pos,_Args,Expr,_Deps)) -->
3015 {dummy_def_body(Name,Expr)},!.
3016 % this is a DEFINITION from a standard library; do not show it
3017 translate_def(definition_decl(Name,DefType,_DefInfos,_Pos,Args,Expr,_Deps)) -->
3018 {def_description(DefType,Desc)}, indent(Desc),insertstr(Name),
3019 {transform_raw_list(Args,TArgs)},
3020 translate_op_params(TArgs),
3021 ( {show_def_body(Expr)}
3022 -> insertstr(' '),{translate_in_mode(eqeq,'==',EqEqStr)}, insertstr(EqEqStr), insertstr(' '),
3023 {transform_raw(Expr,TExpr)},
3024 (translate_def_body(DefType,TExpr) -> [] ; insertstr('CANNOT PRETTY PRINT'))
3025 ; {true}
3026 ),
3027 insertstr(';').
3028 def_description(substitution,'SUBSTITUTION ').
3029 def_description(expression,'EXPRESSION ').
3030 def_description(predicate,'PREDICATE ').
3031 translate_def_body(substitution,B) --> translate_subst_begin_end(B).
3032 translate_def_body(expression,B) --> indent_expr(B).
3033 translate_def_body(predicate,B) --> indent_expr(B).
3034
3035 show_def_body(integer(_,_)).
3036 show_def_body(boolean_true(_)).
3037 show_def_body(boolean_false(_)).
3038 % show_def_body(_) % comment in to pretty print all defs
3039
3040 % check if we have a dummy definition body from a ProB Library file for external functions:
3041 dummy_def_body(Name,Expr) :-
3042 functor(Expr,F,_), (F=external_function_call ; F=external_pred_call),
3043 arg(2,Expr,Name).
3044 %external_function_declarations:external_function_library(Name,NrArgs,DefType,_),length(Args,NrArgs)
3045
3046 % utility to print definitions in JSON format for use in a VisB file:
3047 % useful when converting a B DEFINITIONS file for use in Event-B, TLA+,...
3048 :- public print_defs_as_json/0.
3049 print_defs_as_json :-
3050 findall(json([name=string(Name), value=string(BS)]), (
3051 bmachine:b_get_definition_with_pos(Name,expression,_DefPos,_Args,RawExpr,_Deps),
3052 \+ dummy_def_body(Name,RawExpr),
3053 transform_raw(RawExpr,Body),
3054 translate_subst_or_bexpr(Body,BS)
3055 ), Defs),
3056 Json = json([svg=string(''), definitions=array(Defs)]),
3057 json_write_stream(Json).
3058
3059 ?set_pref_used(Defs) :- member(definition_decl(Name,_,_,_,[],_,_),Defs),
3060 (is_set_pref_def_name(Name,_,_) -> true).
3061
3062 is_set_pref_def_name(Name,Pref,CurValAtom) :-
3063 atom_codes(Name,Codes),append("SET_PREF_",RestCodes,Codes),
3064 atom_codes(Pref,RestCodes),
3065 ? (eclipse_preference(Pref,P) -> get_preference(P,CurVal), translate_pref_val(CurVal,CurValAtom)
3066 ; deprecated_eclipse_preference(Pref,_,NewP,Mapping) -> get_preference(NewP,V), member(CurVal/V,Mapping)
3067 ; get_preference(Pref,CurVal), translate_pref_val(CurVal,CurValAtom)),
3068 translate_pref_val(CurVal,CurValAtom).
3069 translate_pref_val(true,'TRUE').
3070 translate_pref_val(false,'FALSE').
3071 translate_pref_val(Nr,NrAtom) :- number(Nr),!, number_codes(Nr,C), atom_codes(NrAtom,C).
3072 translate_pref_val(Atom,Atom) :- atom(Atom).
3073
3074 is_set_pref(definition_decl(Name,_,_,_Pos,[],_Expr,_Deps)) :-
3075 is_set_pref_def_name(Name,_,_).
3076 translate_set_pref_defs(Defs) -->
3077 {include(is_set_pref,Defs,SPDefs),
3078 sort(SPDefs,SortedDefs)},
3079 translate_set_pref_defs1(SortedDefs).
3080 translate_set_pref_defs1([]) --> !.
3081 translate_set_pref_defs1([Def|Rest]) -->
3082 translate_set_pref_def(Def),translate_set_pref_defs1(Rest).
3083 translate_set_pref_def(definition_decl(Name,_,_,_Pos,[],_Expr,_Deps)) -->
3084 {is_set_pref_def_name(Name,_Pref,CurValAtom)},!,
3085 insertstr(' '),insertstr(Name),
3086 insertstr(' '),
3087 {translate_in_mode(eqeq,'==',EqEqStr)}, insertstr(EqEqStr), insertstr(' '),
3088 insertstr(CurValAtom), % pretty print current value; Expr could be a more complicated non-atomic expression
3089 insertstr(';\n').
3090 translate_set_pref_def(_) --> [].
3091
3092 standard_library_required(Defs,Library) :-
3093 ? member(Decl,Defs),
3094 definition_decl_from_library(Decl,Library).
3095
3096 % TODO: we could also look in the list of loaded files and search for standard libraries
3097 definition_decl_from_library(definition_decl(printf,predicate,_,_,[_,_],_,_Deps),'LibraryIO.def').
3098 definition_decl_from_library(definition_decl('STRING_IS_DECIMAL',predicate,_,_,[_],_,_Deps),'LibraryStrings.def').
3099 definition_decl_from_library(definition_decl('SHA_HASH',expression,_,_,[_],_,_Deps),'LibraryHash.def').
3100 definition_decl_from_library(definition_decl('CHOOSE',expression,_,_,[_],_,_Deps),'CHOOSE.def').
3101 definition_decl_from_library(definition_decl('SCCS',expression,_,_,[_],_,_Deps),'SCCS.def').
3102 definition_decl_from_library(definition_decl('SORT',expression,_,_,[_],_,_Deps),'SORT.def').
3103 definition_decl_from_library(definition_decl('random_element',expression,_,_,[_],_,_Deps),'LibraryRandom.def').
3104 definition_decl_from_library(definition_decl('SIN',expression,_,_,[_],_,_Deps),'LibraryMath.def').
3105 definition_decl_from_library(definition_decl('RMUL',expression,_,_,[_,_],_,_Deps),'LibraryReals.def').
3106 definition_decl_from_library(definition_decl('REGEX_MATCH',predicate,_,_,[_,_],_,_Deps),'LibraryRegex.def').
3107 definition_decl_from_library(definition_decl('ASSERT_EXPR',expression,_,_,[_,_,_],_,_Deps),'LibraryProB.def').
3108 definition_decl_from_library(definition_decl('svg_points',expression,_,_,[_],_,_Deps),'LibrarySVG.def').
3109 definition_decl_from_library(definition_decl('FULL_FILES',expression,_,_,[_],_,_Deps),'LibraryFiles.def').
3110 definition_decl_from_library(definition_decl('READ_XML_FROM_STRING',expression,_,_,[_],_,_Deps),'LibraryXML.def').
3111 definition_decl_from_library(definition_decl('READ_CSV',expression,_,_,[_],_,_Deps),'LibraryCSV.def').
3112
3113 insert_library_usages([]) --> [].
3114 insert_library_usages([Library|T]) -->
3115 insertstr(' "'),insertstr(Library),insertstr('";\n'), % insert inclusion of ProB standard library
3116 insert_library_usages(T).
3117
3118 % ------------- RAW EXPRESSIONS
3119
3120 % try and print raw machine term or parts thereof (e.g. sections)
3121 print_raw_machine_terms(Var) :- var(Var), !,write('VAR !!'),nl.
3122 print_raw_machine_terms([]) :- !.
3123 print_raw_machine_terms([H|T]) :- !,
3124 print_raw_machine_terms(H), write(' '),
3125 print_raw_machine_terms(T).
3126 print_raw_machine_terms(Term) :- raw_machine_term(Term,String,Sub),!,
3127 format('~n~w ',[String]),
3128 print_raw_machine_terms(Sub),nl.
3129 print_raw_machine_terms(expression_definition(A,B,C,D)) :- !,
3130 print_raw_machine_terms(predicate_definition(A,B,C,D)).
3131 print_raw_machine_terms(substitution_definition(A,B,C,D)) :- !,
3132 print_raw_machine_terms(predicate_definition(A,B,C,D)).
3133 print_raw_machine_terms(expression(A,B,C,D)) :- !,
3134 print_raw_machine_terms(predicate_definition(A,B,C,D)).
3135 print_raw_machine_terms(predicate(A,B,C,D)) :- !,
3136 print_raw_machine_terms(predicate_definition(A,B,C,D)).
3137 print_raw_machine_terms(substitution(A,B,C,D)) :- !,
3138 print_raw_machine_terms(predicate_definition(A,B,C,D)).
3139 print_raw_machine_terms(predicate_definition(_,Name,Paras,RHS)) :-
3140 Paras==[],!,
3141 format('~n ~w == ',[Name]),
3142 print_raw_machine_terms(RHS),nl.
3143 print_raw_machine_terms(predicate_definition(_,Name,Paras,RHS)) :- !,
3144 format('~n ~w(',[Name]),
3145 print_raw_machine_terms_sep(Paras,','),
3146 format(') == ',[]),
3147 print_raw_machine_terms(RHS),nl.
3148 print_raw_machine_terms(operation(_,Name,Return,Paras,RHS)) :- !,
3149 format('~n ',[]),
3150 (Return=[] -> true
3151 ; print_raw_machine_terms_sep(Return,','),
3152 format(' <-- ',[])
3153 ),
3154 print_raw_machine_terms(Name),
3155 (Paras=[] -> true
3156 ; format(' (',[]),
3157 print_raw_machine_terms_sep(Paras,','),
3158 format(')',[])
3159 ),
3160 format(' = ',[]),
3161 print_raw_machine_terms(RHS),nl.
3162 print_raw_machine_terms(Term) :- print_raw_bexpr(Term).
3163
3164
3165 print_raw_machine_terms_sep([],_) :- !.
3166 print_raw_machine_terms_sep([H],_) :- !,
3167 print_raw_machine_terms(H).
3168 print_raw_machine_terms_sep([H|T],Sep) :- !,
3169 print_raw_machine_terms(H),write(Sep),print_raw_machine_terms_sep(T,Sep).
3170
3171 raw_machine_term(machine(M),'',M).
3172 raw_machine_term(generated(_,M),'',M).
3173 raw_machine_term(machine_header(_,Name,_Params),Name,[]). % TO DO: treat Params
3174 raw_machine_term(abstract_machine(_,_,Header,M),'MACHINE',[Header,M]).
3175 raw_machine_term(properties(_,P),'PROPERTIES',P).
3176 raw_machine_term(operations(_,P),'OPERATIONS',P).
3177 raw_machine_term(definitions(_,P),'DEFINITIONS',P).
3178 raw_machine_term(constants(_,P),'CONSTANTS',P).
3179 raw_machine_term(variables(_,P),'VARIABLES',P).
3180 raw_machine_term(invariant(_,P),'INVARIANT',P).
3181 raw_machine_term(assertions(_,P),'ASSERTIONS',P).
3182 raw_machine_term(constraints(_,P),'CONSTRAINTS',P).
3183 raw_machine_term(sets(_,P),'SETS',P).
3184 raw_machine_term(deferred_set(_,P),P,[]). % TO DO: enumerated_set ...
3185 %raw_machine_term(identifier(_,P),P,[]).
3186
3187 l_print_raw_bexpr([]).
3188 l_print_raw_bexpr([Raw|T]) :- write(' '),
3189 print_raw_bexpr(Raw),nl, l_print_raw_bexpr(T).
3190
3191 print_raw_bexpr(Raw) :- % a tool (not perfect) to print raw ASTs
3192 transform_raw(Raw,TExpr),!,
3193 print_bexpr_or_subst(TExpr).
3194
3195 translate_raw_bexpr(Raw,TS) :- transform_raw(Raw,TExpr), translate_subst_or_bexpr(TExpr,TS).
3196 ?translate_raw_bexpr_with_limit(Raw,Limit,TS) :- transform_raw(Raw,TExpr),
3197 translate_subst_or_bexpr_with_limit(TExpr,Limit,TS).
3198
3199 transform_raw_list(Var,Res) :- var(Var),!,
3200 add_internal_error('Var raw expression list:',transform_raw_list(Var,Res)),
3201 Res= [b(identifier('$$VARIABLE_LIST$$'),any,[raw])].
3202 transform_raw_list(Args,TArgs) :- l_transform_raw(Args,TArgs).
3203
3204 :- use_module(input_syntax_tree,[raw_symbolic_annotation/2]).
3205
3206 transform_raw(Var,Res) :- %write(raw(Var)),nl,
3207 var(Var), !, add_internal_error('Var raw expression:',transform_raw(Var,Res)),
3208 Res= b(identifier('$$VARIABLE$$'),any,[raw]).
3209 transform_raw(precondition(_,Pre,Body),Res) :- !, Res= b(precondition(TP,TB),subst,[raw]),
3210 transform_raw(Pre,TP),
3211 transform_raw(Body,TB).
3212 transform_raw(typeof(_,E,Type),Res) :- !, Res = b(typeof(TE,TType),any,[]),
3213 transform_raw(E,TE), transform_raw(Type,TType).
3214 transform_raw(identifier(_,M),Res) :- !, Res= b(identifier(M),any,[raw]).
3215 transform_raw(integer(_,M),Res) :- !, Res= b(integer(M),integer,[raw]).
3216 % rules from btype_rewrite2:
3217 transform_raw(integer_set(_),Res) :- !, generate_typed_int_set('INTEGER',Res).
3218 transform_raw(natural_set(_),Res) :- !, generate_typed_int_set('NATURAL',Res).
3219 transform_raw(natural1_set(_),Res) :- !, generate_typed_int_set('NATURAL1',Res).
3220 transform_raw(nat_set(_),Res) :- !, generate_typed_int_set('NAT',Res).
3221 transform_raw(nat1_set(_),Res) :- !, generate_typed_int_set('NAT1',Res).
3222 transform_raw(int_set(_),Res) :- !, generate_typed_int_set('INT',Res).
3223 transform_raw(let_expression(_,_Ids,Eq,Body),Res) :- !,
3224 transform_raw(conjunct(_,Eq,Body),Res). % TO DO: fix and generate let_expression(Ids,ListofExprs,Body)
3225 transform_raw(let_predicate(_,_Ids,Eq,Body),Res) :- !,
3226 transform_raw(conjunct(_,Eq,Body),Res). % ditto
3227 transform_raw(forall(_,Ids,Body),Res) :- !,
3228 (Body=implication(_,LHS,RHS) -> true ; LHS=truth,RHS=Body),
3229 ? transform_raw(forall(_,Ids,LHS,RHS),Res).
3230 transform_raw(record_field(_,Rec,identifier(_,Field)),Res) :- !, Res = b(record_field(TRec,Field),any,[]),
3231 transform_raw(Rec,TRec).
3232 transform_raw(rec_entry(_,identifier(_,Field),Rec),Res) :- !, Res = field(Field,TRec),
3233 transform_raw(Rec,TRec).
3234 transform_raw(conjunct(_,List),Res) :- !,
3235 ? transform_raw_list_to_conjunct(List,Res). % sometimes conjunct/1 with list is used (e.g., .eventb files)
3236 transform_raw(couple(_,L),Res) :- !, transform_raw_list_to_couple(L,Res). % couples are represented by lists
3237 transform_raw(extended_expr(Pos,Op,L,_TypeParas),Res) :- !,
3238 (L=[] -> transform_raw(identifier(none,Op),Res) % no arguments
3239 ; transform_raw(function(Pos,identifier(none,Op),L),Res)).
3240 transform_raw(extended_pred(Pos,Op,L,_TypeParas),Res) :- !,
3241 transform_raw(function(Pos,identifier(none,Op),L),Res). % not of correct type pred, but seems to work
3242 transform_raw(external_function_call_auto(Pos,Name,Para),Res) :- !,
3243 transform_raw(external_function_call(Pos,Name,Para),Res). % we assume expr rather than pred and hope for the best
3244 transform_raw(function(_,F,L),Res) :- !, transform_raw(F,TF),
3245 Res = b(function(TF,Args),any,[]),
3246 transform_raw_list_to_couple(L,Args). % args are represented by lists
3247 transform_raw(Atom,Res) :- atomic(Atom),!,Res=Atom.
3248 transform_raw([H|T],Res) :- !, l_transform_raw([H|T],Res).
3249 transform_raw(Symbolic,Res) :- raw_symbolic_annotation(Symbolic,Body),!,
3250 ? transform_raw(Body,Res).
3251 transform_raw(OtherOp,b(Res,Type,[])) :- OtherOp =..[F,_Pos|Rest],
3252 ? l_transform_raw(Rest,TRest),
3253 (get_type(F,FT) -> Type=FT ; Type=any),
3254 Res =.. [F|TRest].
3255 transform_raw_list_to_couple([R],Res) :- !, transform_raw(R,Res).
3256 transform_raw_list_to_couple([R1|T],Res) :- !, Res=b(couple(TR1,TT),any,[]),
3257 transform_raw(R1,TR1),transform_raw_list_to_couple(T,TT).
3258 transform_raw_list_to_conjunct([R],Res) :- !, transform_raw(R,Res).
3259 transform_raw_list_to_conjunct([R1|T],Res) :-
3260 ? transform_raw(R1,TR1),
3261 ? transform_raw_list_to_conjunct2(TR1,T,Res).
3262 transform_raw_list_to_conjunct2(Res,[],Res).
3263 transform_raw_list_to_conjunct2(Conj,[R1|T],Res) :-
3264 ? transform_raw(R1,TR1),
3265 Conj1 = b(conjunct(Conj,TR1),pred,[]), % conjunct from left to right, e.g. [A,B,C] -> conjunct(conjunct(A,B),C)
3266 ? transform_raw_list_to_conjunct2(Conj1,T,Res).
3267
3268 l_transform_raw([],[]).
3269 ?l_transform_raw([H|T],[RH|RT]) :- transform_raw(H,RH), l_transform_raw(T,RT).
3270
3271 generate_typed_int_set(Name,b(integer_set(Name),set(integer),[])).
3272 get_type(truth,pred).
3273 get_type(falsity,pred).
3274 get_type(conjunct,pred).
3275 get_type(disjunct,pred).
3276 get_type(forall,pred).
3277 get_type(equivalence,pred).
3278 get_type(exists,pred).
3279 get_type(implication,pred).
3280 get_type(equal,pred).
3281 get_type(not_equal,pred).
3282 get_type(member,pred).
3283 get_type(negation,pred).
3284 get_type(not_member,pred).
3285 get_type(subset,pred).
3286 get_type(subset_strict,pred).
3287 get_type(not_subset,pred).
3288 get_type(not_subset_strict,pred).
3289 get_type(less_equal,pred).
3290 get_type(less,pred).
3291 get_type(less_equal_real,pred).
3292 get_type(less_real,pred).
3293 get_type(greater_equal,pred).
3294 get_type(greater,pred).
3295 get_type(finite,pred).
3296 get_type(card,integer).
3297 get_type(size,integer).
3298 get_type(convert_int_floor,integer).
3299 get_type(convert_int_ceiling,integer).
3300 get_type(predecessor,integer).
3301 get_type(successor,integer).
3302 get_type(boolean_false,boolean).
3303 get_type(boolean_true,boolean).
3304 get_type(convert_bool,boolean).
3305 get_type(add_real,real).
3306 get_type(convert_real,real).
3307 get_type(div_real,real).
3308 get_type(max_real,real).
3309 get_type(min_real,real).
3310 get_type(minus_real,real).
3311 get_type(multiplication_real,real).
3312 get_type(power_of_real,real).
3313 get_type(real,real). % real literal
3314 get_type(string,string). % string literal
3315 get_type(bool_set,set(boolean)).
3316 get_type(float_set,set(real)).
3317 get_type(real_set,set(real)).
3318 get_type(string_set,set(real)).
3319
3320 get_type(any,subst).
3321 get_type(assertion,subst).
3322 get_type(assign,subst).
3323 get_type(becomes_element_of,subst).
3324 get_type(becomes_such,subst).
3325 get_type(case,subst).
3326 get_type(choice,subst).
3327 get_type(external_subst_call,subst).
3328 get_type(if,subst).
3329 get_type(let,subst).
3330 get_type(operation_call,subst).
3331 get_type(parallel,subst).
3332 get_type(precondition,subst).
3333 get_type(select,subst).
3334 get_type(sequence,subst).
3335 get_type(skip,subst).
3336 get_type(var,subst).
3337 get_type(while,subst).
3338 get_type(while1,subst).
3339 get_type(witness_then,subst).
3340
3341 :- assert_must_succeed((transform_raw(conjunct(none,[member(none,identifier(none,x),integer_set(none)),
3342 less_equal(none,identifier(none,y),integer(none,5)),
3343 equal(none,integer(none,1),integer(none,1))]),R),
3344 % check that list of conjunctions is transformed left-associatively
3345 R == b(conjunct(b(conjunct(b(member(b(identifier(x),any,[raw]),b(integer_set('INTEGER'),set(integer),[])),pred,[]),
3346 b(less_equal(b(identifier(y),any,[raw]),b(integer(5),integer,[raw])),pred,[])),pred,[]),
3347 b(equal(b(integer(1),integer,[raw]),b(integer(1),integer,[raw])),pred,[])),pred,[]))).
3348
3349 % -------------
3350
3351
3352 % pretty-print the operations of a machine
3353 translate_ops([]) --> !.
3354 translate_ops([Op|Rest]) -->
3355 translate_op(Op),
3356 ({Rest=[]} -> {true}; insertstr(';'),indent),
3357 translate_ops(Rest).
3358 translate_op(Op) -->
3359 { get_texpr_expr(Op,operation(Id,Res,Params,Body)) },
3360 translate_operation(Id,Res,Params,Body).
3361 translate_operation(Id,Res,Params,Body) -->
3362 indent,translate_op_results(Res),
3363 pp_expr_indent(Id),
3364 translate_op_params(Params),
3365 insertstr(' = '),
3366 indention_level(I1,I2),{I2 is I1+2,type_infos_in_subst(Params,Body,Body2)},
3367 translate_subst_begin_end(Body2),
3368 pp_description_pragma_of(Body2),
3369 indention_level(_,I1).
3370 translate_op_results([]) --> !.
3371 translate_op_results(Ids) --> pp_expr_indent_l(Ids), insertstr(' <-- ').
3372 translate_op_params([]) --> !.
3373 translate_op_params(Ids) --> insertstr('('),pp_expr_indent_l(Ids), insertstr(')').
3374
3375 translate_subst_begin_end(TSubst) -->
3376 {get_texpr_expr(TSubst,Subst),subst_needs_begin_end(Subst),
3377 create_texpr(block(TSubst),subst,[],Block)},!,
3378 translate_subst(Block).
3379 translate_subst_begin_end(Subst) -->
3380 translate_subst(Subst).
3381
3382 subst_needs_begin_end(assign(_,_)).
3383 subst_needs_begin_end(assign_single_id(_,_)).
3384 subst_needs_begin_end(parallel(_)).
3385 subst_needs_begin_end(sequence(_)).
3386 subst_needs_begin_end(operation_call(_,_,_)).
3387
3388 type_infos_in_subst([],Subst,Subst) :- !.
3389 type_infos_in_subst(Ids,SubstIn,SubstOut) :-
3390 get_preference(translate_print_typing_infos,true),!,
3391 type_infos_in_subst2(Ids,SubstIn,SubstOut).
3392 type_infos_in_subst(_Ids,Subst,Subst).
3393 type_infos_in_subst2(Ids,SubstIn,SubstOut) :-
3394 get_texpr_expr(SubstIn,precondition(P1,S)),!,
3395 get_texpr_info(SubstIn,Info),
3396 create_texpr(precondition(P2,S),pred,Info,SubstOut),
3397 add_typing_predicates(Ids,P1,P2).
3398 type_infos_in_subst2(Ids,SubstIn,SubstOut) :-
3399 create_texpr(precondition(P,SubstIn),pred,[],SubstOut),
3400 generate_typing_predicates(Ids,Typing),
3401 conjunct_predicates(Typing,P).
3402
3403
3404
3405
3406
3407 % pretty-print the internal section about included and used machines
3408 translate_used([]) --> !.
3409 translate_used([Used|Rest]) -->
3410 translate_used2(Used),
3411 translate_used(Rest).
3412 translate_used2(includeduse(Name,Id,NewTExpr)) -->
3413 indent,pp_expr_indent(NewTExpr),
3414 insertstr(' --> '), insertstr(Name), insertstr(':'), insertstr(Id).
3415
3416 % pretty-print the internal information about freetypes
3417 translate_freetypes([]) --> !.
3418 translate_freetypes([Freetype|Frest]) -->
3419 translate_freetype(Freetype),
3420 translate_freetypes(Frest).
3421 translate_freetype(freetype(Name,Cases)) -->
3422 {pretty_freetype(Name,PName)},
3423 indent(PName),insertstr('= '),
3424 indention_level(I1,I2),{I2 is I1+2},
3425 translate_freetype_cases(Cases),
3426 indention_level(_,I1).
3427 translate_freetype_cases([]) --> !.
3428 translate_freetype_cases([case(Name,Type)|Rest]) --> {nonvar(Type),Type=constant(_)},
3429 !,indent(Name),insert_comma(Rest),
3430 translate_freetype_cases(Rest).
3431 translate_freetype_cases([case(Name,Type)|Rest]) -->
3432 {pretty_type(Type,PT)},
3433 indent(Name),
3434 insertstr('('),insertstr(PT),insertstr(')'),
3435 insert_comma(Rest),
3436 translate_freetype_cases(Rest).
3437
3438 insert_comma([]) --> [].
3439 insert_comma([_|_]) --> insertstr(',').
3440
3441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3442 % substitutions
3443
3444 translate_subst_or_bexpr(Stmt,String) :- get_texpr_type(Stmt,subst),!,
3445 translate_substitution(Stmt,String).
3446 translate_subst_or_bexpr(ExprOrPred,String) :-
3447 translate_bexpression(ExprOrPred,String).
3448
3449 translate_subst_or_bexpr_with_limit(Stmt,Limit,String) :-
3450 translate_subst_or_bexpr_with_limit(Stmt,Limit,report_errors,String).
3451 translate_subst_or_bexpr_with_limit(Stmt,_Limit,ReportErrors,String) :- get_texpr_type(Stmt,subst),!,
3452 translate_substitution(Stmt,String,ReportErrors). % TO DO: use limit
3453 translate_subst_or_bexpr_with_limit(ExprOrPred,Limit,ReportErrors,String) :-
3454 translate_bexpression_with_limit(ExprOrPred,Limit,ReportErrors,String).
3455
3456 print_subst(Stmt) :- translate_substitution(Stmt,T), write(T).
3457 translate_substitution(Stmt,String) :- translate_substitution(Stmt,String,report_errors).
3458 translate_substitution(Stmt,String,_) :-
3459 translate_subst_with_indention(Stmt,0,Codes,[]),
3460 (Codes = [10|C] -> true ; Codes=[13|C] -> true ; Codes=C), % peel off leading newline
3461 atom_codes_with_limit(String, C),!.
3462 translate_substitution(Stmt,String,report_errors) :-
3463 add_error(translate_substitution,'Could not translate substitution: ',Stmt),
3464 String='???'.
3465
3466 translate_subst_with_indention(TS,Indention,I,O) :-
3467 translate_subst(TS,(Indention,I),(_,O)).
3468 translate_subst_with_indention_and_label(TS,Indention,I,O) :-
3469 translate_subst_with_label(TS,(Indention,I),(_,O)).
3470
3471 translate_subst(TS) -->
3472 ( {get_texpr_expr(TS,S)} ->
3473 translate_subst2(S)
3474 ; translate_subst2(TS)).
3475
3476 translate_subst_with_label(TS) -->
3477 ( {get_texpr_expr(TS,S)} ->
3478 indent_rodin_label(TS), % pretty print substitution labels
3479 translate_subst2(S)
3480 ; translate_subst2(TS)).
3481
3482 % will print (first) rodin or pragma label indendent
3483 :- public indent_rodin_label/3.
3484 indent_rodin_label(_TExpr) --> {get_preference(translate_suppress_rodin_positions_flag,true),!}.
3485 indent_rodin_label(_TExpr) --> {get_preference(bugly_pp_scrambling,true),!}.
3486 indent_rodin_label(TExpr) --> {get_texpr_labels(TExpr,Names)},!, % note: this will only get the first label
3487 indent('/* @'),pp_ids_indent(Names),insertstr('*/ '). % this Camille syntax cannot be read back in by B parser
3488 indent_rodin_label(_TExpr) --> [].
3489
3490 pp_ids_indent([]) --> !, [].
3491 pp_ids_indent([ID]) --> !,pp_expr_indent(identifier(ID)).
3492 pp_ids_indent([ID|T]) --> !,pp_expr_indent(identifier(ID)), insertstr(' '),pp_ids_indent(T).
3493 pp_ids_indent(X) --> {add_error(pp_ids_indent,'Not a list of atoms: ',pp_ids_indent(X))}.
3494
3495 translate_subst2(Var) --> {var(Var)}, !, "_", {add_warning(translate_subst,'Variable subst:',Var)}.
3496 translate_subst2(skip) -->
3497 indent(skip).
3498 translate_subst2(operation(Id,Res,Params,Body)) --> translate_operation(Id,Res,Params,Body). % not really a substition that can appear normally
3499 translate_subst2(precondition(P,S)) -->
3500 indent('PRE '), pred_over_lines(2,'@grd',P), indent('THEN'), insert_subst(S), indent('END').
3501 translate_subst2(assertion(P,S)) -->
3502 indent('ASSERT '), pp_expr_indent(P), indent('THEN'), insert_subst(S), indent('END').
3503 translate_subst2(witness_then(P,S)) -->
3504 indent('WITNESS '), pp_expr_indent(P), indent('THEN'), insert_subst(S), indent('END').
3505 translate_subst2(block(S)) -->
3506 indent('BEGIN'), insert_subst(S), indent('END').
3507 translate_subst2(assign([L],[R])) --> !,
3508 indent,pp_expr_indent(L),insertstr(' := '),pp_expr_indent(R).
3509 translate_subst2(assign(L,R)) -->
3510 {(member(b(E,_,_),R), can_indent_expr(E)
3511 -> maplist(create_assign,L,R,ParAssigns))},!, % split into parallel assignments so that we can indent
3512 translate_subst2(parallel(ParAssigns)).
3513 translate_subst2(assign(L,R)) -->
3514 indent,pp_expr_indent_l(L),insertstr(' := '),pp_expr_indent_l(R).
3515 translate_subst2(assign_single_id(L,R)) -->
3516 translate_subst2(assign([L],[R])).
3517 translate_subst2(becomes_element_of(L,R)) -->
3518 indent,pp_expr_indent_l(L),insertstr(' :: '),pp_expr_indent(R).
3519 translate_subst2(becomes_such(L,R)) -->
3520 indent,pp_expr_indent_l(L),insertstr(' : '), insertstr('('),
3521 { add_optional_typing_predicates(L,R,R1) },
3522 pp_expr_indent(R1), insertstr(')').
3523 translate_subst2(evb2_becomes_such(L,R)) --> translate_subst2(becomes_such(L,R)).
3524 translate_subst2(if([Elsif|Rest])) -->
3525 { get_if_elsif(Elsif,P,S) },
3526 indent('IF '), pp_expr_indent(P), insertstr(' THEN'),
3527 insert_subst(S),
3528 translate_ifs(Rest).
3529 translate_subst2(if_elsif(P,S)) --> % not a legal top-level construct; but can be called in b_portray_hook
3530 indent('IF '), pp_expr_indent(P), insertstr(' THEN'),
3531 insert_subst(S),
3532 indent('END').
3533 translate_subst2(choice(Ss)) --> indent(' CHOICE'),
3534 split_over_lines(Ss,'OR'),
3535 indent('END'). % indentation seems too far
3536 translate_subst2(parallel(Ss)) -->
3537 split_over_lines(Ss,'||').
3538 translate_subst2(init_statement(S)) --> insert_subst(S).
3539 translate_subst2(sequence(Ss)) -->
3540 split_over_lines(Ss,';').
3541 translate_subst2(operation_call(Id,Rs,As)) -->
3542 indent,translate_op_results(Rs),
3543 pp_expr_indent(Id),
3544 translate_op_params(As).
3545 translate_subst2(identifier(op(Id))) --> % shouldn't normally appear
3546 indent,pp_expr_indent(identifier(Id)).
3547 translate_subst2(external_subst_call(Symbol,Args)) -->
3548 indent,
3549 pp_expr_indent(identifier(Symbol)),
3550 translate_op_params(Args).
3551 translate_subst2(any(Ids,Pred,Subst)) -->
3552 indent('ANY '), pp_expr_indent_l(Ids),
3553 indent('WHERE '),
3554 {add_optional_typing_predicates(Ids,Pred,Pred2)},
3555 pred_over_lines(2,'@grd',Pred2), indent('THEN'),
3556 insert_subst(Subst),
3557 indent('END').
3558 translate_subst2(select(Whens)) -->
3559 translate_whens(Whens,'SELECT '),
3560 indent('END').
3561 translate_subst2(select_when(Cond,Then)) --> % not a legal top-level construct; but can be called in b_portray_hook
3562 indent('WHEN'),
3563 pp_expr_indent(Cond),
3564 indent('THEN'),
3565 insert_subst(Then),
3566 indent('END').
3567 translate_subst2(select(Whens,Else)) -->
3568 translate_whens(Whens,'SELECT '),
3569 indent('ELSE'), insert_subst(Else),
3570 indent('END').
3571 translate_subst2(var(Ids,S)) -->
3572 indent('VAR '),
3573 pp_expr_indent_l(Ids),
3574 indent('IN'),insert_subst(S),
3575 indent('END').
3576 translate_subst2(let(Ids,P,S)) -->
3577 indent('LET '),
3578 pp_expr_indent_l(Ids),
3579 insertstr(' BE '), pp_expr_indent(P),
3580 indent('IN'), insert_subst(S),
3581 indent('END').
3582 translate_subst2(lazy_let_subst(TID,P,S)) -->
3583 indent('LET '),
3584 pp_expr_indent_l([TID]),
3585 insertstr(' BE '), pp_expr_indent(P), % could be expr or pred
3586 indent('IN'), insert_subst(S),
3587 indent('END').
3588 translate_subst2(case(Expression,Cases,ELSE)) -->
3589 % CASE E OF EITHER m THEN G OR n THEN H ... ELSE I END END
3590 indent('CASE '),
3591 pp_expr_indent(Expression), insertstr(' OF'),
3592 indent('EITHER '), translate_cases(Cases),
3593 indent('ELSE '), insert_subst(ELSE), % we could drop this if ELSE is skip ?
3594 indent('END END').
3595 translate_subst2(while(Pred,Subst,Inv,Var)) -->
3596 indent('WHILE '), pp_expr_indent(Pred),
3597 indent('DO'),insert_subst(Subst),
3598 indent('INVARIANT '),pp_expr_indent(Inv),
3599 indent('VARIANT '),pp_expr_indent(Var),
3600 indent('END').
3601 translate_subst2(while1(Pred,Subst,Inv,Var)) -->
3602 indent('WHILE /* 1 */ '), pp_expr_indent(Pred),
3603 indent('DO'),insert_subst(Subst),
3604 indent('INVARIANT '),pp_expr_indent(Inv),
3605 indent('VARIANT '),pp_expr_indent(Var),
3606 indent('END').
3607 translate_subst2(rlevent(Id,Section,Status,Parameters,Guard,Theorems,Actions,VWitnesses,PWitnesses,_Unmod,Refines)) -->
3608 indent,
3609 insert_status(Status),
3610 insertstr('EVENT '),
3611 ({Id = 'INITIALISATION'}
3612 -> [] % avoid BLexer error in ProB2-UI, BLexerException: Invalid combination of symbols: 'INITIALISATION' and '='.
3613 ; insertstr(Id), insertstr(' = ')),
3614 insertstr('/'), insertstr('* of machine '),
3615 insertstr(Section),insertstr(' */'),
3616 insert_variant(Status),
3617 ( {Parameters=[], get_texpr_expr(Guard,truth)} ->
3618 {NoGuard=true} % indent('BEGIN ')
3619 ; {Parameters=[]} ->
3620 indent('WHEN '),
3621 pred_over_lines(2,'@grd',Guard)
3622 ;
3623 indent('ANY '),pp_expr_indent_l(Parameters),
3624 indent('WHERE '),
3625 pred_over_lines(2,'@grd',Guard)
3626 ),
3627 ( {VWitnesses=[],PWitnesses=[]} ->
3628 []
3629 ;
3630 {append(VWitnesses,PWitnesses,Witnesses)},
3631 indent('WITH '),pp_witness_l(Witnesses)
3632 ),
3633 {( Actions=[] ->
3634 create_texpr(skip,subst,[],Subst)
3635 ;
3636 create_texpr(parallel(Actions),subst,[],Subst)
3637 )},
3638 ( {Theorems=[]} -> {true}
3639 ;
3640 indent('THEOREMS '),
3641 preds_over_lines(2,'@thm',Theorems)
3642 ),
3643 ({NoGuard==true, Actions=[]}
3644 -> pp_refines_l(Refines,Id) % we do not need a BEGIN END block and we need no substitution to be shown
3645 ; ({NoGuard==true}
3646 -> indent('BEGIN ') % avoid BLexer errors in ProB2-UI Syntax highlighting
3647 ; indent('THEN ')
3648 ),
3649 insert_subst(Subst),
3650 pp_refines_l(Refines,Id),
3651 indent('END')
3652 ).
3653
3654
3655 % translate cases of a CASE statement
3656 translate_cases([]) --> !,[].
3657 translate_cases([CaseOr|T]) -->
3658 {get_texpr_expr(CaseOr,case_or(Exprs,Subst))},!,
3659 pp_expr_indent_l(Exprs),
3660 insertstr(' THEN '),
3661 insert_subst(Subst),
3662 ({T==[]} -> {true}
3663 ; indent('OR '), translate_cases(T)).
3664 translate_cases(L) -->
3665 {add_internal_error('Cannot translate CASE list: ',translate_cases(L,_,_))}.
3666
3667 insert_status(TStatus) -->
3668 {get_texpr_expr(TStatus,Status),
3669 status_string(Status,String)},
3670 insertstr(String).
3671 status_string(ordinary,'').
3672 status_string(anticipated(_),'ANTICIPATED ').
3673 status_string(convergent(_),'CONVERGENT ').
3674
3675 insert_variant(TStatus) -->
3676 {get_texpr_expr(TStatus,Status)},
3677 insert_variant2(Status).
3678 insert_variant2(ordinary) --> !.
3679 insert_variant2(anticipated(Variant)) --> insert_variant3(Variant).
3680 insert_variant2(convergent(Variant)) --> insert_variant3(Variant).
3681 insert_variant3(Variant) -->
3682 indent('USING VARIANT '),pp_expr_indent(Variant).
3683
3684 pp_refines_l([],_) --> [].
3685 pp_refines_l([Ref|Rest],Id) -->
3686 pp_refines(Ref,Id),pp_refines_l(Rest,Id).
3687 pp_refines(Refined,_Id) -->
3688 % indent(Id), insertstr(' REFINES '),
3689 ({is_extended_rlevent(Refined)} -> indent('EXTENDS') ; indent('REFINES ')),
3690 insert_subst(Refined).
3691
3692 is_extended_rlevent(b(rlevent(_Id,_Sect,_Status,_Paras,Guard,Theorems,Actions,_VWitn,_PWitn,_Unmod,_Refines),subst,_)) :-
3693 get_texpr_expr(Guard,truth), % bmachine_eventb:optimise_events has removed all guards
3694 Theorems=[], % and all theorems
3695 Actions = []. % ditto for actions: everything removed by optimise_events
3696
3697 pp_witness_l([]) --> [].
3698 pp_witness_l([Witness|WRest]) -->
3699 pp_witness(Witness),pp_witness_l(WRest).
3700 pp_witness(Expr) -->
3701 indention_level(I1,I2),
3702 {get_texpr_expr(Expr,witness(Id,Pred)),
3703 I2 is I1+2},
3704 indent, pp_expr_indent(Id), insertstr(': '),
3705 pp_expr_indent(Pred),
3706 pp_description_pragma_of(Pred),
3707 indention_level(_,I1).
3708
3709
3710 translate_whens([],_) --> !.
3711 translate_whens([When|Rest],T) -->
3712 {get_texpr_expr(When,select_when(P,S))},!,
3713 indent(T), pred_over_lines(2,'@grd',P),
3714 indent('THEN '),
3715 insert_subst(S),
3716 translate_whens(Rest,'WHEN ').
3717 translate_whens(L,_) -->
3718 {add_internal_error('Cannot translate WHEN: ',translate_whens(L,_,_,_))}.
3719
3720
3721
3722 create_assign(LHS,RHS,b(assign([LHS],[RHS]),subst,[])).
3723
3724 split_over_lines([],_) --> !.
3725 split_over_lines([S|Rest],Symbol) --> !,
3726 indention_level(I1,I2),{atom_codes(Symbol,X),length(X,N),I2 is I1+N+1},
3727 translate_subst_check(S),
3728 split_over_lines2(Rest,Symbol,I1,I2).
3729 split_over_lines(S,Symbol) --> {add_error(split_over_lines,'Illegal argument: ',Symbol:S)}.
3730
3731 split_over_lines2([],_,_,_) --> !.
3732 split_over_lines2([S|Rest],Symbol,I1,I2) -->
3733 indention_level(_,I1), indent(Symbol),
3734 indention_level(_,I2), translate_subst(S),
3735 split_over_lines2(Rest,Symbol,I1,I2).
3736
3737 % print a predicate over several lines, at most one conjunct per line
3738 % N is the increment that should be added to the indentation
3739 %pred_over_lines(N,Pred) --> pred_over_lines(N,'@pred',Pred).
3740 pred_over_lines(N,Lbl,Pred) -->
3741 {conjunction_to_list(Pred,List)},
3742 preds_over_lines(N,Lbl,List).
3743 section_pred_over_lines(N,Title,Pred) -->
3744 ({get_eventb_default_label(Title,Lbl)} -> [] ; {Lbl='@pred'}),
3745 pred_over_lines(N,Lbl,Pred).
3746 get_eventb_default_label(properties,'@axm').
3747 get_eventb_default_label(assertions,'@thm').
3748
3749 % print a list of predicates over several lines, at most one conjunct per line
3750 preds_over_lines(N,Lbl,Preds) --> preds_over_lines(N,Lbl,'& ',Preds).
3751 % preds_over_lines(IndentationIncrease,EventBDefaultLabel,ClassicalBSeperator,ListOfPredicates)
3752 preds_over_lines(N,Lbl,Sep,Preds) -->
3753 indention_level(I1,I2),{I2 is I1+N},
3754 preds_over_lines1(Preds,Lbl,1,Sep),
3755 indention_level(_,I1).
3756 preds_over_lines1([],Lbl,Nr,Sep) --> !,
3757 preds_over_lines1([b(truth,pred,[])],Lbl,Nr,Sep).
3758 preds_over_lines1([H|T],Lbl,Nr,Sep) -->
3759 indent(' '), pp_label(Lbl,Nr),
3760 %({T==[]} -> pp_expr_indent(H) ; pp_expr_m_indent(H,40)),
3761 ({T==[]} -> pp_pred_nested(H,conjunct,0) ; pp_pred_nested(H,conjunct,40)),
3762 pp_description_pragma_of(H),
3763 {N1 is Nr+1},
3764 preds_over_lines2(T,Lbl,N1,Sep).
3765 preds_over_lines2([],_,_,_Sep) --> !.
3766 preds_over_lines2([E|Rest],Lbl,Nr,Sep) -->
3767 ({force_eventb_rodin_mode} -> indent(' '), pp_label(Lbl,Nr) ; indent(Sep)),
3768 pp_pred_nested(E,conjunct,40),
3769 pp_description_pragma_of(E),
3770 {N1 is Nr+1},
3771 preds_over_lines2(Rest,Lbl,N1,Sep).
3772
3773 % print event-b label for Rodin/Camille:
3774 pp_label(Lbl,Nr) -->
3775 ({force_eventb_rodin_mode}
3776 -> {atom_codes(Lbl,C1), number_codes(Nr,NC), append(C1,NC,AC), atom_codes(A,AC)},
3777 pp_atom_indent(A), pp_atom_indent(' ')
3778 ; []).
3779
3780 % a version of nested_print_bexpr / nbp that does not directly print to stream conjunct
3781 pp_pred_nested(TExpr,CurrentType,_) --> {TExpr = b(E,pred,_)},
3782 {get_binary_connective(E,NewType,Ascii,LHS,RHS), binary_infix(NewType,Ascii,Prio,left)},
3783 !,
3784 pp_rodin_label_indent(TExpr), % print any label
3785 inc_lvl(CurrentType,NewType),
3786 pp_pred_nested(LHS,NewType,Prio),
3787 {translate_in_mode(NewType,Ascii,Symbol)},
3788 indent(' '),pp_atom_indent(Symbol),
3789 indent(' '),
3790 {(is_associative(NewType) -> NewTypeR=NewType % no need for parentheses if same operator on right
3791 ; NewTypeR=right(NewType))},
3792 pp_pred_nested(RHS,NewTypeR,Prio),
3793 dec_lvl(CurrentType,NewType).
3794 pp_pred_nested(TExpr,_,_) --> {is_nontrivial_negation(TExpr,NExpr,InnerType,Prio)},
3795 !,
3796 pp_rodin_label_indent(TExpr), % print any label
3797 {translate_in_mode(negation,'not',Symbol)},
3798 pp_atom_indent(Symbol),
3799 inc_lvl(other,negation), % always need parentheses for negation
3800 pp_pred_nested(NExpr,InnerType,Prio),
3801 dec_lvl(other,negation).
3802 pp_pred_nested(TExpr,_,_) --> {TExpr = b(exists(Ids,RHS),pred,_)},
3803 !,
3804 pp_rodin_label_indent(TExpr), % print any label
3805 {translate_in_mode(exists,'#',FSymbol)},
3806 %indent(' '),
3807 pp_atom_indent(FSymbol),
3808 pp_expr_ids_in_mode_indent(Ids),pp_atom_indent('.'),
3809 inc_lvl(other,conjunct), % always need parentheses here
3810 {add_normal_typing_predicates(Ids,RHS,RHST), Prio=40}, % Prio of conjunction
3811 pp_pred_nested(RHST,conjunct,Prio),
3812 dec_lvl(other,conjunct).
3813 pp_pred_nested(TExpr,_,_) --> {TExpr = b(forall(Ids,LHS,RHS),pred,_)},
3814 !,
3815 pp_rodin_label_indent(TExpr), % print any label
3816 {translate_in_mode(forall,'!',FSymbol)},
3817 %indent(' '),
3818 pp_atom_indent(FSymbol),
3819 pp_expr_ids_in_mode_indent(Ids),pp_atom_indent('.'),
3820 inc_lvl(other,implication), % always need parentheses here
3821 {add_normal_typing_predicates(Ids,LHS,LHST), Prio=30}, % Prio of implication
3822 pp_pred_nested(LHST,implication,Prio),
3823 {translate_in_mode(implication,'=>',Symbol)},
3824 indent(' '),pp_atom_indent(Symbol),
3825 indent(' '),
3826 pp_pred_nested(RHS,right(implication),Prio),
3827 dec_lvl(other,implication).
3828 pp_pred_nested(TExpr,_,_) -->
3829 {\+ eventb_translation_mode,
3830 TExpr = b(let_predicate(Ids,Exprs,Body),pred,_)
3831 }, %Ids=[_]}, % TODO: enable printing with more than one id; see below
3832 !,
3833 pp_let_nested(Ids,Exprs,Body).
3834 pp_pred_nested(b(BOP,pred,_),_CurrentType,CurMinPrio) -->
3835 {indent_binary_predicate(BOP,LHS,RHS,OpStr),
3836 get_texpr_id(LHS,_),can_indent_texpr(RHS)},!,
3837 pp_expr_m_indent(LHS,CurMinPrio),
3838 insertstr(OpStr),
3839 increase_indentation_level(2),
3840 indent(''),
3841 pp_expr_indent(RHS), % only supports %, {}, bool which do not need parentheses
3842 decrease_indentation_level(2).
3843 pp_pred_nested(Expr,_CurrentType,CurMinPrio) --> {can_indent_texpr(Expr)},!,
3844 pp_expr_m_indent(Expr,CurMinPrio).
3845 pp_pred_nested(Expr,_CurrentType,CurMinPrio) --> pp_expr_m_indent(Expr,CurMinPrio).
3846
3847 indent_binary_predicate(equal(LHS,RHS),LHS,RHS,' = ').
3848 indent_binary_predicate(member(LHS,RHS),LHS,RHS,' : ').
3849
3850 pp_let_nested(Ids,Exprs,Body) -->
3851 indent('LET '),
3852 pp_expr_indent_l(Ids),
3853 insertstr(' BE '),
3854 {maplist(create_equality,Ids,Exprs,Equalities)},
3855 preds_over_lines(2,'@let_eq',Equalities),
3856 indent(' IN '),
3857 increase_indentation_level(2),
3858 pp_pred_nested(Body,let_predicate,40),
3859 decrease_indentation_level(2),
3860 indent(' END').
3861 pp_let_expr_nested(Ids,Exprs,Body) -->
3862 insertstr('LET '),
3863 pp_expr_indent_l(Ids),
3864 insertstr(' BE '),
3865 {maplist(create_equality,Ids,Exprs,Equalities)},
3866 preds_over_lines(2,'@let_eq',Equalities),
3867 indent('IN '),
3868 increase_indentation_level(2),
3869 pp_expr_indent(Body),
3870 decrease_indentation_level(2),
3871 indent('END').
3872
3873 is_nontrivial_negation(b(negation(NExpr),pred,_),NExpr,NewType,Prio) :-
3874 get_texpr_expr(NExpr,E),
3875 (E=negation(_) -> NewType=other,Prio=0
3876 ; get_binary_connective(E,NewType,Ascii,_,_),
3877 binary_infix(NewType,Ascii,Prio,_Assoc)).
3878
3879 pp_rodin_label_indent(b(_,_,Infos),(I,S),(I,T)) :- pp_rodin_label(Infos,S,T).
3880 % note: below we will print unnecessary parentheses in case of Atelier-B mode; but for readability it maye be better to add them
3881 inc_lvl(Old,New) --> {New=Old}, !,[].
3882 inc_lvl(_,_) --> pp_atom_indent('('), % not strictly necessary if higher_prio
3883 increase_indentation_level, indent(' ').
3884 dec_lvl(Old,New) --> {New=Old}, !,[].
3885 dec_lvl(_,_) --> decrease_indentation_level, indent(' '),pp_atom_indent(')').
3886
3887 is_associative(conjunct).
3888 is_associative(disjunct).
3889
3890 %higher_prio(conjunct,implication).
3891 %higher_prio(disjunct,implication).
3892 % priority of equivalence changes in Rodin vs Atelier-B, maybe better add parentheses
3893
3894 translate_ifs([]) --> !,
3895 indent('END').
3896 translate_ifs([Elsif]) -->
3897 {get_if_elsif(Elsif,P,S),
3898 optional_type(P,truth)},!,
3899 indent('ELSE'), insert_subst(S), indent('END').
3900 translate_ifs([Elsif|Rest]) -->
3901 {get_if_elsif(Elsif,P,S)},!,
3902 indent('ELSIF '), pp_expr_indent(P), insertstr(' THEN'),
3903 insert_subst(S),
3904 translate_ifs(Rest).
3905 translate_ifs(ElseList) -->
3906 {functor(ElseList,F,A),add_error(translate_ifs,'Could not translate IF-THEN-ELSE: ',F/A-ElseList),fail}.
3907
3908 get_if_elsif(Elsif,P,S) :-
3909 (optional_type(Elsif,if_elsif(P,S)) -> true
3910 ; add_internal_error('Is not an if_elsif:',get_if_elsif(Elsif,P,S)), fail).
3911
3912 insert_subst(S) -->
3913 indention_level(I,I2),{I2 is I+2},
3914 translate_subst_check(S),
3915 indention_level(_,I).
3916
3917 translate_subst_check(S) --> translate_subst(S),!.
3918 translate_subst_check(S) -->
3919 {b_functor(S,F,A),add_error(translate_subst,'Could not translate substitution: ',F/A-S),fail}.
3920
3921 b_functor(b(E,_,_),F,A) :- !,functor(E,F,A).
3922 b_functor(E,F,A) :- functor(E,F,A).
3923
3924 pp_description_pragma_of(enumerated_set_def(_,_)) --> !, "".
3925 pp_description_pragma_of(Expr) -->
3926 ({get_texpr_description(Expr,Desc)}
3927 -> insert_atom(' /*@desc '), insert_atom(Desc), insert_atom(' */')
3928 ; {true}).
3929 indent_expr(Expr) -->
3930 indent, pp_expr_indent(Expr),
3931 pp_description_pragma_of(Expr).
3932 %indent_expr_l([]) --> !.
3933 %indent_expr_l([Expr|Rest]) -->
3934 % indent_expr(Expr), indent_expr_l(Rest).
3935 indent_expr_l_sep([],_) --> !.
3936 indent_expr_l_sep([Expr|Rest],Sep) -->
3937 indent_expr(Expr),
3938 {(Rest=[] -> RealSep='' ; RealSep=Sep)},
3939 insert_atom(RealSep), % the threaded argument is a pair, not directly a string !
3940 indent_expr_l_sep(Rest,Sep).
3941 %indention_level(L) --> indention_level(L,L).
3942 increase_indentation_level --> indention_level(L,New), {New is L+1}.
3943 increase_indentation_level(N) --> indention_level(L,New), {New is L+N}.
3944 decrease_indentation_level --> indention_level(L,New), {New is L-1}.
3945 decrease_indentation_level(N) --> indention_level(L,New), {New is L-N}.
3946 indention_level(Old,New,(Old,S),(New,S)).
3947 indention_codes(Old,New,(Indent,Old),(Indent,New)).
3948 indent --> indent('').
3949 indent(M,(I,S),(I,T)) :- indent2(I,M,S,T).
3950 indent2(Level,Msg) -->
3951 "\n",do_indention(Level),ppatom(Msg).
3952
3953 insert_atom(Sep,(I,S),(I,T)) :- ppatom(Sep,S,T).
3954
3955 insertstr(M,(I,S),(I,T)) :- ppterm(M,S,T).
3956 insertcodes(M,(I,S),(I,T)) :- ppcodes(M,S,T).
3957
3958 do_indention(0,T,R) :- !, R=T.
3959 do_indention(N,[32|I],O) :-
3960 N>0,N2 is N-1, do_indention(N2,I,O).
3961
3962 optional_type(Typed,Expr) :- get_texpr_expr(Typed,E),!,Expr=E.
3963 optional_type(Expr,Expr).
3964
3965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3966 % expressions and predicates
3967
3968 % pretty-type an expression in an indent-environment
3969 % currently, the indent level is just thrown away
3970 % TODO: pp_expr_indent dom( comprehension_set ) / union ( ...)
3971 pp_expr_indent(b(comprehension_set(Ids,Body),_,_)) -->
3972 {\+ eventb_translation_mode, % TODO: also print in Event-B mode:
3973 detect_lambda_comprehension(Ids,Body, FrontIDs,LambdaBody,ToExpr)},
3974 {add_normal_typing_predicates(FrontIDs,LambdaBody,TLambdaBody)},
3975 !,
3976 insertstr('%('), % to do: use lambda_symbol and improve layout below
3977 pp_expr_indent_l(FrontIDs),
3978 insertstr(') . ('),
3979 pred_over_lines(2,'@body',TLambdaBody),
3980 indent(' | '), increase_indentation_level(2),
3981 indent(''), pp_expr_indent(ToExpr), decrease_indentation_level(2),
3982 indent(')').
3983 pp_expr_indent(b(comprehension_set(Ids,Body),_,Info),(I,S),(I,T)) :-
3984 pp_comprehension_set5(Ids,Body,Info,_,special(_Kind),S,T),
3985 % throw away indent and check if a special pp rule is applicable
3986 !.
3987 pp_expr_indent(b(comprehension_set(Ids,Body),_,_)) -->
3988 !,
3989 insertstr('{'), pp_expr_indent_l(Ids),
3990 insertstr(' | '),
3991 pred_over_lines(2,'@body',Body),
3992 indent('}').
3993 pp_expr_indent(b(convert_bool(Body),_,_)) -->
3994 !,
3995 insertstr('bool('),
3996 pred_over_lines(2,'@bool',Body),
3997 indent(')').
3998 pp_expr_indent(b(IFTE,_,_)) --> {is_ifte(IFTE,Test,Then,Else)},
3999 !,
4000 insertstr('IF'),
4001 pred_over_lines(2,'@test',Test),
4002 indent('THEN'),increase_indentation_level(2),
4003 indent(''),pp_expr_indent(Then),decrease_indentation_level(2),
4004 indent('ELSE'),increase_indentation_level(2),
4005 indent(''),pp_expr_indent(Else),decrease_indentation_level(2),
4006 indent('END').
4007 pp_expr_indent(b(let_expression(Ids,Exprs,Body),_,_)) -->
4008 !,
4009 pp_let_expr_nested(Ids,Exprs,Body).
4010 % TODO: support a few more like dom/ran(comprehension_set) SIGMA, PI, \/ (union), ...
4011 pp_expr_indent(Expr,(I,S),(I,T)) :-
4012 %get_texpr_expr(Expr,F), functor(F,FF,NN), format(user_output,'Cannot indent: ~w/~w~n',[FF,NN]),
4013 pp_expr(Expr,_,_LimitReached,S,T). % throw away indent
4014
4015 can_indent_texpr(b(E,_,_)) :- can_indent_expr(E).
4016 can_indent_expr(comprehension_set(_,_)).
4017 can_indent_expr(convert_bool(_)).
4018 can_indent_expr(if_then_else(_,_,_)).
4019 can_indent_expr(let_expression(_,_,_)).
4020
4021 pp_expr_indent_l([E]) --> !, pp_expr_indent(E).
4022 pp_expr_indent_l(Exprs,(I,S),(I,T)) :-
4023 pp_expr_l(Exprs,_LR,S,T). % throw away indent
4024 pp_expr_m_indent(Expr,MinPrio,(I,S),(I,T)) :-
4025 pp_expr_m(Expr,MinPrio,_LimitReached,S,T).
4026 pp_atom_indent(A,(I,S),(I,T)) :- ppatom(A,S,T).
4027 pp_expr_ids_in_mode_indent(Ids,(I,S),(I,T)) :- pp_expr_ids_in_mode(Ids,_,S,T).
4028
4029
4030
4031
4032 is_boolean_value(b(B,boolean,_),BV) :- boolean_aux(B,BV).
4033 boolean_aux(boolean_true,pred_true).
4034 boolean_aux(boolean_false,pred_false).
4035 boolean_aux(value(V),BV) :- nonvar(V),!,BV=V.
4036
4037
4038 constants_in_mode(F,S) :-
4039 constants(F,S1), translate_in_mode(F,S1,S).
4040
4041 constants(pred_true,'TRUE').
4042 constants(pred_false,'FALSE').
4043 constants(boolean_true,'TRUE').
4044 constants(boolean_false,'FALSE').
4045 constants(max_int,'MAXINT').
4046 constants(min_int,'MININT').
4047 constants(empty_set,'{}').
4048 constants(bool_set,'BOOL').
4049 constants(float_set,'FLOAT').
4050 constants(real_set,'REAL').
4051 constants(string_set,'STRING').
4052 constants(empty_sequence,'[]').
4053 constants(event_b_identity,'id').
4054
4055 constants(truth,Res) :- eventb_translation_mode,!,Res=true.
4056 constants(truth,Res) :- animation_minor_mode(tla),!,Res='TRUE'.
4057 constants(truth,Res) :- atelierb_mode(_),!,Res='(TRUE:BOOL)'. % __truth; we could also do TRUE=TRUE
4058 constants(truth,'btrue').
4059 constants(falsity,Res) :- eventb_translation_mode,!,Res=false.
4060 constants(falsity,Res) :- animation_minor_mode(tla),!,Res='FALSE'.
4061 constants(falsity,Res) :- atelierb_mode(_),!,Res='(TRUE=FALSE)'.
4062 constants(falsity,'bfalse'). % __falsity
4063 constants(unknown_truth_value(Msg),Res) :- % special internal constant
4064 ajoin(['?(',Msg,')'],Res).
4065
4066 function_like_in_mode(F,S) :-
4067 function_like(F,S1),
4068 translate_in_mode(F,S1,S).
4069
4070 function_like(convert_bool,bool).
4071 function_like(convert_real,real). % cannot be used on its own: dom(real) is not accepted by Atelier-B
4072 function_like(convert_int_floor,floor). % ditto
4073 function_like(convert_int_ceiling,ceiling). % ditto
4074 function_like(successor,succ). % can also be used on its own; e.g., dom(succ)=INTEGER is ok
4075 function_like(predecessor,pred). % ditto
4076 function_like(max,max).
4077 function_like(max_real,max).
4078 function_like(min,min).
4079 function_like(min_real,min).
4080 function_like(card,card).
4081 function_like(pow_subset,'POW').
4082 function_like(pow1_subset,'POW1').
4083 function_like(fin_subset,'FIN').
4084 function_like(fin1_subset,'FIN1').
4085 function_like(identity,id).
4086 function_like(first_projection,prj1).
4087 function_like(first_of_pair,'prj1'). % used to be __first_of_pair, will be dealt with separately to generate parsable representation
4088 function_like(second_projection,prj2).
4089 function_like(second_of_pair,'prj2'). % used to be __second_of_pair, will be dealt with separately to generate parsable representation
4090 function_like(iteration,iterate).
4091 function_like(event_b_first_projection_v2,prj1).
4092 function_like(event_b_second_projection_v2,prj2).
4093 function_like(reflexive_closure,closure).
4094 function_like(closure,closure1).
4095 function_like(domain,dom).
4096 function_like(range,ran).
4097 function_like(seq,seq).
4098 function_like(seq1,seq1).
4099 function_like(iseq,iseq).
4100 function_like(iseq1,iseq1).
4101 function_like(perm,perm).
4102 function_like(size,size).
4103 function_like(first,first).
4104 function_like(last,last).
4105 function_like(front,front).
4106 function_like(tail,tail).
4107 function_like(rev,rev).
4108 function_like(general_concat,conc).
4109 function_like(general_union,union).
4110 function_like(general_intersection,inter).
4111 function_like(trans_function,fnc).
4112 function_like(trans_relation,rel).
4113 function_like(tree,tree).
4114 function_like(btree,btree).
4115 function_like(const,const).
4116 function_like(top,top).
4117 function_like(sons,sons).
4118 function_like(prefix,prefix).
4119 function_like(postfix,postfix).
4120 function_like(sizet,sizet).
4121 function_like(mirror,mirror).
4122 function_like(rank,rank).
4123 function_like(father,father).
4124 function_like(son,son).
4125 function_like(subtree,subtree).
4126 function_like(arity,arity).
4127 function_like(bin,bin).
4128 function_like(left,left).
4129 function_like(right,right).
4130 function_like(infix,infix).
4131
4132 function_like(rec,rec).
4133 function_like(struct,struct).
4134
4135 function_like(negation,not).
4136 function_like(bag_items,items).
4137
4138 function_like(finite,finite). % from Event-B, TO DO: if \+ eventb_translation_mode then print as S:FIN(S)
4139 function_like(witness,'@witness'). % from Event-B
4140
4141 function_like(floored_div,'FDIV') :- \+ animation_minor_mode(tla). % using external function
4142
4143 unary_prefix(unary_minus,'\x2212\',210) :- unicode_mode, eventb_translation_mode, !.
4144 unary_prefix(unary_minus,-,210).
4145 unary_prefix(unary_minus_real,-,210).
4146 unary_prefix(mu,'MU',210) :- animation_minor_mode(z).
4147
4148 unary_prefix_parentheses(compaction,'compaction').
4149 unary_prefix_parentheses(bag_items,'bag_items').
4150 unary_prefix_parentheses(mu,'MU') :-
4151 \+ animation_minor_mode(z). % write with () for external function
4152
4153 unary_postfix(reverse,'~',230). % relational inverse
4154 %unary_postfix(mu,'?',250). % TODO: comment in once new parser release made
4155
4156
4157 always_surround_by_parentheses(parallel_product).
4158 always_surround_by_parentheses(composition).
4159
4160 binary_infix_symbol(b(T,_,_),Symbol) :- functor(T,F,2), binary_infix_in_mode(F,Symbol,_,_).
4161
4162 % EXPR * EXPR --> EXPR
4163 binary_infix(composition,';',20,left).
4164 binary_infix(overwrite,'<+',160,left).
4165 binary_infix(direct_product,'><',160,left). % Rodin requires parentheses
4166 binary_infix(parallel_product,'||',20,left).
4167 binary_infix(concat,'^',160,left).
4168 binary_infix(relations,'<->',125,left).
4169 binary_infix(partial_function,'+->',125,left).
4170 binary_infix(total_function,'-->',125,left).
4171 binary_infix(partial_injection,'>+>',125,left).
4172 binary_infix(total_injection,'>->',125,left).
4173 binary_infix(partial_surjection,'+->>',125,left).
4174 binary_infix(total_surjection,Symbol,125,left) :-
4175 (eventb_translation_mode -> Symbol = '->>'; Symbol = '-->>').
4176 binary_infix(total_bijection,'>->>',125,left).
4177 binary_infix(partial_bijection,'>+>>',125,left).
4178 binary_infix(total_relation,'<<->',125,left). % only in Event-B
4179 binary_infix(surjection_relation,'<->>',125,left). % only in Event-B
4180 binary_infix(total_surjection_relation,'<<->>',125,left). % only in Event-B
4181 binary_infix(insert_front,'->',160,left).
4182 binary_infix(insert_tail,'<-',160,left).
4183 binary_infix(domain_restriction,'<|',160,left).
4184 binary_infix(domain_subtraction,'<<|',160,left).
4185 binary_infix(range_restriction,'|>',160,left).
4186 binary_infix(range_subtraction,'|>>',160,left).
4187 binary_infix(intersection,'/\\',160,left).
4188 binary_infix(union,'\\/',160,left).
4189 binary_infix(restrict_front,'/|\\',160,left).
4190 binary_infix(restrict_tail,'\\|/',160,left).
4191 binary_infix(couple,'|->',160,left).
4192 binary_infix(interval,'..',170,left).
4193 binary_infix(add,+,180,left).
4194 binary_infix(add_real,+,180,left).
4195 binary_infix(minus,-,180,left).
4196 binary_infix(minus_real,-,180,left).
4197 binary_infix(set_subtraction,'\\',180,left) :- eventb_translation_mode,!. % symbol is not allowed by Atelier-B
4198 binary_infix(set_subtraction,-,180,left).
4199 binary_infix(minus_or_set_subtract,-,180,left).
4200 binary_infix(multiplication,*,190,left).
4201 binary_infix(multiplication_real,*,190,left).
4202 binary_infix(cartesian_product,**,190,left) :- eventb_translation_mode,!.
4203 binary_infix(cartesian_product,*,190,left).
4204 binary_infix(mult_or_cart,*,190,left). % in case type checker not yet run
4205 binary_infix(div,/,190,left).
4206 binary_infix(div_real,/,190,left).
4207 binary_infix(floored_div,div,190,left) :- animation_minor_mode(tla).
4208 binary_infix(modulo,mod,190,left).
4209 binary_infix(power_of,**,200,right).
4210 binary_infix(power_of_real,**,200,right).
4211 binary_infix(typeof,oftype,120,right). % Event-B oftype operator; usually removed by btypechecker, technically has no associativity in our parser, but right associativity matches better
4212
4213 binary_infix(ring,'\x2218\',160,left). % our B Parser gives ring same priority as direct_product or overwrite
4214
4215 % PRED * PRED --> PRED
4216 binary_infix(implication,'=>',30,left).
4217 binary_infix(conjunct,'&',40,left).
4218 binary_infix(disjunct,or,40,left).
4219 binary_infix(equivalence,'<=>',Prio,left) :- % in Rodin this has the same priority as implication
4220 (eventb_translation_mode -> Prio=30 ; Prio=60).
4221
4222
4223 % EXPR * EXPR --> PRED
4224 binary_infix(equal,=,60,left).
4225 binary_infix(not_equal,'/=',160,left).
4226 binary_infix(less_equal,'<=',160,left).
4227 binary_infix(less,'<',160,left).
4228 binary_infix(less_equal_real,'<=',160,left).
4229 binary_infix(less_real,'<',160,left).
4230 binary_infix(greater_equal,'>=',160,left).
4231 binary_infix(greater,'>',160,left).
4232 binary_infix(member,':',60,left).
4233 binary_infix(not_member,'/:',160,left).
4234 binary_infix(subset,'<:',110,left).
4235 binary_infix(subset_strict,'<<:',110,left).
4236 binary_infix(not_subset,'/<:',110,left).
4237 binary_infix(not_subset_strict,'/<<:',110,left).
4238
4239 binary_infix(values_entry,'=',60,left).
4240
4241 % atelierb_mode(prover(_)): translation for AtelierB's PP/ML prover
4242 % atelierb_mode(native): translation to native B supported by AtelierB
4243 :- dynamic latex_mode/0, unicode_mode/0, atelierb_mode/1, force_eventb_rodin_mode/0.
4244
4245 %latex_mode.
4246 %unicode_mode.
4247 %force_eventb_rodin_mode. % Force Event-B output even if not in eventb minor mode
4248
4249 eventb_translation_mode :- animation_minor_mode(eventb),!.
4250 eventb_translation_mode :- animation_minor_mode(sequent_prover),!.
4251 eventb_translation_mode :- force_eventb_rodin_mode.
4252
4253 set_force_eventb_mode :- assertz(force_eventb_rodin_mode).
4254 unset_force_eventb_mode :-
4255 (retract(force_eventb_rodin_mode) -> true ; add_internal_error('Was not in forced Event-B mode: ',force_eventb_rodin_mode)).
4256
4257 set_unicode_mode :- assertz(unicode_mode).
4258 set_latex_mode :- assertz(latex_mode).
4259 unset_unicode_mode :-
4260 (retract(unicode_mode) -> true ; add_internal_error('Was not in Unicode mode: ',unset_unicode_mode)).
4261 unset_latex_mode :-
4262 (retract(latex_mode) -> true
4263 ; add_internal_error('Was not in Latex mode: ',unset_latex_mode)).
4264
4265 set_atelierb_mode(Mode) :- asserta(atelierb_mode(Mode)).
4266 unset_atelierb_mode :-
4267 (retract(atelierb_mode(_)) -> true ; add_internal_error('Was not in Atelier-B mode: ',unset_atelierb_mode)).
4268
4269 get_translation_mode(M) :- unicode_mode, !, M=unicode.
4270 get_translation_mode(M) :- latex_mode, !, M=latex.
4271 get_translation_mode(M) :- atelierb_mode(native), !, M=atelierb.
4272 get_translation_mode(M) :- atelierb_mode(prover(pp)), !, M=atelierb_pp.
4273 get_translation_mode(M) :- atelierb_mode(prover(ml)), !, M=atelierb_ml.
4274 get_translation_mode(ascii).
4275
4276 % TO DO: provide better stack-based setting/unsetting of modes or use options parameter
4277 set_translation_mode(ascii) :- !, retractall(unicode_mode), retractall(latex_mode), retractall(atelierb_mode(_)).
4278 set_translation_mode(unicode) :- !, set_unicode_mode.
4279 set_translation_mode(latex) :- !, set_latex_mode.
4280 set_translation_mode(atelierb) :- !, set_atelierb_mode(native).
4281 set_translation_mode(atelierb_pp) :- !, set_atelierb_mode(prover(pp)). % translation for PP/ML prover
4282 set_translation_mode(atelierb_ml) :- !, set_atelierb_mode(prover(ml)).
4283 set_translation_mode(Mode) :- add_internal_error('Illegal mode:',set_translation_mode(Mode)).
4284
4285 unset_translation_mode(ascii) :- !.
4286 unset_translation_mode(unicode) :- !,unset_unicode_mode.
4287 unset_translation_mode(latex) :- !,unset_latex_mode.
4288 unset_translation_mode(atelierb) :- !,unset_atelierb_mode.
4289 unset_translation_mode(atelierb_pp) :- !,unset_atelierb_mode.
4290 unset_translation_mode(atelierb_ml) :- !,unset_atelierb_mode.
4291 unset_translation_mode(Mode) :- add_internal_error('Illegal mode:',unset_translation_mode(Mode)).
4292
4293 with_translation_mode(Mode, Call) :-
4294 get_translation_mode(OldMode),
4295 (OldMode == Mode -> Call ;
4296 set_translation_mode(ascii), % Clear all existing translation mode settings first
4297 set_translation_mode(Mode),
4298 call_cleanup(Call, set_translation_mode(OldMode))
4299 % FIXME This might not restore all translation modes fully!
4300 % For example, if both unicode_mode and latex_mode are set,
4301 % then with_translation_mode(ascii, ...) will only restore unicode_mode.
4302 % Not sure if this might cause problems for some code.
4303 ).
4304
4305 % The language mode is currently linked to the animation minor mode,
4306 % so be careful when changing it!
4307 % TODO Allow overriding the language for translate without affecting the animation mode
4308
4309 get_language_mode(csp_and(Lang)) :-
4310 csp_with_bz_mode,
4311 !,
4312 (animation_minor_mode(Lang) -> true ; Lang = b).
4313 get_language_mode(Lang) :- animation_minor_mode(Lang), !.
4314 get_language_mode(Lang) :- animation_mode(Lang).
4315
4316 set_language_mode(csp_and(Lang)) :-
4317 !,
4318 set_animation_mode(csp_and_b),
4319 (Lang == b -> true ; set_animation_minor_mode(Lang)).
4320 set_language_mode(csp) :- !, set_animation_mode(csp).
4321 set_language_mode(xtl) :- !, set_animation_mode(xtl).
4322 set_language_mode(sequent_prover) :- !, set_animation_mode(xtl), set_animation_minor_mode(sequent_prover).
4323 set_language_mode(b) :- !, set_animation_mode(b).
4324 set_language_mode(Lang) :-
4325 set_animation_mode(b),
4326 set_animation_minor_mode(Lang).
4327
4328 with_language_mode(Lang, Call) :-
4329 get_language_mode(OldLang),
4330 (OldLang == Lang -> Call ;
4331 set_language_mode(Lang),
4332 call_cleanup(Call, set_language_mode(OldLang))
4333 % FIXME This might not restore all animation modes fully!
4334 % It's apparently possible to have multiple animation minor modes,
4335 % which get/set_language_mode doesn't handle.
4336 % (Are multiple animation minor modes actually used anywhere?)
4337 ).
4338
4339 exists_symbol --> {latex_mode},!, "\\exists ".
4340 exists_symbol --> {unicode_mode},!, pp_colour_code(magenta),[8707],pp_colour_code(reset).
4341 exists_symbol --> pp_colour_code(blue),"#",pp_colour_code(reset).
4342 forall_symbol --> {latex_mode},!, "\\forall ".
4343 forall_symbol --> {unicode_mode},!, pp_colour_code(magenta),[8704],pp_colour_code(reset).
4344 forall_symbol --> pp_colour_code(blue),"!",pp_colour_code(reset).
4345 dot_symbol --> {latex_mode},!, "\\cdot ".
4346 dot_symbol --> {unicode_mode},!, [183]. %"·". % dot also used in Rodin
4347 dot_symbol --> ".".
4348 dot_bullet_symbol --> {latex_mode},!, "\\cdot ".
4349 dot_bullet_symbol --> [183]. %"·". % dot also used in Rodin
4350 set_brackets(X,Y) :- latex_mode,!,X='\\{', Y='\\}'.
4351 set_brackets('{','}').
4352 left_set_bracket --> {latex_mode},!, "\\{ ".
4353 left_set_bracket --> "{".
4354 right_set_bracket --> {latex_mode},!, "\\} ".
4355 right_set_bracket --> "}".
4356 maplet_symbol --> {latex_mode},!, "\\mapsto ".
4357 maplet_symbol --> {unicode_mode},!, [8614].
4358 maplet_symbol --> "|->". % also provide option to use colours? pp_colour_code(blue) ,...
4359
4360 lambda_symbol --> {unicode_mode},!, [955]. % '\x3BB\'
4361 lambda_symbol --> {latex_mode},!, "\\lambda ".
4362 lambda_symbol --> pp_colour_code(blue),"%",pp_colour_code(reset).
4363
4364 and_symbol --> {unicode_mode},!, [8743]. % ''\x2227\''
4365 and_symbol --> {latex_mode},!, "\\wedge ".
4366 and_symbol --> "&".
4367
4368 hash_card_symbol --> {latex_mode},!, "\\# ".
4369 hash_card_symbol --> "#".
4370 ldots --> {latex_mode},!, "\\ldots ".
4371 ldots --> "...".
4372
4373 empty_set_symbol --> {get_preference(translate_print_all_sequences,true)},!, pp_empty_sequence.
4374 empty_set_symbol --> {unicode_mode},!, [8709].
4375 empty_set_symbol --> {latex_mode},!, "\\emptyset ".
4376 empty_set_symbol --> "{}".
4377
4378 underscore_symbol --> {latex_mode},!, "\\_".
4379 underscore_symbol --> "_".
4380
4381 string_start_symbol --> {latex_mode},!, "\\textnormal{``".
4382 string_start_symbol --> pp_colour_code(blue), """".
4383 string_end_symbol --> {latex_mode},!, "''}".
4384 string_end_symbol --> pp_colour_code(reset), """".
4385
4386
4387 unary_postfix_in_mode(Op,Trans2,Prio) :-
4388 unary_postfix(Op,Trans,Prio), % write(op(Op,Trans)),nl,
4389 translate_in_mode(Op,Trans,Trans2).
4390
4391 binary_infix_in_mode(Op,Trans2,Prio,Assoc) :-
4392 binary_infix(Op,Trans,Prio,Assoc), % write(op(Op,Trans)),nl,
4393 translate_in_mode(Op,Trans,Trans2).
4394
4395 latex_integer_set_translation('NATURAL', '\\mathbb N '). % \nat in bsymb.sty
4396 latex_integer_set_translation('NATURAL1', '\\mathbb N_1 '). % \natn
4397 latex_integer_set_translation('INTEGER', '\\mathbb Z '). % \intg
4398 latex_integer_set_translation('REAL', '\\mathbb R '). % \intg
4399
4400 latex_translation(empty_set, '\\emptyset ').
4401 latex_translation(implication, '\\mathbin\\Rightarrow ').
4402 latex_translation(conjunct,'\\wedge ').
4403 latex_translation(disjunct,'\\vee ').
4404 latex_translation(equivalence,'\\mathbin\\Leftrightarrow ').
4405 latex_translation(negation,'\\neg ').
4406 latex_translation(not_equal,'\\neq ').
4407 latex_translation(less_equal,'\\leq ').
4408 latex_translation(less_equal_real,'\\leq ').
4409 latex_translation(greater_equal,'\\geq ').
4410 latex_translation(member,'\\in ').
4411 latex_translation(not_member,'\\not\\in ').
4412 latex_translation(subset,'\\subseteq ').
4413 latex_translation(subset_strict,'\\subset ').
4414 latex_translation(not_subset,'\\not\\subseteq ').
4415 latex_translation(not_subset_strict,'\\not\\subset ').
4416 latex_translation(union,'\\cup ').
4417 latex_translation(intersection,'\\cap ').
4418 latex_translation(couple,'\\mapsto ').
4419 latex_translation(cartesian_product,'\\times').
4420 latex_translation(rec,'\\mathit{rec}').
4421 latex_translation(struct,'\\mathit{struct}').
4422 latex_translation(convert_bool,'\\mathit{bool}').
4423 latex_translation(max,'\\mathit{max}').
4424 latex_translation(max_real,'\\mathit{max}').
4425 latex_translation(min,'\\mathit{min}').
4426 latex_translation(min_real,'\\mathit{min}').
4427 latex_translation(modulo,'\\mod ').
4428 latex_translation(card,'\\mathit{card}').
4429 latex_translation(successor,'\\mathit{succ}').
4430 latex_translation(predecessor,'\\mathit{pred}').
4431 latex_translation(domain,'\\mathit{dom}').
4432 latex_translation(range,'\\mathit{ran}').
4433 latex_translation(size,'\\mathit{size}').
4434 latex_translation(first,'\\mathit{first}').
4435 latex_translation(last,'\\mathit{last}').
4436 latex_translation(front,'\\mathit{front}').
4437 latex_translation(tail,'\\mathit{tail}').
4438 latex_translation(rev,'\\mathit{rev}').
4439 latex_translation(seq,'\\mathit{seq}').
4440 latex_translation(seq1,'\\mathit{seq}_{1}').
4441 latex_translation(perm,'\\mathit{perm}').
4442 latex_translation(fin_subset,'\\mathit{FIN}').
4443 latex_translation(fin1_subset,'\\mathit{FIN}_{1}').
4444 latex_translation(first_projection,'\\mathit{prj}_{1}').
4445 latex_translation(second_projection,'\\mathit{prj}_{2}').
4446 latex_translation(pow_subset,'\\mathbb P\\hbox{}'). % POW \pow would require bsymb.sty
4447 latex_translation(pow1_subset,'\\mathbb P_1'). % POW1 \pown would require bsymb.sty
4448 latex_translation(concat,'\\stackrel{\\frown}{~}'). % was '\\hat{~}').
4449 latex_translation(relations,'\\mathbin\\leftrightarrow'). % <->, \rel requires bsymb.sty
4450 latex_translation(total_relation,'\\mathbin{\\leftarrow\\mkern-14mu\\leftrightarrow}'). % <<-> \trel requires bsymb.sty
4451 latex_translation(total_surjection_relation,'\\mathbin{\\leftrightarrow\\mkern-14mu\\leftrightarrow}'). % <<->> \strel requires bsymb.sty
4452 latex_translation(surjection_relation,'\\mathbin{\\leftrightarrow\\mkern-14mu\\rightarrow}'). % <->> \srel requires bsymb.sty
4453 latex_translation(partial_function,'\\mathbin{\\mkern6mu\\mapstochar\\mkern-6mu\\rightarrow}'). % +-> \pfun requires bsymb.sty, but \mapstochar is not supported by Mathjax
4454 latex_translation(partial_injection,'\\mathbin{\\mkern9mu\\mapstochar\\mkern-9mu\\rightarrowtail}'). % >+> \pinj requires bsymb.sty
4455 latex_translation(partial_surjection,'\\mathbin{\\mkern6mu\\mapstochar\\mkern-6mu\\twoheadrightarrow}'). % >+> \psur requires bsymb.sty
4456 latex_translation(total_function,'\\mathbin\\rightarrow'). % --> \tfun would require bsymb.sty
4457 latex_translation(total_surjection,'\\mathbin\\twoheadrightarrow'). % -->> \tsur requires bsymb.sty
4458 latex_translation(total_injection,'\\mathbin\\rightarrowtail'). % >-> \tinj requires bsymb.sty
4459 latex_translation(total_bijection,'\\mathbin{\\rightarrowtail\\mkern-18mu\\twoheadrightarrow}'). % >->> \tbij requires bsymb.sty
4460 latex_translation(domain_restriction,'\\mathbin\\lhd'). % <| domres requires bsymb.sty
4461 latex_translation(range_restriction,'\\mathbin\\rhd'). % |> ranres requires bsymb.sty
4462 latex_translation(domain_subtraction,'\\mathbin{\\lhd\\mkern-14mu-}'). % <<| domsub requires bsymb.sty
4463 latex_translation(range_subtraction,'\\mathbin{\\rhd\\mkern-14mu-}'). % |>> ransub requires bsymb.sty
4464 latex_translation(overwrite,'\\mathbin{\\lhd\\mkern-9mu-}'). % <+ \ovl requires bsymb.sty
4465 latex_translation(ring,'\\circ '). % not tested
4466 latex_translation(general_sum,'\\Sigma ').
4467 latex_translation(general_product,'\\Pi ').
4468 latex_translation(lambda,'\\lambda ').
4469 latex_translation(quantified_union,'\\bigcup\\nolimits'). % \Union requires bsymb.sty
4470 latex_translation(quantified_intersection,'\\bigcap\\nolimits'). % \Inter requires bsymb.sty
4471 %latex_translation(truth,'\\top').
4472 %latex_translation(falsity,'\\bot').
4473 latex_translation(truth,'{\\color{olive} \\top}'). % requires \usepackage{xcolor} in Latex
4474 latex_translation(falsity,'{\\color{red} \\bot}').
4475 latex_translation(boolean_true,'{\\color{olive} \\mathit{TRUE}}').
4476 latex_translation(boolean_false,'{\\color{red} \\mathit{FALSE}}').
4477 latex_translation(pred_true,'{\\color{olive} \\mathit{TRUE}}').
4478 latex_translation(pred_false,'{\\color{red} \\mathit{FALSE}}').
4479 latex_translation(reverse,'^{-1}').
4480
4481 ascii_to_unicode(Ascii,Unicode) :-
4482 translate_prolog_constructor(BAst,Ascii), % will not backtrack
4483 unicode_translation(BAst,Unicode).
4484
4485
4486 % can be used to translate Latex shortcuts to B Unicode operators for editors
4487 latex_to_unicode(LatexShortcut,Unicode) :-
4488 latex_to_b_ast(LatexShortcut,BAst),
4489 unicode_translation(BAst,Unicode).
4490 latex_to_unicode(LatexShortcut,Unicode) :- % allow to use B AST names as well
4491 unicode_translation(LatexShortcut,Unicode).
4492 latex_to_unicode(LatexShortcut,Unicode) :-
4493 greek_symbol(LatexShortcut,Unicode).
4494
4495 get_latex_keywords(List) :-
4496 findall(Id,latex_to_unicode(Id,_),Ids),
4497 sort(Ids,List).
4498
4499 get_latex_keywords_with_backslash(BList) :-
4500 get_latex_keywords(List),
4501 maplist(atom_concat('\\'),List,BList).
4502
4503 latex_to_b_ast(and,conjunct).
4504 latex_to_b_ast(bcomp,ring). % bsymb: backwards composition
4505 latex_to_b_ast(bigcap,quantified_intersection).
4506 latex_to_b_ast(bigcup,quantified_union).
4507 latex_to_b_ast(cap,intersection).
4508 latex_to_b_ast(cart,cartesian_product).
4509 latex_to_b_ast(cprod,cartesian_product).
4510 latex_to_b_ast(cdot,dot_symbol).
4511 latex_to_b_ast(cup,union).
4512 latex_to_b_ast(dprod,direct_product).
4513 latex_to_b_ast(dres,domain_restriction).
4514 latex_to_b_ast(dsub,domain_subtraction).
4515 latex_to_b_ast(emptyset,empty_set).
4516 latex_to_b_ast(exp,power_of).
4517 %latex_to_b_ast(fcomp,composition). % bsymb: forwards composition
4518 latex_to_b_ast(geq,greater_equal).
4519 latex_to_b_ast(implies,implication).
4520 latex_to_b_ast(in,member).
4521 latex_to_b_ast(int,'INTEGER').
4522 latex_to_b_ast(intg,'INTEGER'). % from bsymb
4523 latex_to_b_ast(lambda,lambda).
4524 latex_to_b_ast(land,conjunct).
4525 latex_to_b_ast(leq,less_equal).
4526 latex_to_b_ast(leqv,equivalence).
4527 latex_to_b_ast(lhd,domain_restriction).
4528 latex_to_b_ast(limp,implication).
4529 latex_to_b_ast(lor,disjunct).
4530 latex_to_b_ast(lnot,negation).
4531 latex_to_b_ast(mapsto,couple).
4532 latex_to_b_ast(nat,'NATURAL').
4533 latex_to_b_ast(natn,'NATURAL1').
4534 latex_to_b_ast(neg,negation).
4535 latex_to_b_ast(neq,not_equal).
4536 latex_to_b_ast(nin,not_member).
4537 latex_to_b_ast(not,negation).
4538 latex_to_b_ast(nsubseteq,not_subset).
4539 latex_to_b_ast(nsubset,not_subset_strict).
4540 latex_to_b_ast(or,disjunct).
4541 %latex_to_b_ast(ovl,overwrite).
4542 latex_to_b_ast(pfun,partial_function).
4543 latex_to_b_ast(pinj,partial_injection).
4544 latex_to_b_ast(psur,partial_surjection).
4545 latex_to_b_ast(pow,pow_subset).
4546 latex_to_b_ast(pown,pow1_subset).
4547 latex_to_b_ast(pprod,parallel_product).
4548 latex_to_b_ast(qdot,dot_symbol).
4549 latex_to_b_ast(real,'REAL').
4550 latex_to_b_ast(rel,relations).
4551 latex_to_b_ast(rhd,range_restriction).
4552 latex_to_b_ast(rres,range_restriction).
4553 latex_to_b_ast(rsub,range_subtraction).
4554 latex_to_b_ast(srel,surjection_relation).
4555 latex_to_b_ast(subseteq,subset).
4556 latex_to_b_ast(subset,subset_strict).
4557 latex_to_b_ast(tbij,total_bijection).
4558 latex_to_b_ast(tfun,total_function).
4559 latex_to_b_ast(tinj,total_injection).
4560 latex_to_b_ast(trel,total_relation).
4561 latex_to_b_ast(tsrel,total_surjection_relation).
4562 latex_to_b_ast(tsur,total_surjection).
4563 latex_to_b_ast(upto,interval).
4564 latex_to_b_ast(vee,disjunct).
4565 latex_to_b_ast(wedge,conjunct).
4566 latex_to_b_ast('INT','INTEGER').
4567 latex_to_b_ast('NAT','NATURAL').
4568 latex_to_b_ast('N','NATURAL').
4569 latex_to_b_ast('Pi',general_product).
4570 latex_to_b_ast('POW',pow_subset).
4571 latex_to_b_ast('REAL','REAL').
4572 latex_to_b_ast('Rightarrow',implication).
4573 latex_to_b_ast('Sigma',general_sum).
4574 latex_to_b_ast('Leftrightarrow',equivalence).
4575 latex_to_b_ast('Inter',quantified_intersection).
4576 latex_to_b_ast('Union',quantified_union).
4577 latex_to_b_ast('Z','INTEGER').
4578
4579 unicode_translation(implication, '\x21D2\').
4580 unicode_translation(conjunct,'\x2227\').
4581 unicode_translation(disjunct,'\x2228\'). % \vee
4582 unicode_translation(negation,'\xAC\').
4583 unicode_translation(equivalence,'\x21D4\').
4584 unicode_translation(not_equal,'\x2260\').
4585 unicode_translation(less_equal,'\x2264\').
4586 unicode_translation(less_equal_real,'\x2264\').
4587 unicode_translation(greater_equal,'\x2265\').
4588 unicode_translation(member,'\x2208\').
4589 unicode_translation(not_member,'\x2209\').
4590 unicode_translation(subset,'\x2286\').
4591 unicode_translation(subset_strict,'\x2282\').
4592 unicode_translation(not_subset,'\x2288\').
4593 unicode_translation(not_subset_strict,'\x2284\').
4594 unicode_translation(supseteq,'\x2287\'). % ProB parser supports unicode symbol by reversing arguments
4595 unicode_translation(supset_strict,'\x2283\'). % ditto
4596 unicode_translation(not_supseteq,'\x2289\'). % ditto
4597 unicode_translation(not_supset_strict,'\x2285\'). % ditto
4598 unicode_translation(union,'\x222A\').
4599 unicode_translation(intersection,'\x2229\').
4600 unicode_translation(cartesian_product,'\xD7\'). % also 0x2217 in Camille or 0x2A2F (vector or cross product) in IDP
4601 unicode_translation(couple,'\x21A6\').
4602 unicode_translation(div,'\xF7\').
4603 unicode_translation(multiplication,'\x2217\') :- eventb_translation_mode. % Rodin asterisk operator
4604 unicode_translation(minus,'\x2212\') :- eventb_translation_mode. % Rodin minus
4605 unicode_translation(unary_minus,'\x2212\') :- eventb_translation_mode.
4606 unicode_translation(dot_symbol,'\xB7\'). % not a B AST operator, cf dot_symbol 183
4607 unicode_translation(floored_div,'\xF7\') :-
4608 animation_minor_mode(tla). % should we provide another Unicode character here for B?
4609 unicode_translation(power_of,'\x02C4\') :- \+ eventb_translation_mode. % version of ^, does not exist in Rodin ?!, upwards arrow x2191 used below for restrict front
4610 unicode_translation(power_of,'\x5E\') :- eventb_translation_mode.
4611 unicode_translation(power_of_real,'\x02C4\').
4612 unicode_translation(interval,'\x2025\').
4613 unicode_translation(domain_restriction,'\x25C1\').
4614 unicode_translation(domain_subtraction,'\x2A64\').
4615 unicode_translation(range_restriction,'\x25B7\').
4616 unicode_translation(range_subtraction,'\x2A65\').
4617 unicode_translation(relations,'\x2194\').
4618 unicode_translation(partial_function,'\x21F8\').
4619 unicode_translation(total_function,'\x2192\').
4620 unicode_translation(partial_injection,'\x2914\').
4621 unicode_translation(partial_surjection,'\x2900\').
4622 unicode_translation(total_injection,'\x21A3\').
4623 unicode_translation(total_surjection,'\x21A0\').
4624 unicode_translation(total_bijection,'\x2916\').
4625 unicode_translation('INTEGER','\x2124\').
4626 unicode_translation('NATURAL','\x2115\').
4627 unicode_translation('NATURAL1','\x2115\\x2081\') :- \+ eventb_translation_mode. % \x2081\ is subscript 1, not accepted by Rodin
4628 unicode_translation('NATURAL1','\x2115\\x31\') :- eventb_translation_mode. % N1
4629 unicode_translation('REAL','\x211D\'). % 8477 in decimal
4630 unicode_translation(real_set,'\x211D\').
4631 %unicode_translation(bool_set,'\x1D539\'). % conversion used by IDP, but creates SPIO_E_ENCODING_INVALID problem
4632 unicode_translation(pow_subset,'\x2119\').
4633 unicode_translation(pow1_subset,'\x2119\\x2081\') :- \+ eventb_translation_mode. % \x2081\ is subscript 1
4634 unicode_translation(pow1_subset,'\x2119\\x31\') :- eventb_translation_mode. % P1
4635 unicode_translation(lambda,'\x3BB\').
4636 unicode_translation(general_product,'\x220F\').
4637 unicode_translation(general_sum,'\x2211\').
4638 unicode_translation(quantified_union,'\x22C3\'). % 8899 in decimal
4639 unicode_translation(quantified_intersection,'\x22C2\'). % 8898 in decimal
4640 unicode_translation(empty_set,'\x2205\').
4641 unicode_translation(truth,'\x22A4\'). % 8868 in decimal
4642 unicode_translation(falsity,'\x22A5\'). % 8869 in decimal
4643 unicode_translation(direct_product,'\x2297\').
4644 unicode_translation(parallel_product,'\x2225\').
4645 unicode_translation(reverse,'\x207B\\xB9\') :- \+ eventb_translation_mode. % the one ¹ is ASCII 185, this symbol is not accepted by Rodin
4646 unicode_translation(reverse,'\x223c\') :- eventb_translation_mode. % tilde operator used by Rodin
4647 % unicode_translation(infinity,'\x221E\'). % 8734 in decimal
4648 unicode_translation(concat,'\x2312\'). % Arc character
4649 unicode_translation(insert_front,'\x21FE\').
4650 unicode_translation(insert_tail,'\x21FD\').
4651 unicode_translation(restrict_front,'\x2191\'). % up arrow
4652 unicode_translation(restrict_tail,'\x2192\').
4653 unicode_translation(forall, '\x2200\'). % usually forall_symbol used
4654 unicode_translation(exists, '\x2203\'). % usually exists_symbol used
4655 unicode_translation(eqeq,'\x225c\').
4656
4657 unicode_translation(total_relation,'\xE100\') :- force_eventb_rodin_mode. % use this custom symbol only in forced Rodin mode, cannot be displayed by most editors, but is important for BPR proof files
4658 unicode_translation(surjection_relation,'\xE101\') :- force_eventb_rodin_mode. % ditto
4659 unicode_translation(total_surjection_relation,'\xE102\') :- force_eventb_rodin_mode. % ditto
4660 unicode_translation(overwrite,'\xE103\') :- force_eventb_rodin_mode. % ditto, from kernel_lang_20.pdf
4661 unicode_translation(ring,'\x2218\'). % from Event-B
4662 unicode_translation(set_subtraction,'\x2216\'). % used by Rodin
4663 unicode_translation(typeof,'\x2982\'). % Event-B oftype operator
4664
4665 % see Chapter 3 of Atelier-B prover manual:
4666 %atelierb_pp_translation(E,PP,_) :- write(pp(PP,E)),nl,fail.
4667 atelierb_pp_translation(set_minus,pp,'_moinsE'). % is set_subtraction ??
4668 atelierb_pp_translation(cartesian_product,pp,'_multE').
4669 atelierb_pp_translation('INTEGER',_,'INTEGER').
4670 %atelierb_pp_translation('INT','(MININT..MAXINT)'). % does not seem necessary
4671 atelierb_pp_translation('NATURAL',_,'NATURAL').
4672 atelierb_pp_translation('NATURAL1',_,'(NATURAL - {0})').
4673 atelierb_pp_translation('NAT1',_,'(NAT - {0})').
4674 %atelierb_pp_translation('NAT','(0..MAXINT)'). % does not seem necessary
4675 %atelierb_pp_translation('NAT1','(1..MAXINT)'). % does not seem necessary
4676 atelierb_pp_translation(truth,_,btrue).
4677 atelierb_pp_translation(falsity,_,bfalse).
4678 atelierb_pp_translation(boolean_true,_,'TRUE').
4679 atelierb_pp_translation(boolean_false,_,'FALSE').
4680 atelierb_pp_translation(empty_sequence,_,'{}').
4681
4682
4683
4684 quantified_in_mode(F,S) :-
4685 quantified(F,S1), translate_in_mode(F,S1,S).
4686
4687 translate_in_mode(F,S1,Result) :-
4688 ( unicode_mode, unicode_translation(F,S) -> true
4689 ; latex_mode, latex_translation(F,S) -> true
4690 ; atelierb_mode(prover(PPML)), atelierb_pp_translation(F,PPML,S) -> true
4691 ; colour_translation(F,S1,S) -> true
4692 ; S1=S),
4693 (colour_translation(F,S,Res) -> Result=Res ; Result=S).
4694
4695 :- use_module(tools_printing,[get_terminal_colour_code/2, no_color/0]).
4696 use_colour_codes :- \+ no_color,
4697 get_preference(pp_with_terminal_colour,true).
4698 colour_translation(F,S1,Result) :- use_colour_codes,
4699 colour_construct(F,Colour),!,
4700 get_terminal_colour_code(Colour,R1),
4701 get_terminal_colour_code(reset,R2),
4702 ajoin([R1,S1,R2],Result).
4703 colour_construct(pred_true,green).
4704 colour_construct(pred_false,red).
4705 colour_construct(boolean_true,green).
4706 colour_construct(boolean_false,red).
4707 colour_construct(truth,green).
4708 colour_construct(falsity,red).
4709 colour_construct(_,blue).
4710
4711 gen_term_color(Col) --> {use_colour_codes},!, {get_terminal_colour_code(Col,R1), atom_codes(R1,CC)},CC.
4712 gen_term_color(_) --> [].
4713
4714 % pretty print a colour code if colours are enabled:
4715 pp_colour_code(Colour) --> {use_colour_codes,get_terminal_colour_code(Colour,C), atom_codes(C,CC)},!,CC.
4716 pp_colour_code(_) --> [].
4717
4718
4719 quantified(general_sum,'SIGMA').
4720 quantified(general_product,'PI').
4721 quantified(quantified_union,'UNION').
4722 quantified(quantified_intersection,'INTER').
4723 quantified(lambda,X) :- atom_codes(X,[37]).
4724 quantified(forall,'!').
4725 quantified(exists,'#').
4726
4727
4728 translate_prolog_constructor(C,R) :- unary_prefix(C,R,_),!.
4729 translate_prolog_constructor(C,R) :- unary_postfix(C,R,_),!.
4730 translate_prolog_constructor(C,R) :- binary_infix_in_mode(C,R,_,_),!.
4731 translate_prolog_constructor(C,R) :- function_like_in_mode(C,R),!.
4732 translate_prolog_constructor(C,R) :- constants_in_mode(C,R),!.
4733 translate_prolog_constructor(C,R) :- quantified_in_mode(C,R),!.
4734
4735 % translate the Prolog constuctor of an AST node into a form for printing to the user
4736 translate_prolog_constructor_in_mode(Constructor,Result) :-
4737 unicode_mode,
4738 unicode_translation(Constructor,Unicode),!, Result=Unicode.
4739 translate_prolog_constructor_in_mode(Constructor,Result) :-
4740 latex_mode,
4741 latex_translation(Constructor,Latex),!, Result=Latex.
4742 translate_prolog_constructor_in_mode(C,R) :- translate_prolog_constructor(C,R).
4743
4744 translate_subst_or_bexpr_in_mode(Mode,TExpr,String) :-
4745 with_translation_mode(Mode, translate_subst_or_bexpr(TExpr,String)).
4746
4747
4748 translate_bexpression_to_unicode(TExpr,String) :-
4749 with_translation_mode(unicode, translate_bexpression(TExpr,String)).
4750
4751 translate_bexpression(TExpr,String) :-
4752 (pp_expr(TExpr,String) -> true
4753 ; add_error(translate_bexpression,'Could not translate bexpression: ',TExpr),String='???').
4754
4755 translate_bexpression_to_codes(TExpr,Codes) :-
4756 reset_pp,
4757 pp_expr(TExpr,_,_LimitReached,Codes,[]).
4758
4759 pp_expr(TExpr,String) :-
4760 translate_bexpression_to_codes(TExpr,Codes),
4761 atom_codes_with_limit(String, Codes).
4762
4763 translate_bexpression_with_limit(T,S) :- translate_bexpression_with_limit(T,200,report_errors,S).
4764 translate_bexpression_with_limit(TExpr,Limit,String) :-
4765 translate_bexpression_with_limit(TExpr,Limit,report_errors,String).
4766 translate_bexpression_with_limit(TExpr,Limit,report_errors,String) :- compound(String),!,
4767 add_internal_error('Result is instantiated to a compound term:',
4768 translate_bexpression_with_limit(TExpr,Limit,report_errors,String)),fail.
4769 translate_bexpression_with_limit(TExpr,Limit,ReportErrors,String) :-
4770 (catch_call(pp_expr_with_limit(TExpr,Limit,String)) -> true
4771 ; (ReportErrors=report_errors,
4772 add_error(translate_bexpression,'Could not translate bexpression: ',TExpr),String='???')).
4773
4774 pp_expr_with_limit(TExpr,Limit,String) :-
4775 set_up_limit_reached(Codes,Limit,LimitReached),
4776 reset_pp,
4777 pp_expr(TExpr,_,LimitReached,Codes,[]),
4778 atom_codes_with_limit(String, Limit, Codes).
4779
4780
4781
4782 % pretty-type an expression, if the expression has a priority >MinPrio, parenthesis
4783 % can be ommitted, if not the expression has to be put into parenthesis
4784 pp_expr_m(TExpr,MinPrio,LimitReached,S,Srest) :-
4785 add_outer_paren(Prio,MinPrio,S,Srest,X,Xrest), % use co-routine to instantiate S as soon as possible
4786 pp_expr(TExpr,Prio,LimitReached,X,Xrest).
4787
4788 :- block add_outer_paren(-,?,?,?,?,?).
4789 add_outer_paren(Prio,MinPrio,S,Srest,X,Xrest) :-
4790 ( Prio > MinPrio -> % was >=, but problem with & / or with same priority or with non associative operators !
4791 S=X, Srest=Xrest
4792 ;
4793 [Open] = "(", [Close] = ")",
4794 S = [Open|X], Xrest = [Close|Srest]).
4795 % warning: if prio not set we will have a pending co-routine and instantiation_error in atom_codes later
4796
4797 :- use_module(translate_keywords,[classical_b_keyword/1, translate_keyword_id/2]).
4798 translated_identifier('_zzzz_binary',R) :- !,
4799 (latex_mode -> R='z''''' ; R='z__'). % TO DO: could cause clash with user IDs
4800 translated_identifier('_zzzz_unary',R) :- !,
4801 (latex_mode -> R='z''' ; R='z_'). % TO DO: ditto
4802 translated_identifier('__RANGE_LAMBDA__',R) :- !,
4803 (latex_mode -> R='\\rho\'' ; unicode_mode -> R= '\x03c1\' % RHO
4804 ; R = 'RANGE_LAMBDA__'). %ditto, could clash with user IDs !!
4805 % TO DO: do we need to treat _prj_arg1__, _prj_arg2__, _lambda_result_ here ?
4806 translated_identifier(ID,Result) :-
4807 latex_mode,!,
4808 my_greek_latex_escape_atom(ID,Greek,Res), %print_message(translate_latex(ID,Greek,Res)),
4809 (Greek=greek -> Result = Res ; ajoin(['\\mathit{',Res,'}'],Result)).
4810 translated_identifier(X,X).
4811
4812 ?pp_identifier(Atom) --> {id_requires_escaping(Atom), \+ eventb_translation_mode, \+ latex_mode}, !,
4813 ({atelierb_mode(_)}
4814 -> pp_identifier_for_atelierb(Atom)
4815 ; pp_backquoted_identifier(Atom)
4816 ).
4817 pp_identifier(Atom) --> ppatom_opt_scramble(Atom).
4818
4819 % print atom using backquotes, we use same escaping rules as in a string
4820 % requires B parser version 2.9.30 or newer
4821 pp_backquoted_identifier(Atom) --> {atom_codes(Atom,Codes)}, pp_backquoted_id_codes(Codes,outer).
4822 pp_backquoted_id_codes(Codes,_) --> {append(Prefix,[0'. | Suffix],Codes), Suffix=[_|_]},
4823 !, % we need to split the id and quote each part separately; otherwise the parser will complain
4824 % see issue https://github.com/hhu-stups/prob-issues/issues/321
4825 % However, ids with dots are not accepted for constants and variables; so this does not solve all problems
4826 ({id_codes_requires_escaping(Prefix)}
4827 -> "`", pp_codes_opt_scramble(Prefix), "`"
4828 ; pp_codes_opt_scramble(Prefix)
4829 ), ".",
4830 pp_backquoted_id_codes(Suffix,inner).
4831 pp_backquoted_id_codes(Codes,inner) --> % last part of an id with dots
4832 {\+ id_codes_requires_escaping(Codes)},
4833 !, pp_codes_opt_scramble(Codes).
4834 pp_backquoted_id_codes(Codes,_) --> "`", pp_codes_opt_scramble(Codes), "`".
4835
4836 id_codes_requires_escaping(Codes) :- atom_codes(PA,Codes),id_requires_escaping(PA).
4837 :- use_module(tools_strings,[is_simple_classical_b_identifier/1]).
4838 id_requires_escaping(ID) :- classical_b_keyword(ID).
4839 id_requires_escaping(ID) :- \+ is_simple_classical_b_identifier(ID).
4840
4841 pp_identifier_for_atelierb(Atom) -->
4842 {atom_codes(Atom,Codes),
4843 strip_illegal_id_codes(Codes,Change,Codes2),
4844 Change==true},!,
4845 {atom_codes(A2,Codes2)},
4846 ppatom_opt_scramble(A2).
4847 pp_identifier_for_atelierb(Atom) --> ppatom_opt_scramble(Atom).
4848
4849 % remove illegal codes in an identifier (probably EventB or Z)
4850 strip_illegal_id_codes([0'_ | T ],Change,[946 | TR]) :- !, Change=true, strip_illegal_id_codes(T,_,TR).
4851 strip_illegal_id_codes(Codes,Change,Res) :- strip_illegal_id_codes2(Codes,Change,Res).
4852
4853 strip_illegal_id_codes2([],_,[]).
4854 strip_illegal_id_codes2([H|T],Change,Res) :- strip_code(H,Res,TR),!, Change=true, strip_illegal_id_codes2(T,_,TR).
4855 strip_illegal_id_codes2([H|T],Change,[H|TR]) :- strip_illegal_id_codes2(T,Change,TR).
4856
4857 strip_code(46,[0'_, 0'_ |T],T). % replace dot . by two underscores
4858 strip_code(36,[946|T],T) :- T \= [48]. % replace dollar $ by beta unless it is $0 at the end
4859 strip_code(92,[950|T],T). % replace dollar by zeta; probably from Zed
4860 % TODO: add more symbols and ensure that the new codes do not exist
4861
4862
4863
4864 :- use_module(tools,[latex_escape_atom/2]).
4865
4866 greek_or_math_symbol(Symbol) :- greek_symbol(Symbol,_).
4867 % other Latex math symbols
4868 greek_or_math_symbol('varepsilon').
4869 greek_or_math_symbol('varphi').
4870 greek_or_math_symbol('varpi').
4871 greek_or_math_symbol('varrho').
4872 greek_or_math_symbol('varsigma').
4873 greek_or_math_symbol('vartheta').
4874 greek_or_math_symbol('vdash').
4875 greek_or_math_symbol('models').
4876
4877 greek_symbol('Alpha','\x0391\').
4878 greek_symbol('Beta','\x0392\').
4879 greek_symbol('Chi','\x03A7\').
4880 greek_symbol('Delta','\x0394\').
4881 greek_symbol('Epsilon','\x0395\').
4882 greek_symbol('Eta','\x0397\').
4883 greek_symbol('Gamma','\x0393\').
4884 greek_symbol('Iota','\x0399\').
4885 greek_symbol('Kappa','\x039A\').
4886 greek_symbol('Lambda','\x039B\').
4887 greek_symbol('Mu','\x039C\').
4888 greek_symbol('Nu','\x039D\').
4889 greek_symbol('Phi','\x03A6\').
4890 greek_symbol('Pi','\x03A0\').
4891 greek_symbol('Psi','\x03A8\').
4892 greek_symbol('Rho','\x03A1\').
4893 greek_symbol('Omega','\x03A9\').
4894 greek_symbol('Omicron','\x039F\').
4895 greek_symbol('Sigma','\x03A3\').
4896 greek_symbol('Theta','\x0398\').
4897 greek_symbol('Upsilon','\x03A5\').
4898 greek_symbol('Xi','\x039E\').
4899 greek_symbol('alpha','\x03B1\').
4900 greek_symbol('beta','\x03B2\').
4901 greek_symbol('delta','\x03B4\').
4902 greek_symbol('chi','\x03C7\').
4903 greek_symbol('epsilon','\x03B5\').
4904 greek_symbol('eta','\x03B7\').
4905 greek_symbol('gamma','\x03B3\').
4906 greek_symbol('iota','\x03B9\').
4907 greek_symbol('kappa','\x03BA\').
4908 greek_symbol('lambda','\x03BB\').
4909 greek_symbol('mu','\x03BC\').
4910 greek_symbol('nu','\x03BD\').
4911 greek_symbol('omega','\x03C9\').
4912 greek_symbol('omicron','\x03BF\').
4913 greek_symbol('pi','\x03C0\').
4914 greek_symbol('phi','\x03C6\').
4915 greek_symbol('psi','\x03C8\').
4916 greek_symbol('rho','\x03C1\').
4917 greek_symbol('sigma','\x03C3\').
4918 greek_symbol('tau','\x03C4\').
4919 greek_symbol('theta','\x03B8\').
4920 greek_symbol('upsilon','\x03C5\').
4921 greek_symbol('xi','\x03BE\').
4922 greek_symbol('zeta','\x03B6\').
4923
4924
4925 my_greek_latex_escape_atom(A,greek,Res) :-
4926 greek_or_math_symbol(A),get_preference(latex_pp_greek_ids,true),!,
4927 atom_concat('\\',A,Res).
4928 my_greek_latex_escape_atom(A,no_greek,EA) :- latex_escape_atom(A,EA).
4929
4930 % ppatom + scramble if BUGYLY is TRUE
4931 ppatom_opt_scramble(Name) --> {get_preference(bugly_pp_scrambling,true)},
4932 % {\+ bmachine:b_top_level_operation(Name)}, % comment in to not change name of B operations
4933 !,
4934 {bugly_scramble_id(Name,ScrName)},
4935 ppatom(ScrName).
4936 ppatom_opt_scramble(Name) -->
4937 {primes_to_unicode(Name, UnicodeName)},
4938 pp_atom_opt_latex(UnicodeName).
4939
4940 % Convert ASCII primes (apostrophes) in identifiers to Unicode primes
4941 % so they can be parsed by the classical B parser.
4942 primes_to_unicode(Name, UnicodeName) :-
4943 atom_codes(Name, Codes),
4944 phrase(primes_to_unicode(Codes), UCodes),
4945 atom_codes(UnicodeName, UCodes).
4946 primes_to_unicode([0'\'|T]) --> !,
4947 "\x2032\",
4948 primes_to_unicode(T).
4949 primes_to_unicode([C|T]) --> !,
4950 [C],
4951 primes_to_unicode(T).
4952 primes_to_unicode([]) --> "".
4953
4954 :- use_module(tools,[b_string_escape_codes/2]).
4955 :- use_module(tools_strings,[convert_atom_to_number/2]).
4956 % a version of ppatom which encodes/quotes symbols inside strings such as quotes "
4957 ppstring_opt_scramble(Name) --> {var(Name)},!,ppatom(Name).
4958 ppstring_opt_scramble(Name) --> {compound(Name)},!,
4959 {add_internal_error('Not an atom: ',ppstring_opt_scramble(Name,_,_))},
4960 "<<" ,ppterm(Name), ">>".
4961 ppstring_opt_scramble(Name) --> {get_preference(bugly_pp_scrambling,true)},!,
4962 pp_bugly_composed_string(Name).
4963 ppstring_opt_scramble(Name) --> {atom_codes(Name,Codes),b_string_escape_codes(Codes,EscCodes)},
4964 pp_codes_opt_latex(EscCodes).
4965
4966 % a version of ppstring_opt_scramble with codes list
4967 pp_codes_opt_scramble(Codes) --> {get_preference(bugly_pp_scrambling,true)},!,
4968 pp_bugly_composed_string_codes(Codes,[]).
4969 pp_codes_opt_scramble(Codes) --> {b_string_escape_codes(Codes,EscCodes)},
4970 pp_codes_opt_latex(EscCodes).
4971
4972 pp_bugly_composed_string(Name) --> {atom_codes(Name,Codes)},
4973 !, % we can decompose the string; scramble each string separately; TODO: provide option to define separators
4974 % idea is that if we have a string with spaces or other special separators we preserve the separators
4975 pp_bugly_composed_string_codes(Codes,[]).
4976
4977 pp_bugly_composed_string_codes([],Acc) --> {atom_codes(Atom,Acc)}, pp_bugly_string(Atom).
4978 pp_bugly_composed_string_codes(List,Acc) --> {decompose_string(List,Seps,T)},!,
4979 {reverse(Acc,Rev),atom_codes(Atom,Rev)}, pp_bugly_string(Atom),
4980 ppcodes(Seps),
4981 pp_bugly_composed_string_codes(T,[]).
4982 pp_bugly_composed_string_codes([H|T],Acc) --> pp_bugly_composed_string_codes(T,[H|Acc]).
4983
4984 decompose_string([Sep|T],[Sep],T) :- bugly_separator(Sep).
4985 % comment in and adapt for domain specific separators:
4986 %decompose_string(List,Seps,T) :- member(Seps,["LEU","DEF","BAL"]), append(Seps,T,List).
4987 %bugly_separator(10).
4988 %bugly_separator(13).
4989 bugly_separator(32).
4990 bugly_separator(0'-).
4991 bugly_separator(0'_).
4992 bugly_separator(0',).
4993 bugly_separator(0'.).
4994 bugly_separator(0';).
4995 bugly_separator(0':).
4996 bugly_separator(0'#).
4997 bugly_separator(0'[).
4998 bugly_separator(0']).
4999 bugly_separator(0'().
5000 bugly_separator(0')).
5001
5002 % scramble and pretty print individual strings or components of strings
5003 pp_bugly_string('') --> !, [].
5004 pp_bugly_string(Name) -->
5005 {convert_atom_to_number(Name,_)},!, % do not scramble numbers; we could check if LibraryStrings is available
5006 pp_atom_opt_latex(Name).
5007 pp_bugly_string(Name) -->
5008 {bugly_scramble_id(Name,ScrName)},
5009 ppatom(ScrName).
5010
5011 % ------------
5012
5013 pp_atom_opt_latex(Name) --> {latex_mode},!,
5014 {my_greek_latex_escape_atom(Name,_,EscName)},
5015 % should we add \mathrm{.} or \mathit{.}?
5016 ppatom(EscName).
5017 pp_atom_opt_latex(Name) --> ppatom(Name).
5018
5019 % a version of pp_atom_opt_latex working with codes
5020 pp_codes_opt_latex(Codes) --> {latex_mode},!,
5021 {atom_codes(Name,Codes),my_greek_latex_escape_atom(Name,_,EscName)},
5022 ppatom(EscName).
5023 pp_codes_opt_latex(Codes) --> ppcodes(Codes).
5024
5025 pp_atom_opt_latex_mathit(Name) --> {latex_mode},!,
5026 {latex_escape_atom(Name,EscName)},
5027 "\\mathit{",ppatom(EscName),"}".
5028 pp_atom_opt_latex_mathit(Name) --> ppatom(Name).
5029
5030 pp_atom_opt_mathit(EscName) --> {latex_mode},!,
5031 % we assume already escaped
5032 "\\mathit{",ppatom(EscName),"}".
5033 pp_atom_opt_mathit(Name) --> ppatom(Name).
5034
5035 pp_space --> {latex_mode},!, "\\ ".
5036 pp_space --> " ".
5037
5038 opt_scramble_id(ID,Res) :- get_preference(bugly_pp_scrambling,true),!,
5039 bugly_scramble_id(ID,Res).
5040 opt_scramble_id(ID,ID).
5041
5042 :- use_module(probsrc(gensym),[gensym/2]).
5043 :- dynamic bugly_scramble_id_cache/2.
5044 bugly_scramble_id(ID,Res) :- var(ID),!, add_internal_error('Illegal call: ',bugly_scramble_id(ID,Res)), ID=Res.
5045 bugly_scramble_id(ID,Res) :- bugly_scramble_id_cache(ID,ScrambledID),!,
5046 Res=ScrambledID.
5047 bugly_scramble_id(ID,Res) :- %write(gen_id(ID,Res)),nl,
5048 genbuglynr(Nr),
5049 gen_bugly_id(Nr,ScrambledID),
5050 assertz(bugly_scramble_id_cache(ID,ScrambledID)),
5051 %format(user_output,'BUGLY scramble ~w --> ~w~n',[ID,ScrambledID]),
5052 Res = ScrambledID.
5053
5054 gen_bugly_id_codes(Nr,[Char|TC]) :- Char is 97+ Nr mod 26,
5055 (Nr> 25 -> N1 is Nr // 26, gen_bugly_id_codes(N1,TC) ; TC=[]).
5056 gen_bugly_id(Nr,ScrambledID) :- gen_bugly_id_codes(Nr,Codes), atom_codes(ScrambledID,[97,97|Codes]).
5057 %gen_bugly_id(Nr,ScrambledID) :- ajoin(['aa',Nr],ScrambledID). % old version using aaNr
5058
5059 :- dynamic bugly_count/1.
5060 bugly_count(0).
5061 genbuglynr(Nr) :-
5062 retract(bugly_count(Nr)), N1 is Nr + 1,
5063 assertz(bugly_count(N1)).
5064
5065
5066 is_lambda_result_id(b(identifier(ID),_,_INFO),Suffix) :- % _INFO=[lambda_result], sometiems _INFO=[]
5067 is_lambda_result_name(ID,Suffix).
5068 is_lambda_result_name(LAMBDA_RESULT,Suffix) :- atomic(LAMBDA_RESULT),
5069 atom_codes(LAMBDA_RESULT,[95,108,97,109,98,100,97,95,114,101,115,117,108,116,95|Suffix]). % _lambda_result_
5070
5071 pp_expr(TE,P) --> %{write('OBSOLETE'),nl,nl},
5072 pp_expr(TE,P,_LimitReached).
5073
5074 pp_expr(TExpr,Prio,_) --> {var(TExpr)},!,"_",{Prio=500}.
5075 pp_expr(_,Prio,LimitReached) --> {LimitReached==limit_reached},!,"...",{Prio=500}.
5076 pp_expr(b(Expr,Type,Info),Prio,LimitReached) --> !,
5077 pp_expr0(Expr,Type,Info,Prio,LimitReached).
5078 pp_expr([H|T],10,LimitReached) --> !, % also allow pp_expr to be used for lists of expressions
5079 pp_expr_l([H|T],LimitReached).
5080 pp_expr(Expr,Prio,LimitReached) -->
5081 pp_expr1(Expr,any,[],Prio,LimitReached).
5082
5083 pp_expr0(identifier(ID),_Type,_Info,Prio,_LimitReached) --> {is_lambda_result_name(ID,Suffix)},!, {Prio=500},
5084 {append("LAMBDA_RESULT___",Suffix,ASCII), atom_codes(R,ASCII)}, ppatom(R).
5085 pp_expr0(Expr,_Type,Info,Prio,_LimitReached) -->
5086 {eventb_translation_mode},
5087 pp_theory_operator(Expr,Info,Prio),!.
5088 pp_expr0(Expr,Type,Info,Prio,LimitReached) -->
5089 {check_info(Expr,Type,Info)},
5090 pp_rodin_label(Expr,Info),
5091 (pp_expr1(Expr,Type,Info,Prio,LimitReached) -> {true}
5092 ; {add_error(translate,'Could not translate:',Expr,Expr),fail}
5093 ).
5094
5095 check_info(Expr,_,Info) :- var(Info), add_error(translate,'Illegal variable info field for expression: ', Expr),fail.
5096 check_info(_,_,_).
5097
5098 pp_theory_operator(general_sum(_,Membercheck,_),_Info,500) -->
5099 {get_texpr_expr(Membercheck,member(_,Arg))},
5100 ppatom('SUM('),pp_expr(Arg,_),ppatom(')').
5101 pp_theory_operator(general_product(_,Membercheck,_),_Info,500) -->
5102 {get_texpr_expr(Membercheck,member(_Couple,Arg))},
5103 ppatom('PRODUCT('),pp_expr(Arg,_),ppatom(')').
5104 pp_theory_operator(function(_,Arg),Info,500) -->
5105 {memberchk_in_info(theory_operator(O,N),Info),decouplise_expr(N,Arg,Args)},
5106 ppatom(O),"(",pp_expr_l_sep(Args,",",_LR),")".
5107 pp_theory_operator(member(Arg,_),Info,500) -->
5108 {memberchk_in_info(theory_operator(O,N),Info),decouplise_expr(N,Arg,Args)},
5109 ppatom(O),"(",pp_expr_l_sep(Args,",",_LR),")".
5110
5111 decouplise_expr(1,E,R) :- !,R=[E].
5112 decouplise_expr(N,E,R) :-
5113 get_texpr_expr(E,couple(A,B)),!,
5114 N2 is N-1,
5115 decouplise_expr(N2,A,R1),append(R1,[B],R).
5116 decouplise_expr(N,E,[E]) :-
5117 print_message(call_failed(decouplise_expr(N,E,_))),nl.
5118
5119 % do not print labels for identifiers (can happen in ANY); not accepted by B parser
5120 pp_rodin_label(identifier(_),_Infos) --> {!}, [].
5121 pp_rodin_label(_Expr,Infos) --> pp_rodin_label(Infos).
5122
5123 % will pretty print (first) rodin or pragma label
5124 pp_rodin_label(_Infos) --> {preference(translate_suppress_rodin_positions_flag,true),!}.
5125 pp_rodin_label(_Infos) --> {preference(bugly_pp_scrambling,true),!}.
5126 pp_rodin_label(Infos) --> {var(Infos)},!, "/* ILLEGAL VARIABLE INFO FIELD */".
5127 ?pp_rodin_label(Infos) --> {get_info_labels(Infos,Label)},!,
5128 pp_start_label_pragma,
5129 ppatoms_opt_latex(Label),
5130 pp_end_label_pragma.
5131 pp_rodin_label(Infos) --> {preference(pp_wd_infos,true)},!, pp_wd_info(Infos).
5132 pp_rodin_label(_Infos) --> [].
5133
5134 % print infos about well-definedness attached to AST node:
5135 pp_wd_info(Infos) --> {member(discharged_wd_po,Infos)},!, "/*D",
5136 ({member(contains_wd_condition,Infos)} -> "-WD*/ " ; "*/ ").
5137 pp_wd_info(Infos) --> {member(contains_wd_condition,Infos)},!, "/*WD*/ ".
5138 pp_wd_info(_Infos) --> [].
5139
5140 pp_start_label_pragma -->
5141 {(atelierb_mode(prover(_))
5142 ; get_preference(translate_print_typing_infos,true))}, % proxy for parseable;
5143 % set by translate_bvalue_to_parseable_classicalb; important for parsertests with labels
5144 !,
5145 "/*@label ".
5146 pp_start_label_pragma --> "/* @". % shorter version, for viewing in UI
5147 pp_end_label_pragma --> " */ ".
5148
5149 ppatoms([]) --> !, [].
5150 ppatoms([ID|T]) --> !,ppatom(ID), " ", ppatoms(T).
5151 ppatoms(X) --> {add_error(ppatoms,'Not a list of atoms: ',ppatoms(X))}.
5152
5153 ppatoms_opt_latex([]) --> !, [].
5154 ppatoms_opt_latex([ID]) --> !,pp_atom_opt_latex(ID).
5155 ppatoms_opt_latex([ID|T]) --> !,pp_atom_opt_latex(ID), " ", ppatoms_opt_latex(T).
5156 ppatoms_opt_latex(X) --> {add_error(ppatoms_opt_latex,'Not a list of atoms: ',ppatoms_opt_latex(X))}.
5157
5158 %:- use_module(bsyntaxtree,[is_set_type/2]).
5159 :- load_files(library(system), [when(compile_time), imports([environ/2])]).
5160 pp_expr1(Expr,_,_,Prio,_) --> {var(Expr)},!,"_",{Prio=500}.
5161 pp_expr1(event_b_comprehension_set(Ids,E,P),Type,_Info,Prio,LimitReached) -->
5162 {\+ eventb_translation_mode, b_ast_cleanup:rewrite_event_b_comprehension_set(Ids,E,P,Type, NewExpression)},!,
5163 pp_expr(NewExpression,Prio,LimitReached).
5164 pp_expr1(union(b(event_b_identity,Type,_), b(closure(Rel),Type,_)),_,Info,500,LimitReached) -->
5165 /* closure(Rel) = id \/ closure1(Rel) */
5166 ? {member_in_info(was(reflexive_closure),Info)},!,
5167 "closure(",pp_expr(Rel,_,LimitReached),")".
5168 pp_expr1(comprehension_set([_],_),_,Info,500,_LimitReached) -->
5169 {memberchk_in_info(freetype(P),Info),!},ppatom(P).
5170 % used instead of constants(Expr,Symbol) case below:
5171 pp_expr1(greater_equal(A,Y),Type,Info,Prio,LimitReached) --> % x:NATURAL was rewritten to x>=0, see test 499, 498
5172 {memberchk_in_info(was(member(A,B)),Info), get_integer(Y,_)},
5173 pp_expr1(member(A,B),Type,Info,Prio,LimitReached).
5174 pp_expr1(comprehension_set([TID],b(B,_,_)),Type,Info,Prio,LimitReached) -->
5175 {memberchk_in_info(was(integer_set(S)),Info)},
5176 {S='INTEGER' -> B=truth
5177 ; get_texpr_id(TID,ID),
5178 B=greater_equal(TID2,Y), get_integer(Y,I),
5179 get_texpr_id(TID2,ID),
5180 (I=0 -> S='NATURAL' ; I=1,S='NATURAL1')}, % TO DO: check bounds
5181 !,
5182 pp_expr1(integer_set(S),Type,Info,Prio,LimitReached).
5183 pp_expr1(interval(b(A,_,_),B),Type,Info,Prio,LimitReached) -->
5184 {memberchk_in_info(was(integer_set(S)),Info)},
5185 {B=b(max_int,integer,_)}, % TO DO ? allow value(int(Mx))
5186 {A=min_int -> S='INT' ; A=integer(0) -> S='NAT' ; A=integer(1),S='NAT1'},
5187 !,
5188 pp_expr1(integer_set(S),Type,Info,Prio,LimitReached).
5189 pp_expr1(falsity,_,Info,Prio,LimitReached) --> {memberchk_in_info(was(Pred),Info)},!,
5190 ({(unicode_mode ; latex_mode)}
5191 -> {translate_in_mode(falsity,'falsity',Symbol)},
5192 ppatom(Symbol),
5193 ({get_preference(pp_propositional_logic_mode,true)} -> {true}
5194 ; " ", enter_comment, " ", pp_expr2(Pred,Prio,LimitReached), " ", exit_comment)
5195 ; enter_comment, " falsity ",exit_comment, " ",
5196 pp_expr2(Pred,Prio,LimitReached)). % Pred is not wrapped
5197 pp_expr1(truth,_,Info,Prio,LimitReached) --> {memberchk_in_info(was(Pred),Info)},!,
5198 ({(unicode_mode ; latex_mode)}
5199 -> {translate_in_mode(truth,'truth',Symbol)},
5200 ppatom(Symbol),
5201 ({get_preference(pp_propositional_logic_mode,true)} -> {true}
5202 ; " ",enter_comment, " ", pp_expr2(Pred,Prio,LimitReached), " ", exit_comment)
5203 ; enter_comment, " truth ", exit_comment, " ",
5204 pp_expr2(Pred,Prio,LimitReached)). % Pred is not wrapped
5205 % TO DO: do this for other expressions as well; but then we have to ensure that ast_cleanup generates complete was(_) infos
5206 % :- load_files(library(system), [when(compile_time), imports([environ/2])]). % directive moved above to avoid Spider warning
5207 pp_expr1(event_b_identity,Type,_Info,500,_LimitReached) -->
5208 {\+ eventb_translation_mode}, %{atelierb_mode(prover(_)},
5209 {is_set_type(Type,couple(ElType,ElType))},
5210 !,
5211 "id(", {pretty_normalized_type(ElType,S)},ppatom(S), ")".
5212 pp_expr1(typeset,SType,_Info,500,_LimitReached) --> % normally removed by ast_cleanup
5213 {is_set_type(SType,Type)},
5214 !,
5215 ({normalized_type_requires_outer_paren(Type)} -> "(" ; ""),
5216 {pretty_normalized_type(Type,S)},ppatom(S),
5217 ({normalized_type_requires_outer_paren(Type)} -> ")" ; "").
5218 :- if(environ(prob_safe_mode,true)).
5219 pp_expr1(exists(Parameters,_),_,Info,_Prio,_LimitReached) -->
5220 {\+ member_in_info(used_ids(_),Info),
5221 add_error(translate,'Missing used_ids Info for exists: ',Parameters:Info),fail}.
5222 %pp_expr1(exists(Ids,P1),_,Info,250) --> !, { member_in_info(used_ids(Used),Info)},
5223 % exists_symbol,pp_expr_ids_in_mode(Ids,LimitReached),
5224 % {add_normal_typing_predicates(Ids,P1,P)},
5225 % " /* Used = ", ppterm(Used), " */ ",
5226 % ".",pp_expr_m(P,221).
5227 :- endif.
5228 pp_expr1(Expr,Type,Info,Prio,LimitReached) --> {member_in_info(sharing(ID,Count,_,_),Info),number(Count),Count>1},!,
5229 "( ",enter_comment," CSE ",ppnumber(ID), ":#", ppnumber(Count),
5230 ({member_in_info(negated_cse,Info)} -> " (neg) " ; " "),
5231 ({member_in_info(contains_wd_condition,Info)} -> " (wd) " ; " "),
5232 exit_comment, " ",
5233 {delete(Info,sharing(_,_,_,_),Info2)},
5234 pp_expr1(Expr,Type,Info2,Prio,LimitReached), ")".
5235 %pp_expr1(Expr,_,Info,Prio) --> {member_in_info(contains_wd_condition,Info)},!,
5236 % "( /* (wd) */ ", pp_expr2(Expr,Prio), ")".
5237 % pp_expr1(Expr,subst,_Info,Prio) --> !, translate_subst2(Expr,Prio). % TO DO: also allow substitutions here
5238 pp_expr1(value(V),Type,_,Prio,LimitReached) --> !,
5239 {(nonvar(V),V=closure(_,_,_) -> Prio=300 ; Prio=500)}, pp_value_with_type(V,Type,LimitReached).
5240 pp_expr1(comprehension_set(Ids,P1),_,Info,500,LimitReached) --> !,
5241 pp_comprehension_set(Ids,P1,Info,LimitReached).
5242 %pp_expr1(Expr,_,Info,Prio,LimitReached) --> {pp_is_important_info_field(Expr,Info,_)},
5243 % !, pp_important_infos(Expr,Info), pp_expr2(Expr,Prio,LimitReached).
5244 pp_expr1(first_of_pair(X),_,Info,500,LimitReached) --> {was_eventb_destructor(Info,X,Op,Arg)},!,
5245 ppatom(Op), "(",pp_expr(Arg,_,LimitReached), ")".
5246 pp_expr1(second_of_pair(X),_,Info,500,LimitReached) --> {was_eventb_destructor(Info,X,Op,Arg)},!,
5247 ppatom(Op), "(",pp_expr(Arg,_,LimitReached), ")".
5248 %pp_expr1(let_expression(_Ids,Exprs,_P),_Type,Info,500,LimitReached) -->
5249 % % pretty print direct definition operator calls, which get translated using create_z_let
5250 % % However: the lets can get removed; in which case the translated direct definition will be pretty printed
5251 % % also: what if the body of the let has been modified ??
5252 % {member(was(extended_expr(DirectDefOp)),Info),
5253 % bmachine_eventb:stored_operator_direct_definition(DirectDefOp,_Proj,_Theory,Parameters,_Def,_WD,_TypeParas,_Kind),
5254 % %length(Exprs,Arity),,length(Parameters,Arity1), write(found_dd(DirectDefOp,Arity1,Arity2,Proj,Theory)),nl,
5255 % same_length(Parameters,ActualParas), %same_length(TypeParameters,TP),
5256 % append(ActualParas,_TP,Exprs)
5257 % },
5258 % !,
5259 % ppatom(DirectDefOp),
5260 % pp_expr_wrap_l('(',ActualParas,')',LimitReached).
5261 pp_expr1(Expr,_,_Info,Prio,LimitReached) --> pp_expr2(Expr,Prio,LimitReached).
5262
5263 was_eventb_destructor(Info,X,Op,Arg) :- eventb_translation_mode,
5264 member(was(extended_expr(Op)),Info),peel_projections(X,Arg).
5265 is_projection(first_of_pair(A),A).
5266 is_projection(second_of_pair(A),A).
5267 % peel projections constructed for Event-B destructor operator
5268 peel_projections(b(A,_,_),R) :-
5269 (is_projection(A,RA) -> peel_projections(RA,R)
5270 ; A = freetype_destructor(_,_,R)).
5271
5272
5273 :- public pp_important_infos/4. % debugging utility
5274 pp_important_infos(Expr,Info) -->
5275 {findall(PPI,pp_is_important_info_field(Expr,Info,PPI),PPInfos), PPInfos \= []},
5276 " ", enter_comment, ppterm(PPInfos), exit_comment, " ".
5277 pp_is_important_info_field(_,Infos,'DO_NOT_ENUMERATE'(X)) :- member(prob_annotation('DO_NOT_ENUMERATE'(X)),Infos).
5278 pp_is_important_info_field(exists(_,_),Infos,'LIFT') :- member(allow_to_lift_exists,Infos).
5279 pp_is_important_info_field(exists(_,_),Infos,used_ids(Used)) :- member(used_ids(Used),Infos).
5280 pp_is_important_info_field(exists(_,_),Infos,'(wd)') :- member(contains_wd_condition,Infos).
5281
5282
5283 pp_expr2(Expr,_,_LimitReached) --> {var(Expr)},!,"_".
5284 pp_expr2(_,_,LimitReached) --> {LimitReached==limit_reached},!,"...".
5285
5286 pp_expr2(atom_string(V),500,_) --> !,pp_atom_opt_latex_mathit(V). % hardwired_atom
5287 pp_expr2(global_set(V),500,_) --> !, pp_identifier(V).
5288 pp_expr2(freetype_set(V),500,_) --> !,{pretty_freetype(V,P)},ppatom_opt_scramble(P).
5289 pp_expr2(lazy_lookup_expr(I),500,_) --> !, pp_identifier(I).
5290 pp_expr2(lazy_lookup_pred(I),500,_) --> !, pp_identifier(I).
5291 pp_expr2(identifier(I),500,_) --> !,
5292 {( I=op(Id) -> true; I=Id)},
5293 ( {atomic(Id)} -> ({translated_identifier(Id,TId)},
5294 ({latex_mode} -> ppatom(TId) ; pp_identifier(TId)))
5295 ;
5296 "'",ppterm(Id), "'").
5297 pp_expr2(integer(N),500,_) --> !, ppnumber(N).
5298 pp_expr2(real(N),500,_) --> !, ppatom(N).
5299 pp_expr2(integer_set(S),500,_) --> !,
5300 {integer_set_mapping(S,T)},ppatom(T).
5301 pp_expr2(string(S),500,_) --> !, string_start_symbol, ppstring_opt_scramble(S), string_end_symbol.
5302 pp_expr2(set_extension(Ext),500,LimitReached) --> !, {set_brackets(L,R)},
5303 pp_expr_wrap_l(L,Ext,R,LimitReached).
5304 pp_expr2(sequence_extension(Ext),500,LimitReached) --> !,
5305 pp_begin_sequence,
5306 ({get_preference(translate_print_cs_style_sequences,true)} -> pp_expr_l_sep(Ext,"",LimitReached)
5307 ; pp_expr_l_sep(Ext,",",LimitReached)),
5308 pp_end_sequence.
5309 pp_expr2(assign(LHS,RHS),10,LimitReached) --> !,
5310 pp_expr_wrap_l(',',LHS,'',LimitReached), ":=", pp_expr_wrap_l(',',RHS,'',LimitReached).
5311 pp_expr2(assign_single_id(LHS,RHS),10,LimitReached) --> !, pp_expr2(assign([LHS],[RHS]),10,LimitReached).
5312 pp_expr2(parallel(RHS),10,LimitReached) --> !,
5313 pp_expr_wrap_l('||',RHS,'',LimitReached).
5314 pp_expr2(sequence(RHS),10,LimitReached) --> !,
5315 pp_expr_wrap_l(';',RHS,'',LimitReached).
5316 pp_expr2(event_b_comprehension_set(Ids,E,P1),500,LimitReached) --> !, % normally conversion above should trigger; this is if we call pp_expr for untyped expressions
5317 pp_event_b_comprehension_set(Ids,E,P1,LimitReached).
5318 pp_expr2(recursive_let(Id,S),500,LimitReached) --> !,
5319 ({eventb_translation_mode} -> "" % otherwise we get strange characters in Rodin
5320 ; enter_comment," recursive ID ", pp_expr(Id,_,LimitReached), " ", exit_comment),
5321 pp_expr(S,_,LimitReached).
5322 pp_expr2(image(A,B),300,LimitReached) --> !,
5323 pp_expr_m(A,249,LimitReached),"[", % was 0; but we may have to bracket A; e.g., f <| {2} [{2}] is not ok; 250 is priority of lambda
5324 pp_expr_m(B,0,LimitReached),"]". % was 500, now set to 0: we never need an outer pair of () !?
5325 pp_expr2(function(A,B),300,LimitReached) --> !,
5326 pp_expr_m(A,249,LimitReached), % was 0; but we may have to bracket A; e.g., f <| {2} (2) is not ok; 250 is priority of lambda
5327 pp_function_left_bracket,
5328 pp_expr_m(B,0,LimitReached), % was 500, now set to 0: we never need an outer pair of () !?
5329 pp_function_right_bracket.
5330 pp_expr2(definition(A,B),300,LimitReached) --> !, % definition call; usually inlined,...
5331 ppatom(A),
5332 pp_function_left_bracket,
5333 pp_expr_l_sep(B,",",LimitReached),
5334 pp_function_right_bracket.
5335 pp_expr2(operation_call_in_expr(A,B),300,LimitReached) --> !,
5336 pp_expr_m(A,249,LimitReached),
5337 pp_function_left_bracket,
5338 pp_expr_l_sep(B,",",LimitReached),
5339 pp_function_right_bracket.
5340 pp_expr2(enumerated_set_def(GS,ListEls),200,LimitReached) --> !, % for pretty printing enumerate set defs
5341 {reverse(ListEls,RLE)}, /* they have been inserted in inverse order */
5342 pp_identifier(GS), "=", pp_expr_wrap_l('{',RLE,'}',LimitReached).
5343 pp_expr2(forall(Ids,D1,P),Prio,LimitReached) --> !,
5344 ({eventb_translation_mode} -> {Prio=60} ; {Prio=250}), % in Rodin forall/exists cannot be mixed with &, or, <=>, ...
5345 ({eventb_translation_mode} -> "(" ; ""), % always put brackets around the forall in Rodin
5346 forall_symbol,pp_expr_ids_in_mode(Ids,LimitReached),
5347 {add_normal_typing_predicates(Ids,D1,D)},
5348 dot_symbol,pp_expr_m(b(implication(D,P),pred,[]),221,LimitReached),
5349 ({eventb_translation_mode} -> ")" ; "").
5350 pp_expr2(exists(Ids,P1),Prio,LimitReached) --> !,
5351 ({eventb_translation_mode} -> {Prio=60} ; {Prio=250}), % exists has Prio 250, but dot has 220
5352 ({eventb_translation_mode} -> "(" ; ""), % always put brackets around the exists in Rodin
5353 exists_symbol,pp_expr_ids_in_mode(Ids,LimitReached),
5354 {add_normal_typing_predicates(Ids,P1,P)},
5355 dot_symbol,
5356 ({eventb_translation_mode} -> {MinPrio=29} ; {MinPrio=500}),
5357 % used to be 221, but #x.x>7 or #x.not(...) are not parsed by Atelier-B or ProB, x.x and x.not are parsed as composed identifiers
5358 % In Event-B ∃y·y>x ∧ (y=x+1 ∨ y=x+2) is valid and requires no outer parenthesis (if not on the left side of another predicate!)
5359 pp_expr_m(P,MinPrio,LimitReached),
5360 ({eventb_translation_mode} -> ")" ; "").
5361 pp_expr2(record_field(R,I),250,LimitReached) --> !,
5362 pp_expr_m(R,251,LimitReached),"'",pp_identifier(I).
5363 pp_expr2(rec(Fields),500,LimitReached) --> !,
5364 {function_like_in_mode(rec,Symbol)},
5365 ppatom(Symbol), "(",pp_expr_fields(Fields,LimitReached),")".
5366 pp_expr2(struct(Rec),500,LimitReached) -->
5367 {get_texpr_expr(Rec,rec(Fields)),Val=false ; get_texpr_expr(Rec,value(rec(Fields)))},!,
5368 {function_like_in_mode(struct,Symbol)},
5369 ppatom(Symbol), "(",
5370 ({Val==false} -> pp_expr_fields(Fields,LimitReached)
5371 ; pp_value_l(Fields,',',LimitReached)),
5372 ")".
5373 pp_expr2(freetype_case(_FT,L,Expr),Prio,LimitReached) --> !,
5374 %{Prio=500}, pp_freetype_term('__is_ft_case',FT,L,Expr,LimitReached).
5375 % we now pretty-print it as Expr : ran(L) assuming there is a constant L generated for every case
5376 {FTCons = b(identifier(L),any,[]), RanFTCons = b(range(FTCons),any,[])},
5377 pp_expr(b(member(Expr,RanFTCons),pred,[]),Prio,LimitReached).
5378 pp_expr2(freetype_constructor(_FT,Case,Expr),Prio,LimitReached) --> !,
5379 {FTCons = b(identifier(Case),any,[])},
5380 pp_expr(b(function(FTCons,Expr),any,[]),Prio,LimitReached).
5381 % ppatom_opt_scramble(Case),ppatom('('),pp_expr(Expr,_,LimitReached),ppatom(')').
5382 pp_expr2(freetype_destructor(_FT,Case,Expr),Prio,LimitReached) --> !,
5383 % pretty print it as: Case~(Expr)
5384 {FTCons = b(identifier(Case),any,[]), Destr = b(reverse(FTCons),any,[])},
5385 pp_expr(b(function(Destr,Expr),any,[]),Prio,LimitReached).
5386 % ({unicode_mode}
5387 % -> {unicode_translation(reverse,PowMinus1Symbol)},
5388 % ppatom(Case),ppatom(PowMinus1Symbol), % Note: we do not print the freetype's name FT
5389 % "(",pp_expr_m(Expr,0,LimitReached),")"
5390 % ; pp_freetype_term('__ft~',FT,Case,Expr,LimitReached) % TODO: maybe find better print
5391 % ).
5392 pp_expr2(let_predicate(Ids,Exprs,P),1,LimitReached) --> !,
5393 pp_expr_let_exists(Ids,Exprs,P,LimitReached). % instead of pp_expr_let
5394 pp_expr2(let_expression(Ids,Exprs,P),1,LimitReached) --> !,
5395 pp_expr_let(Ids,Exprs,P,LimitReached).
5396 pp_expr2(let_expression_global(Ids,Exprs,P),1,LimitReached) --> !, " /", "* global *", "/ ",
5397 pp_expr_let(Ids,Exprs,P,LimitReached).
5398 pp_expr2(lazy_let_pred(Id,Expr,P),Pr,LimitReached) --> !, pp_expr2(lazy_let_expr(Id,Expr,P),Pr,LimitReached).
5399 pp_expr2(lazy_let_subst(Id,Expr,P),Pr,LimitReached) --> !, pp_expr2(lazy_let_expr(Id,Expr,P),Pr,LimitReached).
5400 pp_expr2(lazy_let_expr(Id,Expr,P),1,LimitReached) --> !,
5401 pp_expr_let([Id],[Expr],P,LimitReached).
5402 pp_expr2(norm_conjunct(Cond,[]),1,LimitReached) --> !, % norm_conjunct: flattened version generated by b_interpreter_check,...
5403 "( ",pp_expr(Cond,_,LimitReached), ")".
5404 pp_expr2(norm_conjunct(Cond,[H|T]),1,LimitReached) --> !,
5405 "( ",pp_expr(Cond,_,LimitReached), ") ", and_symbol, " (", pp_expr2(norm_conjunct(H,T),_,LimitReached), ")".
5406 pp_expr2(assertion_expression(Cond,Msg,Expr),1,LimitReached) --> !,
5407 " ASSERT_EXPR (",
5408 pp_expr_m(b(convert_bool(Cond),pred,[]),30,LimitReached), ",",
5409 pp_expr_m(string(Msg),30,LimitReached), ",",
5410 pp_expr_m(Expr,30,LimitReached),
5411 " )".
5412 %pp_expr2(assertion_expression(Cond,_Msg,Expr),1) --> !,
5413 % "__ASSERT ",pp_expr_m(Cond,30),
5414 % " IN ", pp_expr_m(Expr,30).
5415 pp_expr2(partition(S,Elems),500,LimitReached) -->
5416 {eventb_translation_mode ;
5417 \+ atelierb_mode(_), length(Elems,Len), Len>50 % we need to print a quadratic number of disjoints
5418 },!,
5419 "partition(",pp_expr(S,_,LimitReached),
5420 ({Elems=[]} -> ")" ; pp_expr_wrap_l(',',Elems,')',LimitReached)).
5421 pp_expr2(partition(S,Elems),500,LimitReached) --> !,
5422 "(",pp_expr(S,_,LimitReached), " = ",
5423 ({Elems=[]} -> "{})"
5424 ; pp_expr_l_sep(Elems,"\\/",LimitReached), pp_all_disjoint(Elems,LimitReached),")").
5425 pp_expr2(finite(S),Prio,LimitReached) --> {\+ eventb_translation_mode}, %{atelierb_mode(_)},
5426 !,
5427 pp_expr2(member(S,b(fin_subset(S),set(any),[])),Prio,LimitReached).
5428 pp_expr2(if_then_else(If,Then,Else),1,LimitReached) --> {animation_minor_mode(z)},!,
5429 "\\IF ",pp_expr_m(If,30,LimitReached),
5430 " \\THEN ",pp_expr_m(Then,30,LimitReached),
5431 " \\ELSE ",pp_expr_m(Else,30,LimitReached).
5432 %pp_expr2(if_then_else(If,Then,Else),1) --> {unicode_mode},!,
5433 % "if ",pp_expr_m(If,30), " then ",pp_expr_m(Then,30), " else ",pp_expr_m(Else,30).
5434 pp_expr2(if_then_else(If,Then,Else),Prio,LimitReached) --> {atelierb_mode(_)},!,
5435 % print IF-THEN-ELSE using a translation that Atelier-B can understand:
5436 % TODO: support if_predicate
5437 {rewrite_if_then_else_expr_to_b(if_then_else(If,Then,Else), NExpr),
5438 get_texpr_type(Then,Type),
5439 NAst = b(NExpr,Type,[])},
5440 % construct {d,x| If => x=Then & not(if) => x=Else}(TRUE)
5441 pp_expr(NAst,Prio,LimitReached).
5442 pp_expr2(IFTE,1,LimitReached) --> {is_ifte(IFTE,If,Then,Else)}, !,
5443 pp_atom_opt_mathit('IF'),pp_space, % "IF ",
5444 pp_expr_m(If,30,LimitReached),
5445 pp_space, pp_atom_opt_mathit('THEN'),pp_space, %" THEN ",
5446 pp_expr_m(Then,30,LimitReached),
5447 pp_space, pp_atom_opt_mathit('ELSE'),pp_space, %" ELSE ",
5448 pp_expr_m(Else,30,LimitReached),
5449 pp_space, pp_atom_opt_mathit('END'). %" END"
5450 pp_expr2(kodkod(Id,Identifiers),300,LimitReached) --> !,
5451 "KODKOD_CALL(",ppnumber(Id),": ",pp_expr_ids(Identifiers,LimitReached),")".
5452 pp_expr2(Expr,500,_) -->
5453 {constants_in_mode(Expr,Symbol)},!,ppatom(Symbol).
5454 pp_expr2(equal(A,B),Prio,LimitReached) -->
5455 {get_preference(pp_propositional_logic_mode,true), % a mode for printing propositional logic formuli
5456 is_boolean_value(B,BV),
5457 get_texpr_id(A,_)},!,
5458 ({BV=pred_true} -> pp_expr(A,Prio,LimitReached)
5459 ; pp_expr2(negation(b(equal(A,b(boolean_true,boolean,[])),pred,[])),Prio,LimitReached)).
5460 pp_expr2(Expr,Prio,LimitReached) -->
5461 {functor(Expr,F,1),
5462 unary_prefix(F,Symbol,Prio),!,
5463 arg(1,Expr,Arg),APrio is Prio+1},
5464 ppatom(Symbol),
5465 ({F=unary_minus, eventb_translation_mode} -> "" ; " "), % no space between unary minus and integer literal in Event-B
5466 pp_expr_m(Arg,APrio,LimitReached).
5467 pp_expr2(Expr,500,LimitReached) -->
5468 {functor(Expr,F,1),
5469 unary_prefix_parentheses(F,Symbol),!,
5470 arg(1,Expr,Arg)},
5471 pp_atom_opt_latex(Symbol), "(", pp_expr(Arg,_,LimitReached), ")".
5472 pp_expr2(Expr,Prio,LimitReached) -->
5473 {functor(Expr,F,1),
5474 unary_postfix_in_mode(F,Symbol,Prio),!,
5475 arg(1,Expr,Arg),APrio is Prio+1},
5476 pp_expr_m(Arg,APrio,LimitReached),ppatom(Symbol).
5477 pp_expr2(power_of(Left,Right),Prio,LimitReached) --> {latex_mode},!, % special case, as we need to put {} around RHS
5478 {Prio=200, LPrio is Prio+1, RPrio = Prio},
5479 pp_expr_m(Left,LPrio,LimitReached),
5480 "^{",
5481 pp_expr_m(Right,RPrio,LimitReached),
5482 "}".
5483 pp_expr2(power_of_real(Left,Right),Prio,LimitReached) --> !,
5484 ({get_texpr_expr(Right,convert_real(RI))}
5485 -> pp_expr2(power_of(Left,RI),Prio,LimitReached) % the Atelier-B power_of expects integer exponent
5486 ; pp_external_call('RPOW',[Left,Right],expression,Prio,LimitReached)
5487 ).
5488 pp_expr2(Expr,OPrio,LimitReached) -->
5489 {functor(Expr,F,2),
5490 binary_infix_in_mode(F,Symbol,Prio,Ass),!,
5491 arg(1,Expr,Left),
5492 arg(2,Expr,Right),
5493 ( Ass = left, binary_infix_symbol(Left,Symbol) -> LPrio is Prio-1, RPrio is Prio+1
5494 ; Ass = right, binary_infix_symbol(Right,Symbol) -> LPrio is Prio+1, RPrio is Prio-1
5495 ; LPrio is Prio+1, RPrio is Prio+1)},
5496 % Note: Prio+1 is actually not necessary, Prio would be sufficient, as pp_expr_m uses a strict comparison <
5497 ({always_surround_by_parentheses(F)} -> "(",{OPrio=1000} ; {OPrio=Prio}),
5498 pp_expr_m(Left,LPrio,LimitReached),
5499 " ", ppatom(Symbol), " ",
5500 pp_expr_m(Right,RPrio,LimitReached),
5501 ({always_surround_by_parentheses(F)} -> ")" ; []).
5502 pp_expr2(first_of_pair(X),500,LimitReached) --> {get_texpr_type(X,couple(From,To))},!,
5503 "prj1(", % TO DO: Latex version
5504 ({\+ atelierb_mode(_)} % eventb_translation_mode
5505 -> "" % no need to print types in Event-B or with new parser;
5506 % TODO: also with new parser no longer required; only print in Atelier-B mode
5507 ; {pretty_normalized_type(From,FromT),
5508 pretty_normalized_type(To,ToT)},
5509 pp_atom_opt_latex(FromT), ",", pp_atom_opt_latex(ToT),
5510 ")("
5511 ),
5512 pp_expr(X,_,LimitReached),")".
5513 pp_expr2(second_of_pair(X),500,LimitReached) --> {get_texpr_type(X,couple(From,To))},!,
5514 "prj2(", % TO DO: Latex version
5515 ({\+ atelierb_mode(_)} -> "" % no need to print types in Event-B or with new parser
5516 ; {pretty_normalized_type(From,FromT),
5517 pretty_normalized_type(To,ToT)},
5518 pp_atom_opt_latex(FromT), ",", pp_atom_opt_latex(ToT),
5519 ")("
5520 ),
5521 pp_expr(X,_,LimitReached),")".
5522 pp_expr2(Call,Prio,LimitReached) --> {external_call(Call,Kind,Symbol,Args)},!,
5523 pp_external_call(Symbol,Args,Kind,Prio,LimitReached).
5524 pp_expr2(card(A),500,LimitReached) --> {latex_mode, get_preference(latex_pp_greek_ids,true)},!,
5525 "|",pp_expr_m(A,0,LimitReached),"|".
5526 pp_expr2(Expr,500,LimitReached) -->
5527 {functor(Expr,F,_),
5528 function_like_in_mode(F,Symbol),!,
5529 Expr =.. [F|Args]},
5530 ppatom(Symbol),
5531 ({Args=[]}
5532 -> "" % some operators like pred and succ do not expect arguments
5533 ; pp_expr_wrap_l('(',Args,')',LimitReached)).
5534 pp_expr2(Expr,250,LimitReached) -->
5535 {functor(Expr,F,3),
5536 quantified_in_mode(F,Symbol),
5537 Expr =.. [F,Ids,P1,E],
5538 !,
5539 add_normal_typing_predicates(Ids,P1,P)},
5540 ppatom(Symbol),pp_expr_ids(Ids,LimitReached),".(",
5541 pp_expr_m(P,11,LimitReached),pp_such_that_bar(E),
5542 pp_expr_m(E,11,LimitReached),")".
5543 pp_expr2(Expr,Prio,LimitReached) -->
5544 {functor(Expr,F,N),
5545 (debug_mode(on)
5546 -> format('**** Unknown functor ~w/~w in pp_expr2~n expression: ~w~n',[F,N,Expr])
5547 ; format('**** Unknown functor ~w/~w in pp_expr2~n',[F,N])
5548 ),
5549 %add_internal_error('Unknown Expression: ',pp_expr2(Expr,Prio)),
5550 Prio=20},
5551 ppterm_with_limit_reached(Expr,LimitReached).
5552
5553 :- use_module(external_function_declarations,[synonym_for_external_predicate/2]).
5554
5555 pp_external_call('MEMOIZE_STORED_FUNCTION',[TID],_,500,LimitReached) -->
5556 {get_integer(TID,ID),memoization:get_registered_function_name(ID,Name)},!,
5557 pp_expr_m(atom_string(Name),20,LimitReached),
5558 " /*@memo ", pp_expr_m(TID,20,LimitReached), "*/".
5559 pp_external_call('STRING_LENGTH',[Arg],_,Prio,LimitReached) -->
5560 {get_preference(allow_sequence_operators_on_strings,true)},!,
5561 pp_expr2(size(Arg),Prio,LimitReached).
5562 pp_external_call('STRING_APPEND',[Arg1,Arg2],_,Prio,LimitReached) -->
5563 {get_preference(allow_sequence_operators_on_strings,true)},!,
5564 pp_expr2(concat(Arg1,Arg2),Prio,LimitReached).
5565 pp_external_call('STRING_CONC',[Arg1],_,Prio,LimitReached) -->
5566 {get_preference(allow_sequence_operators_on_strings,true)},!,
5567 pp_expr2(general_concat(Arg1),Prio,LimitReached).
5568 % we could also pretty-print RMUL, ...
5569 pp_external_call(PRED,Args,pred,Prio,LimitReached) -->
5570 {get_preference(translate_ids_to_parseable_format,true),
5571 synonym_for_external_predicate(PRED,FUNC)},
5572 !, % print external predicate as function, as parser can only parse the latter without access to DEFINITIONS
5573 pp_expr2(equal(b(external_function_call(FUNC,Args),boolean,[]),
5574 b(boolean_true,boolean,[])),Prio,LimitReached).
5575 pp_external_call(Symbol,Args,_,Prio,LimitReached) -->
5576 ({invisible_external_pred(Symbol)}
5577 -> pp_expr2(truth,Prio,LimitReached),
5578 " /* ",pp_expr_m(atom_string(Symbol),20,LimitReached),pp_expr_wrap_l('(',Args,') */',LimitReached)
5579 ; {Prio=500},pp_expr_m(atom_string(Symbol),20,LimitReached),
5580 pp_expr_wrap_l('(',Args,')',LimitReached) % pp_expr_wrap_l('/*EXT:*/(',Args,')')
5581 ).
5582
5583 invisible_external_pred('LEQ_SYM').
5584 invisible_external_pred('LEQ_SYM_BREAK'). % just for symmetry breaking foralls,...
5585 external_call(external_function_call(Symbol,Args),expression,Symbol,Args).
5586 external_call(external_pred_call(Symbol,Args),pred,Symbol,Args).
5587 external_call(external_subst_call(Symbol,Args),subst,Symbol,Args).
5588
5589 pp_all_disjoint([H1,H2],LimitReached) --> !, " ",and_symbol," ", pp_disjoint(H1,H2,LimitReached).
5590 pp_all_disjoint([H1|T],LimitReached) --> pp_all_disjoint_aux(T,H1,LimitReached), pp_all_disjoint(T,LimitReached).
5591 pp_all_disjoint([],_) --> "".
5592
5593 pp_all_disjoint_aux([],_,_) --> "".
5594 pp_all_disjoint_aux([H2|T],H1,LimitReached) --> " ",and_symbol," ",
5595 pp_disjoint(H1,H2,LimitReached), pp_all_disjoint_aux(T,H1,LimitReached).
5596
5597 pp_disjoint(H1,H2,LimitReached) --> pp_expr(H1,_), "/\\", pp_expr(H2,_,LimitReached), " = {}".
5598
5599
5600 % given a list of predicates and an ID either extract ID:Set and return Set or return its type as string
5601 select_membership([],TID,[],atom_string(TS)) :- % atom_string used as wrapper for pp_expr2
5602 get_texpr_type(TID,Type), pretty_type(Type,TS).
5603 select_membership([Pred|Rest],TID,Rest,Set) :-
5604 Pred = b(member(TID2,Set),pred,_),
5605 same_id(TID2,TID,_),!.
5606 select_membership([Pred|Rest],TID,Rest,Set) :-
5607 Pred = b(equal(TID2,EqValue),pred,_),
5608 same_id(TID2,TID,_),!, get_texpr_type(TID,Type),
5609 Set = b(set_extension([EqValue]),set(Type),[]).
5610 select_membership([Pred|T],TID,[Pred|Rest],Set) :-
5611 select_membership(T,TID,Rest,Set).
5612
5613 % pretty print prj1/prj2
5614 pp_prj12(Prj,Set1,Set2,LimitReached) -->
5615 ppatom(Prj),"(",pp_expr(Set1,_,LimitReached),",",pp_expr(Set2,_),")".
5616
5617 %:- use_module(bsyntaxtree,[is_a_disjunct/3, get_integer/2]).
5618
5619 pp_comprehension_set(Ids,P1,Info,LimitReached) -->
5620 pp_comprehension_set5(Ids,P1,Info,LimitReached,_).
5621
5622 % the extra argument of pp_comprehension_set5 indicates whether a special(Rule) was applied or not
5623 %pp_comprehension_set(IDs,Body,Info,LimitReached,_) --> {write(pp(IDs,Body,Info)),nl,fail}.
5624 pp_comprehension_set5([TID1,TID2,TID3],Body,_Info,LimitReached,special(Proj)) -->
5625 /* This comprehension set was a projection function (prj1/prj2) */
5626 % %(z_,z__).(z__ : NATURAL|z_) -> prj1(INTEGER,NATURAL)
5627 {get_texpr_id(TID1,ID1), % sometimes _zzzz_unary or _prj_arg1__
5628 get_texpr_id(TID2,ID2), % sometimes _zzzz_binary or _prj_arg2__
5629 get_texpr_id(TID3,LambdaID),
5630 ? get_lambda_equality(Body,LambdaID,RestBody,ResultExpr),
5631 get_texpr_id(ResultExpr,ResultID),
5632 (ResultID = ID1 -> Proj = prj1 ; ResultID = ID2, Proj = prj2),
5633 flatten_conjunctions(RestBody,Rest1),
5634 select_membership(Rest1,TID1,Rest2,Set1), % will extract full type if no membership there
5635 select_membership(Rest2,TID2,[],Set2)}, % ditto
5636 !,
5637 pp_prj12(Proj,Set1,Set2,LimitReached).
5638 pp_comprehension_set5([ID1|T],Body,Info,LimitReached,special(disjunct)) --> {is_a_disjunct(Body,B1,B2),
5639 get_last(T,ID1,_FrontIDs,LastID),
5640 is_lambda_result_id(LastID,_Suffix)},!, % we seem to have the union of two lambda expressions
5641 "(", pp_comprehension_set([ID1|T],B1,Info,LimitReached),
5642 " \\/ ", pp_comprehension_set([ID1|T],B2,Info,LimitReached), ")".
5643 pp_comprehension_set5(Paras,Body,_,_,special(pred)) --> % '_lambda_result_'
5644 {is_pred_compset(Paras,Body)},
5645 !,
5646 "pred".
5647 pp_comprehension_set5(Paras,Body,_,_,special(succ)) --> % '_lambda_result_'
5648 {is_succ_compset(Paras,Body)},
5649 !,
5650 "succ".
5651 pp_comprehension_set5(Paras,Body,Info,LimitReached,special(lambda)) -->
5652 {detect_lambda_comprehension(Paras,Body, FrontIDs,LambdaBody,ToExpr)},
5653 !,
5654 {add_normal_typing_predicates(FrontIDs,LambdaBody,TLambdaBody)},
5655 ({eventb_translation_mode} -> "(" ; ""), % put brackets around the lambda in Rodin
5656 pp_annotations(Info,Body),
5657 lambda_symbol, % "%"
5658 pp_lambda_identifiers(FrontIDs,LimitReached),
5659 ".",
5660 ({eventb_translation_mode} -> {IPrio=30} ; {IPrio=11}, "("), % In Rodin it is not ok to write (P|E)
5661 pp_expr_m(TLambdaBody,IPrio,LimitReached), % Check 11 against prio of . and |
5662 pp_such_that_bar(ToExpr),
5663 pp_expr_m(ToExpr,IPrio,LimitReached),
5664 ")".
5665 pp_comprehension_set5(TIds,Body,Info,LimitReached,special(event_b_comprehension_set)) -->
5666 % detect Event-B style set comprehensions and use bullet • or Event-B notation such as {x·x ∈ 1 ‥ 3|x * 10}
5667 % gets translated to {`__comp_result__`|∃x·(x ∈ 1 ‥ 3 ∧ `__comp_result__` = x * 10)}
5668 ? {is_eventb_comprehension_set(TIds,Body,Info,Ids,P1,EXPR), \+ atelierb_mode(_)},!, % print rewritten version for AtelierB
5669 pp_annotations(Info,P1),
5670 left_set_bracket,
5671 pp_expr_l(Ids,LimitReached), % here we must separate with , not with |-> via pp_expr_l_pair_in_mode !
5672 {add_normal_typing_predicates(Ids,P1,P)},
5673 dot_bullet_symbol,
5674 pp_expr_m(P,11,LimitReached),
5675 pp_such_that_bar(P),
5676 pp_expr_m(EXPR,11,LimitReached),
5677 right_set_bracket.
5678 pp_comprehension_set5(Ids,P1,_Info,LimitReached,normal) --> {atelierb_mode(prover(ml))},!,
5679 "SET(",
5680 pp_expr_l_pair_in_mode(Ids,LimitReached),
5681 ").(",
5682 {add_normal_typing_predicates(Ids,P1,P)},
5683 pp_expr_m(P,11,LimitReached),
5684 ")".
5685 pp_comprehension_set5(Ids,P1,Info,LimitReached,normal) -->
5686 pp_annotations(Info,P1),
5687 left_set_bracket,
5688 pp_expr_l_pair_in_mode(Ids,LimitReached),
5689 {add_normal_typing_predicates(Ids,P1,P)},
5690 pp_such_that_bar(P),
5691 pp_expr_m(P,11,LimitReached),
5692 right_set_bracket.
5693
5694
5695 detect_lambda_comprehension([ID1|T],Body, FrontIDs,LambdaBody,ToExpr) :-
5696 get_last(T,ID1,FrontIDs,LastID),
5697 FrontIDs=[_|_], % at least one identifier for the lambda
5698 is_lambda_result_id(LastID,Suffix),
5699 % nl, write(lambda(Body,T,ID1)),nl,
5700 (is_an_equality(Body,From,ToExpr) -> LambdaBody = b(truth,pred,[])
5701 ; is_a_conjunct(Body,LambdaBody,Equality),
5702 is_an_equality(Equality,From,ToExpr)),
5703 is_lambda_result_id(From,Suffix).
5704
5705 pp_annotations(V,_) --> {var(V), format('Illegal variable info field in pp_annotations: ~w~n',[V])},!,
5706 "/* ILLEGAL VARIABLE INFO FIELD */".
5707 ?pp_annotations(INFO,_) --> {member(prob_annotation('SYMBOLIC'),INFO)},!,
5708 "/*@symbolic*/ ".
5709 ?pp_annotations(_,b(_,_,INFO)) --> {nonvar(INFO),member(prob_annotation('SYMBOLIC'),INFO)},!,
5710 "/*@symbolic*/ ".
5711 % TO DO: maybe also print other annotations like memoize, recursive ?
5712 pp_annotations(_,_) --> "".
5713
5714 % in Event-B style: { x,y . P | E }
5715 pp_event_b_comprehension_set(Ids,E,P1,LimitReached) -->
5716 left_set_bracket,pp_expr_l(Ids,LimitReached), % use comma separated list; maplet is not accepted by Rodin
5717 {add_normal_typing_predicates(Ids,P1,P)},
5718 dot_symbol,pp_expr_m(P,11,LimitReached),
5719 pp_such_that_bar(P),pp_expr_m(E,11,LimitReached),right_set_bracket.
5720
5721 pp_lambda_identifiers([H1,H2|T],LimitReached) --> {\+ eventb_translation_mode},!,
5722 "(",pp_expr_l([H1,H2|T],LimitReached),")".
5723 pp_lambda_identifiers(L,LimitReached) --> pp_expr_l_pair_in_mode(L,LimitReached).
5724
5725 pp_such_that_bar(_) --> {latex_mode},!, "\\mid ".
5726 pp_such_that_bar(_) --> {unicode_mode},!, "\x2223\". % used by Rodin
5727 pp_such_that_bar(b(unary_minus(_),_,_)) --> !, " | ". % otherwise AtelierB complains about illegal token |-
5728 pp_such_that_bar(b(unary_minus_real(_),_,_)) --> !, " | ". % otherwise AtelierB complains about illegal token |-
5729 pp_such_that_bar(_Next) --> "|".
5730 pp_such_that_bar --> {latex_mode},!, "\\mid ".
5731 pp_such_that_bar --> {unicode_mode},!, "\x2223\".
5732 pp_such_that_bar --> "|".
5733
5734 is_an_equality(b(equal(A,B),_,_),A,B).
5735
5736 integer_set_mapping(A,B) :- integer_set_mapping(A,_,B).
5737 ?integer_set_mapping(A,integer_set,B) :- unicode_mode, unicode_translation(A,B),!.
5738 integer_set_mapping(A,integer_set,B) :- latex_mode, latex_integer_set_translation(A,B),!.
5739 integer_set_mapping(A,integer_set,B) :- atelierb_mode(prover(PPML)),
5740 atelierb_pp_translation(A,PPML,B),!.
5741 integer_set_mapping(A,integer_set,B) :-
5742 eventb_translation_mode, eventb_integer_mapping(A,B),!.
5743 integer_set_mapping(ISet,user_set,Res) :- atomic(ISet),!,Res=ISet.
5744 integer_set_mapping(_ISet,unknown_set,'integer_set(??)').
5745
5746 eventb_integer_mapping('INTEGER','INT').
5747 eventb_integer_mapping('NATURAL','NAT').
5748 eventb_integer_mapping('NATURAL1','NAT1').
5749
5750 real_set_mapping(A,B) :- unicode_mode, unicode_translation(A,B),!.
5751 real_set_mapping(X,X). % TO DO: unicode_mode,...
5752
5753 :- dynamic comment_level/1.
5754 reset_pp :- retractall(comment_level(_)).
5755 enter_comment --> {retract(comment_level(N))},!, "(*", {N1 is N+1, assertz(comment_level(N1))}.
5756 enter_comment --> "/*", {assertz(comment_level(1))}.
5757 exit_comment --> {retract(comment_level(N))},!,
5758 ({N>1} -> "*)", {N1 is N-1, assertz(comment_level(N1))} ; "*/").
5759 exit_comment --> "*/", {add_internal_error('Unmatched closing comment:',exit_comment)}.
5760 % TO DO: ensure reset_pp is called when starting to pretty print, in case timeout occurs in previous pretty prints
5761
5762 %get_last([b(identifier(_lambda_result_10),set(couple(integer,set(couple(integer,integer)))),[])],b(identifier(i),integer,[]),[b(identifier(i),integer,[])],b(identifier(_lambda_result_10),set(couple(integer,set(couple(integer,integer)))),[]))
5763
5764 get_last([],Last,[],Last).
5765 get_last([H2|T],H1,[H1|LT],Last) :- get_last(T,H2,LT,Last).
5766
5767 pp_expr_wrap_l(Pre,Expr,Post,LimitReached) -->
5768 ppatom(Pre),pp_expr_l(Expr,LimitReached),ppatom(Post).
5769 %pp_freetype_term(Term,FT,L,Expr,LimitReached) -->
5770 % {pretty_freetype(FT,P)},
5771 % ppatom(Term),"(",ppatom_opt_scramble(P),",",
5772 % ppatom(L),",",pp_expr_m(Expr,500,LimitReached),")".
5773
5774 % print a list of expressions, seperated by commas
5775 pp_expr_l_pair_in_mode(List,LimitReached) --> {eventb_translation_mode},!,
5776 {maplet_symbol(MapletStr,[])},
5777 pp_expr_l_sep(List,MapletStr,LimitReached).
5778 pp_expr_l_pair_in_mode(List,LimitReached) --> pp_expr_l_sep(List,",",LimitReached).
5779 pp_expr_l(List,LimitReached) --> pp_expr_l_sep(List,",",LimitReached).
5780
5781 pp_expr_l_sep([Expr],_,LimitReached) --> !,
5782 pp_expr_m(Expr,0,LimitReached).
5783 pp_expr_l_sep(List,Sep,LimitReached) --> pp_expr_l2(List,Sep,LimitReached).
5784 pp_expr_l2([],_Sep,_) --> !.
5785 pp_expr_l2([Expr|Rest],Sep,LimitReached) -->
5786 {get_sep_prio(Sep,Prio)},
5787 pp_expr_m(Expr,Prio,LimitReached),
5788 pp_expr_l3(Rest,Sep,LimitReached).
5789 pp_expr_l3([],_Sep,_) --> !.
5790 pp_expr_l3(Rest,Sep,LimitReached) -->
5791 Sep,pp_expr_l2(Rest,Sep,LimitReached).
5792
5793 get_sep_prio(",",Prio) :- !, Prio=116. % Prio of , is 115
5794 get_sep_prio("\\/",Prio) :- !, Prio=161.
5795 get_sep_prio("/\\",Prio) :- !, Prio=161.
5796 get_sep_prio("|->",Prio) :- !, Prio=161.
5797 get_sep_prio([8614],Prio) :- !, Prio=161.
5798 %
5799 get_sep_prio(_,161).
5800
5801 % print the fields of a record
5802 pp_expr_fields([field(Name,Expr)],LimitReached) --> !,
5803 pp_identifier(Name),":",pp_expr_m(Expr,120,LimitReached).
5804 pp_expr_fields(Fields,LimitReached) -->
5805 pp_expr_fields2(Fields,LimitReached).
5806 pp_expr_fields2([],_) --> !.
5807 pp_expr_fields2([field(Name,Expr)|Rest],LimitReached) -->
5808 pp_identifier(Name),":",
5809 pp_expr_m(Expr,116,LimitReached),
5810 pp_expr_fields3(Rest,LimitReached).
5811 pp_expr_fields3([],_) --> !.
5812 pp_expr_fields3(Rest,LimitReached) -->
5813 ",",pp_expr_fields2(Rest,LimitReached).
5814
5815 % TO DO: test more fully; identifiers seem to be wrapped in brackets
5816 pp_expr_let_exists(Ids,Exprs,P,LimitReached) -->
5817 exists_symbol,
5818 ({eventb_translation_mode} -> % otherwise we get strange characters in Rodin, no (.) allowed in Rodin
5819 pp_expr_ids_in_mode(Ids,LimitReached),
5820 ".("
5821 ; " /* LET */ (",
5822 pp_expr_l_pair_in_mode(Ids,LimitReached),
5823 ").("
5824 ),
5825 pp_expr_let_pred_exprs(Ids,Exprs,LimitReached),
5826 ({is_truth(P)} -> ""
5827 ; " ",and_symbol," ", pp_expr_m(P,40,LimitReached)),
5828 ")".
5829
5830 pp_expr_let_pred_exprs([],[],_) --> !.
5831 pp_expr_let_pred_exprs([Id|Irest],[Expr|Erest],LimitReached) -->
5832 " ",pp_expr_let_id(Id,LimitReached),
5833 "=",pp_expr_m(Expr,400,LimitReached),
5834 ( {Irest=[]} -> [] ; " ", and_symbol),
5835 pp_expr_let_pred_exprs(Irest,Erest,LimitReached).
5836
5837 % print a LET expression
5838 pp_expr_let(_Ids,Exprs,P,LimitReached) -->
5839 {eventb_translation_mode,
5840 P=b(_,_,I), member(was(extended_expr(Op)),I)},!, % let was created by direct_definition for a theory operator call
5841 ppatom(Op),
5842 pp_function_left_bracket,
5843 pp_expr_l_sep(Exprs,",",LimitReached),
5844 %pp_expr_let_pred_exprs(Ids,Exprs,LimitReached) % write entire predicate with parameter names
5845 pp_function_right_bracket.
5846 pp_expr_let(Ids,Exprs,P,LimitReached) -->
5847 "LET ", pp_expr_ids_no_parentheses(Ids,LimitReached),
5848 " BE ", pp_expr_let_pred_exprs(Ids,Exprs,LimitReached),
5849 " IN ",pp_expr_m(P,5,LimitReached),
5850 " END".
5851
5852 pp_expr_let_id(ID,LimitReached) --> {atomic(ID),!, write(unwrapped_let_id(ID)),nl},
5853 pp_expr_m(identifier(ID),500,LimitReached).
5854 pp_expr_let_id(ID,LimitReached) --> pp_expr_m(ID,499,LimitReached).
5855
5856 % print a list of identifiers
5857 pp_expr_ids_in_mode([],_) --> !.
5858 pp_expr_ids_in_mode(Ids,LimitReached) --> {eventb_translation_mode ; Ids=[_]},!,
5859 pp_expr_l(Ids,LimitReached). % no (.) allowed in Event-B; not necessary in B if only one id
5860 pp_expr_ids_in_mode(Ids,LimitReached) --> "(",pp_expr_l(Ids,LimitReached),")".
5861
5862 pp_expr_ids([],_) --> !.
5863 pp_expr_ids(Ids,LimitReached) -->
5864 % ( {Ids=[Id]} -> pp_expr_m(Id,221)
5865 % ;
5866 "(",pp_expr_l(Ids,LimitReached),")".
5867
5868 pp_expr_ids_no_parentheses(Ids,LimitReached) --> pp_expr_l(Ids,LimitReached).
5869
5870
5871 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5872 % pretty print types for error messages
5873
5874 %:- use_module(probsrc(typing_tools), [normalize_type/2]).
5875 % replace seq(.) types before pretty printing:
5876 pretty_normalized_type(Type,String) :- typing_tools:normalize_type(Type,NT),!,
5877 pretty_type(NT,String).
5878 pretty_normalized_type(Type,String) :-
5879 add_internal_error('Cannot normalize type:',pretty_normalized_type(Type,String)),
5880 pretty_type(Type,String).
5881
5882 % for pp_expr: do we potentially have to add parentheses
5883 normalized_type_requires_outer_paren(couple(_,_)).
5884 % all other types are either identifiers or use prefix notation (POW(.), seq(.), struct(.))
5885
5886 pretty_type(Type,String) :-
5887 pretty_type_l([Type],[String]).
5888
5889 pretty_type_l(Types,Strings) :-
5890 extract_vartype_names(Types,N),
5891 pretty_type2_l(Types,N,Strings).
5892 pretty_type2_l([],_,[]).
5893 pretty_type2_l([T|TRest],Names,[S|SRest]) :-
5894 pretty_type2(T,Names,noparen,S),
5895 pretty_type2_l(TRest,Names,SRest).
5896
5897 extract_vartype_names(Types,names(Variables,Names)) :-
5898 term_variables(Types,Variables),
5899 name_variables(Variables,1,Names).
5900
5901 pretty_type2(X,names(Vars,Names),_,Name) :- var(X),!,exact_member_lookup(X,Name,Vars,Names).
5902 pretty_type2(any,_,_,'?').
5903 pretty_type2(set(T),N,_,Text) :- nonvar(T),T=couple(A,B),!,
5904 pretty_type2(A,N,paren,AT), pretty_type2(B,N,paren,BT),
5905 binary_infix_in_mode(relations,Symbol,_,_), % <->
5906 ajoin(['(',AT,Symbol,BT,')'],Text).
5907 pretty_type2(set(T),N,_,Text) :-
5908 pretty_type2(T,N,noparen,TT), function_like_in_mode(pow_subset,POW),
5909 ajoin([POW,'(',TT,')'],Text).
5910 pretty_type2(seq(T),N,_,Text) :-
5911 pretty_type2(T,N,noparen,TT), ajoin(['seq(',TT,')'],Text).
5912 pretty_type2(couple(A,B),N,Paren,Text) :-
5913 pretty_type2(A,N,paren,AT),pretty_type2(B,N,paren,BT),
5914 binary_infix_in_mode(cartesian_product,Cart,_,_),
5915 ajoin([AT,Cart,BT],Prod),
5916 ( Paren == noparen ->
5917 Text = Prod
5918 ;
5919 ajoin(['(',Prod,')'],Text)).
5920 pretty_type2(string,_,_,'STRING').
5921 pretty_type2(integer,_,_,Atom) :- integer_set_mapping('INTEGER',Atom).
5922 pretty_type2(real,_,_,Atom) :- real_set_mapping('REAL',Atom).
5923 pretty_type2(boolean,_,_,'BOOL').
5924 pretty_type2(global(G_Id),_,_,A) :- opt_scramble_id(G_Id,G), ajoin([G],A).
5925 pretty_type2(freetype(Id),N,_,A) :- pretty_freetype2(Id,N,A).
5926 pretty_type2(pred,_,_,predicate).
5927 pretty_type2(subst,_,_,substitution).
5928 pretty_type2(constant(List),_,_,A) :-
5929 (var(List) -> ['{??VAR??...}'] % should not happen
5930 ; ajoin_with_sep(List,',',P), ajoin(['{',P,'}'],A)).
5931 pretty_type2(record(Fields),N,_,Text) :-
5932 pretty_type_fields(Fields,N,FText),
5933 ajoin(['struct(',FText,')'],Text).
5934 pretty_type2(op(Params,Results),N,_,Text) :-
5935 pretty_type_l(Params,N,PText),
5936 ( nonvar(Results),Results=[] ->
5937 ajoin(['operation(',PText,')'],Text)
5938 ;
5939 pretty_type_l(Results,N,RText),
5940 ajoin([RText,'<--operation(',PText,')'],Text) ).
5941 pretty_type2(definition(DefType,_,_),_,_,DefType).
5942 pretty_type2(witness,_,_,witness).
5943 pretty_type2([],_,_,'[]') :- add_error(pretty_type,'Illegal list in type:','[]').
5944 pretty_type2([H|T],_,_,'[_]') :- add_error(pretty_type,'Illegal list in type:',[H|T]).
5945 pretty_type2(b(E,T,I),_,_,'?') :- add_error(pretty_type,'Illegal b/3 term in type:',b(E,T,I)).
5946
5947 pretty_type_l(L,_,'...') :- var(L),!.
5948 pretty_type_l([],_,'') :- !.
5949 pretty_type_l([E|Rest],N,Text) :-
5950 pretty_type2(E,N,noparen,EText),
5951 ( nonvar(Rest),Rest=[] ->
5952 EText=Text
5953 ;
5954 pretty_type_l(Rest,N,RText),
5955 ajoin([EText,',',RText],Text)).
5956
5957 pretty_type_fields(L,_,'...') :- var(L),!.
5958 pretty_type_fields([],_,'') :- !.
5959 pretty_type_fields([field(Name,Type)|FRest],N,Text) :- !,
5960 pretty_type2(Type,N,noparen,TText),
5961 ptf_seperator(FRest,Sep),
5962 pretty_type_fields(FRest,N,RestText),
5963 opt_scramble_id(Name,ScrName),
5964 ajoin([ScrName,':',TText,Sep,RestText],Text).
5965 pretty_type_fields(Err,N,Text) :-
5966 add_internal_error('Illegal field type: ',pretty_type_fields(Err,N,Text)), Text='??'.
5967 ptf_seperator(L,', ') :- var(L),!.
5968 ptf_seperator([],'') :- !.
5969 ptf_seperator(_,', ').
5970
5971 pretty_freetype(Id,A) :-
5972 extract_vartype_names(Id,N),
5973 pretty_freetype2(Id,N,A).
5974 pretty_freetype2(Id,_,A) :- var(Id),!,A='_'.
5975 pretty_freetype2(Id,_,A) :- atomic(Id),!,Id=A.
5976 pretty_freetype2(Id,N,A) :-
5977 Id=..[Name|TypeArgs],
5978 pretty_type2_l(TypeArgs,N,PArgs),
5979 ajoin_with_sep(PArgs,',',P),
5980 ajoin([Name,'(',P,')'],A).
5981
5982 name_variables([],_,[]).
5983 name_variables([_|VRest],Index,[Name|NRest]) :-
5984 (nth1(Index,"ABCDEFGHIJKLMNOPQRSTUVWXYZ",C) -> SName = [C] ; number_codes(Index,SName)),
5985 append("_",SName,CName),atom_codes(Name,CName),
5986 Next is Index+1,
5987 name_variables(VRest,Next,NRest).
5988
5989 ppatom(Var) --> {var(Var)},!, ppatom('$VARIABLE').
5990 ppatom(Cmp) --> {compound(Cmp)},!, ppatom('$COMPOUND_TERM').
5991 ppatom(Atom) --> {safe_atom_codes(Atom,Codes)}, ppcodes(Codes).
5992
5993 ppnumber(Number) --> {var(Number)},!,pp_clpfd_variable(Number).
5994 ppnumber(inf) --> !,"inf".
5995 ppnumber(minus_inf) --> !,"minus_inf".
5996 ppnumber(Number) --> {number(Number),number_codes(Number,Codes)},!, ppcodes(Codes).
5997 ppnumber(Number) --> {add_internal_error('Not a number: ',ppnumber(Number,_,_))}, "<<" ,ppterm(Number), ">>".
5998
5999 pp_numberedvar(N) --> "_",ppnumber(N),"_".
6000
6001 pp_clpfd_variable(X) --> "?:",{fd_dom(X,Dom)},write_to_codes(Dom), pp_frozen_info(X).
6002
6003 pp_frozen_info(_X) --> {get_preference(translate_print_frozen_infos,false)},!,[].
6004 pp_frozen_info(X) -->
6005 ":(",{frozen(X,Goal)},
6006 write_goal_with_max_depth(Goal),
6007 ")".
6008
6009 write_goal_with_max_depth((A,B)) --> !, "(",write_goal_with_max_depth(A),
6010 ", ", write_goal_with_max_depth(B), ")".
6011 write_goal_with_max_depth(Term) --> write_with_max_depth(3,Term).
6012
6013 write_with_max_depth(Depth,Term,S1,S2) :- write_term_to_codes(Term,S1,S2,[max_depth(Depth)]).
6014
6015 ppterm(Term) --> write_to_codes(Term).
6016
6017 ppcodes([],S,S).
6018 ppcodes([C|Rest],[C|In],Out) :- ppcodes(Rest,In,Out).
6019
6020 ppterm_with_limit_reached(Term,LimitReached) -->
6021 {write_to_codes(Term,Codes,[])}, ppcodes_with_limit_reached(Codes,LimitReached).
6022
6023 ppcodes_with_limit_reached([C|Rest],LimitReached,[C|In],Out) :- var(LimitReached), !,
6024 ppcodes_with_limit_reached(Rest,LimitReached,In,Out).
6025 ppcodes_with_limit_reached(_,_LimitReached,S,S).
6026
6027 % for debugging:
6028 :- public b_portray_hook/1.
6029 b_portray_hook(X) :-
6030 nonvar(X),
6031 (is_texpr(X), ground(X) -> write('{# '),print_bexpr_or_subst(X),write(' #}')
6032 ; X=avl_set(_), ground(X) -> write('{#avl '), print_bvalue(X), write(')}')
6033 ; X=wfx(WF0,_,WFE,Info) -> format('wfx(~w,$mutable,~w,~w)',[WF0,WFE,Info]) % to do: short summary of prios & call stack
6034 ).
6035
6036 install_b_portray_hook :- % register portray hook mainly for the Prolog debugger
6037 assertz(( user:portray(X) :- translate:b_portray_hook(X) )).
6038 remove_b_portray_hook :-
6039 retractall( user:portray(_) ).
6040
6041
6042 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6043 % Pretty-print of Event-B models as classical B
6044
6045 translate_eventb_to_classicalb(EBMachine,AddInfo,Rep) :-
6046 ( conversion_check(EBMachine) ->
6047 convert_eventb_classicalb(EBMachine,CBMachine),
6048 call_cleanup(( set_animation_mode(b), % clear minor mode "eventb"
6049 translate_machine(CBMachine,Rep,AddInfo),!),
6050 set_animation_minor_mode(eventb))
6051 ; \+ animation_minor_mode(eventb) -> add_error(translate,'Conversion only applicable to Event-B models')
6052 ;
6053 add_error_and_fail(translate,'Conversion not applicable, check if you limited the number of abstract level to 0')
6054 ).
6055
6056 convert_eventb_classicalb(EBMachine,CBMachine) :-
6057 select_section(operation_bodies,In,Out,EBMachine,CBMachine1),
6058 maplist(convert_eventop,In,Out),
6059 select_section(initialisation,IIn,IOut,CBMachine1,CBMachine),
6060 convert_event(IIn,[],IOut).
6061 convert_eventop(EBOp,CBOp) :-
6062 get_texpr_expr(EBOp,operation(Id,[],Args,EBBody)),
6063 get_texpr_info(EBOp,Info),
6064 convert_event(EBBody,Args,CBBody),
6065 % Remove the arguments
6066 create_texpr(operation(Id,[],[],CBBody),op([],[]),Info,CBOp).
6067 convert_event(TEvent,Parameters,TSubstitution) :-
6068 get_texpr_expr(TEvent,rlevent(_Id,_Section,_Status,_Parameters,Guard,_Theorems,Actions,_VariableWitnesses,_ParameterWitnesses,_Ums,_Refined)),
6069 in_parallel(Actions,PAction),
6070 convert_event2(Parameters,Guard,PAction,TSubstitution).
6071 convert_event2([],Guard,Action,Action) :-
6072 is_truth(Guard),!.
6073 convert_event2([],Guard,Action,Select) :-
6074 !,create_texpr(select([When]),subst,[],Select),
6075 create_texpr(select_when(Guard,Action),subst,[],When).
6076 convert_event2(Parameters,Guard,Action,Any) :-
6077 create_texpr(any(Parameters,Guard,Action),subst,[],Any).
6078 in_parallel([],Skip) :- !,create_texpr(skip,subst,[],Skip).
6079 in_parallel([A],A) :- !.
6080 in_parallel(Actions,Parallel) :- create_texpr(parallel(Actions),subst,[],Parallel).
6081
6082 conversion_check(Machine) :-
6083 animation_mode(b),
6084 animation_minor_mode(eventb),
6085 get_section(initialisation,Machine,Init),
6086 get_texpr_expr(Init,rlevent(_Id,_Sec,_St,_Par,_Grd,_Thms,_Act,_VW,_PW,_Ums,[])).
6087
6088 % ------------------------------------------------------------
6089
6090 % divide a B typed expression into columns for CSV export or Table viewing of its values
6091 get_bexpression_column_template(b(couple(A,B),_,_),(AVal,BVal),ColHeaders,Columns) :- !,
6092 get_bexpression_column_template(A,AVal,AHeaders,AColumns),
6093 get_bexpression_column_template(B,BVal,BHeaders,BColumns),
6094 append(AHeaders,BHeaders,ColHeaders),
6095 append(AColumns,BColumns,Columns).
6096 get_bexpression_column_template(TypedExpr,Value,[ColHeader],[Value]) :-
6097 translate:translate_bexpression_with_limit(TypedExpr,100,ColHeader).
6098
6099
6100 % a version of member that creates an error when info list not instantiated
6101 member_in_info(X,T) :- var(T),!, add_internal_error('Illegal info field:', member_in_info(X,T)),fail.
6102 member_in_info(X,[X|_]).
6103 ?member_in_info(X,[_|T]) :- member_in_info(X,T).
6104
6105 memberchk_in_info(X,T) :- var(T),!, add_internal_error('Illegal info field:', memberchk_in_info(X,T)),fail.
6106 memberchk_in_info(X,[X|_]) :- !.
6107 memberchk_in_info(X,[_|T]) :- memberchk_in_info(X,T).
6108
6109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6110
6111 :- use_module(library(clpfd)).
6112
6113 % print also partially instantiated variables with CLP(FD) Info
6114 print_value_variable(X) :- var(X), !, write(X).
6115 print_value_variable(int(X)) :- write('int('), print_clpfd_variable(X), write(')').
6116 print_value_variable(fd(X,T)) :- write('fd('), print_clpfd_variable(X), write(','), write(T),write(')').
6117 print_value_variable(X) :- write(X).
6118
6119 print_clpfd_variable(X) :- var(X),!,write(X), write(':'), fd_dom(X,Dom), write(Dom), print_frozen_info(X).
6120 print_clpfd_variable(X) :- write(X).
6121
6122 %print_clpfd_variables([]).
6123 %print_clpfd_variables([H|T]) :- write('CLPFD: '),print_clpfd_variable(H), nl, print_clpfd_variables(T).
6124
6125
6126 :- public l_print_frozen_info/1.
6127 l_print_frozen_info([]).
6128 l_print_frozen_info([H|T]) :- write(H), write(' '),
6129 (var(H) -> print_frozen_info(H) ;
6130 H=fd_var(V,_) -> print_frozen_info(V) ; true), l_print_frozen_info(T).
6131
6132 print_frozen_info(X) :- frozen(X,Goal), print_frozen_goal(Goal).
6133 print_frozen_goal((A,B)) :- !, print_frozen_goal(A), write(','), print_frozen_goal(B).
6134 print_frozen_goal(prolog:trig_nondif(_A,_B,R,_S)) :- !, frozen(R,G2), print_frozen_goal2(G2).
6135 print_frozen_goal(G) :- print_frozen_goal2(G).
6136 print_frozen_goal2(V) :- var(V),!, write(V).
6137 print_frozen_goal2(true) :- !.
6138 print_frozen_goal2((A,B)) :- !, print_frozen_goal2(A), write(','), print_frozen_goal2(B).
6139 print_frozen_goal2(G) :- write(' :: '), tools_printing:print_term_summary(G).
6140
6141
6142 /* Event-B operators */
6143 translate_eventb_operators([]) --> !.
6144 translate_eventb_operators([Name-Call|Rest]) -->
6145 translate_eventb_operator(Call,Name),
6146 translate_eventb_operators(Rest).
6147
6148 translate_eventb_operator(Module:Call,Name) -->
6149 insertcodes("\n "),
6150 indention_codes(In,Out),
6151 {Call =.. [Functor|Args],
6152 translate_eventb_operator2(Functor,Args,Module,Call,Name,In,Out)}.
6153
6154
6155 translate_eventb_operator2(direct_definition,[Args,_RawWD,RawBody,TypeParas|_],_Module,_Call,Name) -->
6156 pp_eventb_direct_definition_header(Name,Args),!,
6157 ppcodes(" direct_definition ["),
6158 pp_eventb_operator_args(TypeParas),
6159 ppcodes("] "),
6160 {translate_in_mode(eqeq,'==',EqEqStr)}, ppatom(EqEqStr),
6161 ppcodes(" "),
6162 pp_raw_formula(RawBody). % TO DO: use indentation
6163 translate_eventb_operator2(axiomatic_definition,[Tag|_],_Module,_Call,Name) --> !,
6164 ppterm(Name),
6165 ppcodes(": Operator implemented by axiomatic definition using "),
6166 ppatom(Tag).
6167 translate_eventb_operator2(Functor,_,Module,_Call,Name) -->
6168 ppterm(Name),
6169 ppcodes(": Operator implemented by "),
6170 ppatom(Module),ppcodes(":"),ppatom(Functor).
6171
6172 % example direct definition:
6173 %direct_definition([argument(curM,integer_set(none)),argument(curH,integer_set(none))],truth(none),add(none,identifier(none,curM),multiplication(none,identifier(none,curH),integer(none,60))),[])
6174
6175 pp_eventb_direct_definition_header(Name,Args) -->
6176 ppterm(Name), ppcodes("("),
6177 pp_eventb_operator_args(Args), ppcodes(")").
6178
6179 translate_eventb_direct_definition_header(Name,Args,ResAtom) :-
6180 (pp_eventb_direct_definition_header(Name,Args,C,[])
6181 -> atom_codes(ResAtom,C) ; ResAtom='<<UNABLE TO PRETTY-PRINT OPERATOR HEADER>>').
6182 translate_eventb_direct_definition_body(RawBody,ResAtom) :-
6183 (pp_raw_formula(RawBody,C,[]) -> atom_codes(ResAtom,C) ; ResAtom='<<UNABLE TO PRETTY-PRINT OPERATOR BODY>>').
6184
6185 ?pp_raw_formula(RawExpr) --> {transform_raw(RawExpr,TExpr)},!, pp_expr(TExpr,_,_LR).
6186 pp_raw_formula(_) --> ppcodes("<<UNABLE TO PRETTY-PRINT>>").
6187
6188
6189 pp_eventb_operator_args([]) --> [].
6190 pp_eventb_operator_args([Arg]) --> !, pp_argument(Arg).
6191 pp_eventb_operator_args([Arg|T]) --> pp_argument(Arg), ppcodes(","),
6192 pp_eventb_operator_args(T).
6193 pp_argument(argument(ID,_RawType)) --> !, ppatom(ID).
6194 pp_argument(identifier(_,ID)) --> !, "<",ppatom(ID),">".
6195 pp_argument(Atom) --> ppatom(Atom).
6196
6197 % ---------------------------------------
6198
6199 % translate a predicate into B machine for manipulation
6200 translate_predicate_into_machine(Pred,MchName,ResultAtom) :-
6201 with_language_mode(b, translate_predicate_into_machine_aux(Pred,MchName,ResultAtom)). % clear minor mode "eventb"
6202 translate_predicate_into_machine_aux(Pred,MchName,ResultAtom) :-
6203 get_global_identifiers(Ignored,ignore_promoted_constants),
6204 find_typed_identifier_uses(Pred, Ignored, TUsedIds),
6205 get_texpr_ids(TUsedIds,UsedIds),
6206 add_typing_predicates(TUsedIds,Pred,TPred),
6207 set_print_type_infos(all,CHNG),
6208 call_pp_with_no_limit_and_parseable(pred_over_lines(2,_Lbl,TPred,(0,CPrettyPred),(_,[]))), % split predicate into one conjunct per line
6209 atom_codes(PrettyPred,CPrettyPred),
6210 reset_print_type_infos(CHNG),
6211 convert_and_ajoin_ids_line_break(UsedIds,AllIds,10),
6212 bmachine:get_full_b_machine(Name,BMachine),
6213 include(relevant_section,BMachine,RelevantSections),
6214 % TO DO: we could filter out enumerate/deferred sets not occuring in Pred
6215 translate_section_list(RelevantSections,SetsParas),
6216 atom_codes(ASP,SetsParas),
6217 pp_identifier(MchName,CMchName,[]), atom_codes(EMchName,CMchName),
6218 ajoin(['MACHINE ', EMchName, ' /* generated from ',Name,' */\n',ASP,'CONSTANTS\n ',AllIds,'\nPROPERTIES',PrettyPred,'\nEND\n'],ResultAtom).
6219
6220 relevant_section(deferred_sets/_).
6221 relevant_section(enumerated_elements/_).
6222 relevant_section(parameters/_).
6223
6224 :- use_module(library(system),[ datime/1]).
6225 :- use_module(specfile,[currently_opened_file/1]).
6226 :- use_module(probsrc(version), [format_prob_version/1]).
6227 % print a Proof Obligation aka Sequent as a B machine
6228 % Rodin disprover can print this to tmp/ProB_Rodin_PO_SelectedHyps.mch
6229 nested_print_sequent_as_classicalb(Stream,HypsList,Goal,AllHypsList,MchName,ProofInfos) :-
6230 set_suppress_rodin_positions(false,Chng), % ensure we print Rodin labels if available
6231 call_cleanup(nested_print_sequent_as_classicalb_aux(Stream,HypsList,Goal,AllHypsList,MchName,ProofInfos),
6232 reset_suppress_rodin_positions(Chng)).
6233
6234 % convert identifier by adding backquote if necessary for unicode, reserved keywords, ...
6235 convert_id(b(identifier(ID),_,_),CAtom) :- !, convert_id(ID,CAtom).
6236 convert_id(Atom,CAtom) :- atom(Atom),!,pp_identifier(Atom,Codes,[]), atom_codes(CAtom,Codes).
6237 convert_id(E,CAtom) :- add_internal_error('Illegal id: ',E), CAtom = '?'.
6238 convert_and_ajoin_ids(UsedIds,AllIdsWithCommas) :-
6239 maplist(convert_id,UsedIds,ConvUsedIds),
6240 ajoin_with_sep(ConvUsedIds,', ',AllIdsWithCommas).
6241 convert_and_ajoin_ids_line_break(UsedIds,AllIdsWithLineBreak,Threshold) :-
6242 (length(UsedIds,Len), Len>Threshold -> Sep=',\n ' ; Sep=', ' ),
6243 maplist(convert_id,UsedIds,ConvUsedIds),
6244 ajoin_with_sep(ConvUsedIds,Sep,AllIdsWithLineBreak).
6245
6246 nested_print_sequent_as_classicalb_aux(Stream,HypsList,Goal,AllHypsList,MchName,ProofInfos) :-
6247 conjunct_predicates(HypsList,HypsPred),
6248 conjunct_predicates([Goal|HypsList],Pred),
6249 get_global_identifiers(Ignored,ignore_promoted_constants), % the sets section below will not print the promoted enumerated set constants, they may also not be valid for the selected hyps only
6250 find_typed_identifier_uses(Pred, Ignored, TUsedIds),
6251 get_texpr_ids(TUsedIds,UsedIds),
6252 convert_and_ajoin_ids(UsedIds,AllIds),
6253 bmachine:get_full_b_machine(_Name,BMachine),
6254 include(relevant_section,BMachine,RelevantSections),
6255 % TO DO: we could filter out enumerate/deferred sets not occuring in Pred
6256 translate_section_list(RelevantSections,SetsParas),
6257 set_print_type_infos(all,CHNG),
6258 datime(datime(Yr,Mon,Day,Hr,Min,_Sec)),
6259 format(Stream,'MACHINE ~w~n /* Exported: ~w/~w/~w ~w:~w */~n',[MchName,Day,Mon,Yr,Hr,Min]),
6260 (currently_opened_file(File), bmachine:b_machine_name(Name)
6261 -> format(Stream,' /* Origin: ~w : ~w */~n',[Name,File]) ; true),
6262 write(Stream,' /* '),format_prob_version(Stream), format(Stream,' */~n',[]),
6263 format(Stream,' /* Use static asssertion checking to look for counter examples: */~n',[]),
6264 format(Stream,' /* - probcli -cbc_assertions ProB_Rodin_PO_SelectedHyps.mch */~n',[]),
6265 format(Stream,' /* - in ProB2-UI: Verifications View -> Symbolic Tab -> Static Assertion Checking */~n',[]),
6266 maplist(format_proof_infos(Stream),ProofInfos),
6267 format(Stream,'~sCONSTANTS~n ~w~nPROPERTIES /* Selected Hypotheses: */~n',[SetsParas,AllIds]),
6268 add_typing_predicates(TUsedIds,HypsPred,HypsT),
6269 current_output(OldStream),
6270 set_output(Stream),
6271 nested_print_bexpr_as_classicalb2(HypsT,s(0)), % TODO: pass stream to this predicate
6272 format(Stream,'~nASSERTIONS /* Proof Goal: */~n',[]),
6273 nested_print_bexpr_as_classicalb2(Goal,s(0)), % TODO: pass stream to this predicate
6274 (AllHypsList = [] -> true
6275 ; sort(AllHypsList,SAL), sort(HypsList,SL),
6276 ord_subtract(SAL,SL,RemainingHypsList), % TODO: we could preserve order
6277 conjunct_predicates(RemainingHypsList,AllHypsPred),
6278 find_typed_identifier_uses(AllHypsPred, Ignored, TAllUsedIds),
6279 get_texpr_ids(TAllUsedIds,AllUsedIds),
6280 ord_subtract(AllUsedIds,UsedIds,NewIds), % compute new ids not used in selected hyps and goal
6281 (NewIds = []
6282 -> format(Stream,'OPERATIONS~n CheckRemainingHypotheses = SELECT~n',[])
6283 ; ajoin_with_sep(NewIds,', ',NIdLst),
6284 format(Stream,'OPERATIONS~n CheckRemainingHypotheses(~w) = SELECT~n',[NIdLst])
6285 ),
6286 add_typing_predicates(TAllUsedIds,AllHypsPred,AllHypsT),
6287 nested_print_bexpr_as_classicalb2(AllHypsT,s(0)), % TODO: pass stream to this predicate
6288 format(Stream,' THEN skip~n END /* CheckRemainingHypotheses */~n',[])
6289 ),
6290 set_output(OldStream),
6291 reset_print_type_infos(CHNG),
6292 format(Stream,'DEFINITIONS~n SET_PREF_DISPROVER_MODE == TRUE~n ; SET_PREF_TRY_FIND_ABORT == FALSE~n',[]),
6293 format(Stream,' ; SET_PREF_ALLOW_REALS == FALSE~n',[]),
6294 % The Rodin DisproverCommand.java usually enables CHR;
6295 % TODO: we could also look for options(List) in ProofInfos and check use_chr_solver/true in List, ...
6296 (get_preference(use_clpfd_solver,false) -> format(Stream,' ; SET_PREF_CHR == FALSE~n',[]) ; true),
6297 (get_preference(use_chr_solver,true) -> format(Stream,' ; SET_PREF_CHR == TRUE~n',[]) ; true),
6298 (get_preference(use_smt_mode,true) -> format(Stream,' ; SET_PREF_SMT == TRUE~n',[]) ; true),
6299 (get_preference(use_common_subexpression_elimination,true) -> format(Stream,' ; SET_PREF_CSE == TRUE~n',[]) ; true),
6300 (get_preference(smt_supported_interpreter,true) -> format(Stream,' ; SET_PREF_SMT_SUPPORTED_INTERPRETER == TRUE~n',[]) ; true),
6301 format(Stream,'END~n',[]).
6302
6303 format_proof_infos(_,Var) :- var(Var),!.
6304 format_proof_infos(Stream,disprover_result(Prover,Hyps,Result)) :- nonvar(Result),functor(Result,FR,_),!,
6305 format(Stream,' /* ProB Disprover ~w result on ~w : ~w */~n',[Prover,Hyps,FR]).
6306 format_proof_infos(Stream,E) :- format(Stream,' /* ~w */~n',[E]).
6307
6308
6309 % ---------------------------------------
6310
6311
6312 % show non obvious functors
6313 get_texpr_top_level_symbol(TExpr,Symbol,2,infix) :-
6314 translate:binary_infix_symbol(TExpr,Symbol),!.
6315 get_texpr_top_level_symbol(b(E,_,_),Symbol,1,postfix) :-
6316 functor(E,F,1), translate:unary_postfix_in_mode(F,Symbol,_),!.
6317 get_texpr_top_level_symbol(b(E,_,_),Symbol,3,prefix) :-
6318 functor(E,F,Arity), (Arity=3 ; Arity=2), % 2 for exists
6319 quantified_in_mode(F,Symbol),!.
6320 get_texpr_top_level_symbol(b(E,_,_),Symbol,N,prefix) :-
6321 functor(E,F,N),
6322 function_like_in_mode(F,Symbol).
6323
6324 % ---------------
6325
6326 % feedback to user about values
6327 translate_bvalue_kind([],Res) :- !, Res='EMPTY-Set'.
6328 translate_bvalue_kind([_|_],Res) :- !, Res='LIST-Set'.
6329 translate_bvalue_kind(avl_set(A),Res) :- !, avl_size(A,Size), ajoin(['AVL-Set:',Size],Res).
6330 translate_bvalue_kind(int(_),Res) :- !, Res = 'INTEGER'.
6331 translate_bvalue_kind(term(floating(_)),Res) :- !, Res = 'FLOAT'.
6332 translate_bvalue_kind(string(_),Res) :- !, Res = 'STRING'.
6333 translate_bvalue_kind(pred_true,Res) :- !, Res = 'TRUE'.
6334 translate_bvalue_kind(pred_false,Res) :- !, Res = 'FALSE'.
6335 translate_bvalue_kind(fd(_,T),Res) :- !, Res = T.
6336 translate_bvalue_kind((_,_),Res) :- !, Res = 'PAIR'.
6337 translate_bvalue_kind(rec(_),Res) :- !, Res = 'RECORD'.
6338 translate_bvalue_kind(freeval(Freetype,_Case,_),Res) :- !, Res = Freetype.
6339 translate_bvalue_kind(CL,Res) :- custom_explicit_sets:is_interval_closure(CL,_,_),!, Res= 'INTERVAL'.
6340 translate_bvalue_kind(CL,Res) :- custom_explicit_sets:is_infinite_explicit_set(CL),!, Res= 'INFINITE-Set'.
6341 translate_bvalue_kind(closure(_,_,_),Res) :- !, Res= 'SYMBOLIC-Set'.
6342
6343
6344 % ---------------------------------------
6345
6346 :- use_module(tools_printing,[better_write_canonical_to_codes/3]).
6347 pp_xtl_value(Value) --> better_write_canonical_to_codes(Value).
6348
6349 translate_xtl_value(Value,Output) :-
6350 pp_xtl_value(Value,Codes,[]),
6351 atom_codes_with_limit(Output,Codes).