1 | | % (c) 2009-2024 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, |
2 | | % Heinrich Heine Universitaet Duesseldorf |
3 | | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) |
4 | | |
5 | | :- module(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_as_classicalb/1, |
9 | | print_bexpr_stream/2, |
10 | | print_components/1, |
11 | | print_bexpr_with_limit/2, |
12 | | print_unwrapped_bexpr_with_limit/1,print_bvalue/1, l_print_bvalue/1, print_bvalue_stream/2, |
13 | | translate_params_for_dot/2, translate_params_for_dot_nl/2, |
14 | | print_machine/1, |
15 | | translate_machine/3, |
16 | | set_unicode_mode/0, unset_unicode_mode/0, unicode_mode/0, |
17 | | unicode_translation/2, % unicode translation of a symbol/keyword |
18 | | set_latex_mode/0, unset_latex_mode/0, latex_mode/0, |
19 | | set_atelierb_mode/1, unset_atelierb_mode/0, |
20 | | set_force_eventb_mode/0, unset_force_eventb_mode/0, |
21 | | get_translation_mode/1, set_translation_mode/1, unset_translation_mode/1, |
22 | | with_translation_mode/2, |
23 | | get_language_mode/1, set_language_mode/1, with_language_mode/2, |
24 | | translate_bexpression_to_unicode/2, |
25 | | translate_bexpression/2, translate_subst_or_bexpr_in_mode/3, |
26 | | translate_bexpression_with_limit/3, translate_bexpression_with_limit/2, |
27 | | translate_bexpression_to_codes/2, |
28 | | translate_bexpr_to_parseable/2, |
29 | | translate_predicate_into_machine/3, nested_print_sequent_as_classicalb/6, |
30 | | get_bexpression_column_template/4, |
31 | | translate_subst_or_bexpr/2, translate_subst_or_bexpr_with_limit/3, |
32 | | translate_substitution/2, print_subst/1, |
33 | | translate_bvalue/2, translate_bvalue_to_codes/2, translate_bvalue_to_codes_with_limit/3, |
34 | | translate_bvalue_to_parseable_classicalb/2, |
35 | | translate_bvalue_for_dot/2, |
36 | | translate_bvalue_with_limit/3, |
37 | | translate_bvalue_with_type/3, translate_bvalue_with_type_and_limit/4, |
38 | | translate_bvalue_for_expression/3, translate_bvalue_for_expression_with_limit/4, |
39 | | translate_bvalue_with_tlatype/3, |
40 | | translate_bvalue_kind/2, |
41 | | print_state/1, |
42 | | translate_bstate/2, translate_bstate_limited/2, translate_bstate_limited/3, |
43 | | print_bstate/1, print_bstate_limited/3, |
44 | | translate_b_state_to_comma_list/3, |
45 | | translate_context/2, print_context/1, |
46 | | translate_any_state/2, |
47 | | print_value_variable/1, |
48 | | print_cspm_state/1, translate_cspm_state/2, |
49 | | print_csp_value/1, translate_csp_value/2, |
50 | | translate_cspm_expression/2, |
51 | | translate_properties_with_limit/2, |
52 | | translate_event/2,translate_events/2, |
53 | | translate_event_with_target_id/4, |
54 | | translate_event_with_src_and_target_id/4, translate_event_with_src_and_target_id/5, |
55 | | get_non_det_modified_vars_in_target_id/3, |
56 | | translate_event_with_limit/3, |
57 | | translate_state_errors/2,translate_state_error/2, |
58 | | translate_event_error/2, |
59 | | translate_call_stack/2, |
60 | | translate_prolog_constructor/2, translate_prolog_constructor_in_mode/2, |
61 | | get_texpr_top_level_symbol/4, |
62 | | pretty_type/2, % pretty-prints a type (pp_type, translate_type) |
63 | | explain_state_error/3, get_state_error_span/2, |
64 | | explain_event_trace/3, |
65 | | generate_typing_predicates/2, % keeps sequence typing info |
66 | | |
67 | | print_raw_machine_terms/1, |
68 | | print_raw_bexpr/1, l_print_raw_bexpr/1, |
69 | | translate_raw_bexpr_with_limit/3, |
70 | | |
71 | | print_span/1, print_span_nl/1, translate_span/2, |
72 | | translate_span_with_filename/2, |
73 | | get_definition_context_from_span/2, |
74 | | |
75 | | %set_type_to_maximal_texpr/2, type_set/2, % now in typing_tools as create_type_set |
76 | | |
77 | | translate_error_term/2, translate_error_term/3, |
78 | | translate_prolog_exception/2, |
79 | | |
80 | | set_translation_constants/1, set_translation_context/1, |
81 | | clear_translation_constants/0, |
82 | | |
83 | | set_print_type_infos/1, |
84 | | suppress_rodin_positions/1, reset_suppress_rodin_positions/1, |
85 | | add_normal_typing_predicates/3, |
86 | | |
87 | | install_b_portray_hook/0,remove_b_portray_hook/0, |
88 | | |
89 | | translate_eventb_to_classicalb/3, |
90 | | translate_eventb_direct_definition_header/3, translate_eventb_direct_definition_body/2, |
91 | | return_csp_closure_value/2, |
92 | | latex_to_unicode/2, get_latex_keywords/1, get_latex_keywords_with_backslash/1, |
93 | | ascii_to_unicode/2 |
94 | | |
95 | | ]). |
96 | | |
97 | | :- meta_predicate call_pp_with_no_limit_and_parseable(0). |
98 | | :- meta_predicate with_translation_mode(+, 0). |
99 | | :- meta_predicate with_language_mode(+, 0). |
100 | | |
101 | | :- use_module(tools). |
102 | | :- use_module(tools_lists,[is_list_simple/1]). |
103 | | :- use_module(extrasrc(json_parser), [json_write_stream/1]). |
104 | | |
105 | | :- use_module(module_information). |
106 | | :- module_info(group,tools). |
107 | | :- module_info(description,'This module is responsible for pretty-printing B and CSP, source spans, ...'). |
108 | | |
109 | | :- use_module(library(lists)). |
110 | | :- use_module(library(codesio)). |
111 | | :- use_module(library(terms)). |
112 | | :- use_module(library(avl)). |
113 | | |
114 | | :- use_module(debug). |
115 | | :- use_module(error_manager). |
116 | | :- use_module(self_check). |
117 | | :- use_module(b_global_sets). |
118 | | :- use_module(specfile,[csp_with_bz_mode/0,process_algebra_mode/0, |
119 | | animation_minor_mode/1,set_animation_minor_mode/1, |
120 | | remove_animation_minor_mode/0, |
121 | | animation_mode/1,set_animation_mode/1, csp_mode/0, |
122 | | translate_operation_name/2]). |
123 | | :- use_module(bsyntaxtree). |
124 | | %:- use_module('smv/smv_trans',[smv_print_initialisation/2]). |
125 | | :- use_module(preferences,[get_preference/2, set_preference/2, eclipse_preference/2]). |
126 | | :- use_module(bmachine_structure). |
127 | | :- use_module(avl_tools,[check_is_non_empty_avl/1]). |
128 | | |
129 | | :- set_prolog_flag(double_quotes, codes). |
130 | | |
131 | | % print a list of expressions or substitutions |
132 | | l_print_bexpr_or_subst([]). |
133 | | l_print_bexpr_or_subst([H|T]) :- |
134 | | print_bexpr_or_subst(H), |
135 | | (T=[] -> true |
136 | | ; (get_texpr_type(H,Type),is_subst_type(Type) -> print('; ') ; print(', '), |
137 | | l_print_bexpr_or_subst(T)) |
138 | | ). |
139 | | |
140 | | is_subst_type(T) :- var(T),!,fail. |
141 | | is_subst_type(subst). |
142 | | is_subst_type(op(_,_)). |
143 | | |
144 | | print_bexpr_or_subst(E) :- get_texpr_type(E,T),is_subst_type(T),!, print_subst(E). |
145 | | print_bexpr_or_subst(precondition(A,B)) :- !, print_subst(precondition(A,B)). |
146 | | print_bexpr_or_subst(any(A,B,C)) :- !, print_subst(any(A,B,C)). |
147 | | print_bexpr_or_subst(select(A)) :- !, print_subst(select(A)). % TO DO: add more cases ? |
148 | | print_bexpr_or_subst(E) :- print_bexpr(E). |
149 | | |
150 | | print_unwrapped_bexpr_with_limit(Expr) :- print_unwrapped_bexpr_with_limit(Expr,200). |
151 | | print_unwrapped_bexpr_with_limit(Expr,Limit) :- |
152 | | translate:print_bexpr_with_limit(b(Expr,pred,[]),Limit),nl. |
153 | | debug_print_bexpr(E) :- debug:debug_mode(off) -> true ; print_bexpr(E). |
154 | | print_bexpr(Expr) :- translate_bexpression(Expr,R), write(R). |
155 | | print_bexpr_with_limit(Expr,Limit) :- translate_bexpression_with_limit(Expr,Limit,R), write(R). |
156 | | print_bvalue(Val) :- translate_bvalue(Val,TV), write(TV). |
157 | | print_bexpr_stream(S,Expr) :- translate_bexpression(Expr,R), write(S,R). |
158 | | print_bvalue_stream(S,Val) :- translate_bvalue(Val,R), write(S,R). |
159 | | |
160 | | print_components(C) :- print_components(C,0). |
161 | | print_components([],Nr) :- write('Nr of components: '),write(Nr),nl. |
162 | | print_components([component(Pred,Vars)|T],Nr) :- N1 is Nr+1, |
163 | | write('Component: '), write(N1), write(' over '), write(Vars),nl, |
164 | | print_bexpr(Pred),nl, |
165 | | print_components(T,N1). |
166 | | |
167 | | l_print_bvalue([]). |
168 | | l_print_bvalue([H|T]) :- print_bvalue(H), write(' : '),l_print_bvalue(T). |
169 | | |
170 | | nested_print_bexpr_as_classicalb(E) :- nested_print_bexpr_as_classicalb2(E,0). |
171 | | |
172 | | nested_print_bexpr_as_classicalb2(E,InitialPeanoIndent) :- |
173 | | (animation_minor_mode(X) |
174 | | -> remove_animation_minor_mode, |
175 | | call_cleanup(nested_print_bexpr2(E,InitialPeanoIndent), set_animation_minor_mode(X)) |
176 | | ; nested_print_bexpr2(E,InitialPeanoIndent)). |
177 | | |
178 | | % can also print lists of predicates and lists of lists, ... |
179 | | nested_print_bexpr(Expr) :- nested_print_bexpr2(Expr,0). |
180 | | |
181 | | % a version where one can specify the initial indent in peano numbering |
182 | | nested_print_bexpr2([],_) :- !. |
183 | | nested_print_bexpr2([H],InitialIndent) :- !,nested_print_bexpr2(H,InitialIndent). |
184 | | nested_print_bexpr2([H|T],II) :- !, |
185 | | nested_print_bexpr2(H,II), |
186 | | print_indent(II), write('&'),nl, |
187 | | nested_print_bexpr2(T,II). |
188 | | nested_print_bexpr2(Expr,II) :- nbp(Expr,conjunct,II). |
189 | | |
190 | | nbp(b(E,_,Info),Type,Indent) :- !,nbp2(E,Type,Info,Indent). |
191 | | nbp(E,Type,Indent) :- format(user_error,'Missing b/3 wrapper!~n',[]), |
192 | | nbp2(E,Type,[],Indent). |
193 | | nbp2(E,Type,_Info,Indent) :- get_binary_connective(E,NewType,Ascii,LHS,RHS),!, |
194 | | inc_indent(NewType,Type,Indent,NIndent), |
195 | | print_bracket(Indent,NIndent,'('), |
196 | | nbp(LHS,NewType,NIndent), |
197 | | print_indent(NIndent), |
198 | | translate_in_mode(NewType,Ascii,Symbol), print(Symbol),nl, |
199 | | (is_associative(NewType) -> NewTypeR=NewType % no need for parentheses if same operator on right |
200 | | ; NewTypeR=right(NewType)), |
201 | | nbp(RHS,NewTypeR,NIndent), |
202 | | print_bracket(Indent,NIndent,')'). |
203 | | nbp2(lazy_let_pred(TID,LHS,RHS),Type,_Info,Indent) :- |
204 | | def_get_texpr_id(TID,ID),!, |
205 | | NewType=lazy_let_pred(TID), |
206 | | inc_indent(NewType,Type,Indent,NIndent), |
207 | | print_indent(Indent), format('LET ~w = (~n',[ID]), |
208 | | nbp(LHS,NewType,NIndent), |
209 | | print_indent(NIndent), print(') IN ('),nl, |
210 | | nbp(RHS,NewType,NIndent), |
211 | | print_indent(NIndent),print(')'),nl. |
212 | | nbp2(negation(LHS),_Type,_Info,Indent) :- !, |
213 | | inc_indent(negation,false,Indent,NIndent), |
214 | | print_indent(Indent), |
215 | | translate_in_mode(negation,'not',Symbol), format('~s(~n',[Symbol]), |
216 | | nbp(LHS,negation,NIndent), |
217 | | print_indent(Indent), print(')'),nl. |
218 | | nbp2(let_predicate(Ids,Exprs,Pred),_Type,_Info,Indent) :- !, |
219 | | inc_indent(let_predicate,false,Indent,NIndent), |
220 | | pp_expr_ids_in_mode(Ids,_LR,Codes,[]), |
221 | | print_indent(Indent),format('#~s.( /* LET */~n',[Codes]), |
222 | | pp_expr_let_pred_exprs(Ids,Exprs,_LimitReached,Codes2,[]), |
223 | | print_indent(Indent), format('~s~n',[Codes2]), |
224 | | print_indent(NIndent), print('&'),nl, |
225 | | nbp(Pred,let_predicate,NIndent), |
226 | | print_indent(Indent), print(')'),nl. |
227 | | nbp2(exists(Ids,Pred),_Type,_Infos,Indent) :- !, |
228 | | inc_indent(exists,false,Indent,NIndent), |
229 | | pp_expr_ids_in_mode(Ids,_LR,Codes,[]), |
230 | | print_indent(Indent), |
231 | | %(member(allow_to_lift_exists,_Infos) -> write('/* LIFT */ ') ; true), |
232 | | exists_symbol(ExistsSymbol,[]), format('~s~s.(~n',[ExistsSymbol,Codes]), |
233 | | nbp(Pred,exists,NIndent), |
234 | | print_indent(Indent), print(')'),nl. |
235 | | nbp2(forall(Ids,LHS,RHS),_Type,_Info,Indent) :- !, |
236 | | inc_indent(forall,false,Indent,NIndent), |
237 | | pp_expr_ids_in_mode(Ids,_LR,Codes,[]), |
238 | | print_indent(Indent), |
239 | | forall_symbol(ForallSymbol,[]), format('~s~s.(~n',[ForallSymbol,Codes]), |
240 | | nbp(LHS,forall,NIndent), |
241 | | print_indent(NIndent), |
242 | | translate_in_mode(implication,'=>',Symbol),print(Symbol),nl, |
243 | | nbp(RHS,forall,NIndent), |
244 | | print_indent(Indent), print(')'),nl. |
245 | | nbp2(if_then_else(Test,LHS,RHS),_Type,_Info,Indent) :- !, |
246 | | inc_indent(if_then_else,false,Indent,NIndent), |
247 | | print_indent(Indent), print('IF'),nl, |
248 | | nbp(Test,if_then_else,NIndent), |
249 | | print_indent(Indent), print('THEN'),nl, |
250 | | nbp(LHS,if_then_else,NIndent), |
251 | | print_indent(Indent), print('ELSE'),nl, |
252 | | nbp(RHS,if_then_else,NIndent), |
253 | | print_indent(Indent), print('END'),nl. |
254 | | %nbp2(equal(LHS,RHS),pred,_Info,Indent) :- |
255 | | % get_texpr_id(LHS,_Id),!, |
256 | | % print_indent(Indent),print_bexpr(LHS),print(' ='),nl, |
257 | | % inc_indent(equal,false,Indent,NIndent), |
258 | | nbp2(value(V),_,Info,Indent) :- !, |
259 | | print_indent(Indent), print_bexpr(b(value(V),any,Info)),nl. |
260 | | nbp2(E,_,Info,Indent) :- print_indent(Indent), print_bexpr(b(E,pred,Info)),nl. |
261 | | |
262 | | % all left-associative |
263 | | get_binary_connective(conjunct(LHS,RHS),conjunct,'&',LHS,RHS). |
264 | | get_binary_connective(disjunct(LHS,RHS),disjunct,'or',LHS,RHS). |
265 | | get_binary_connective(implication(LHS,RHS),implication,'=>',LHS,RHS). |
266 | | get_binary_connective(equivalence(LHS,RHS),equivalence,'<=>',LHS,RHS). |
267 | | |
268 | | inc_indent(Type,CurType,I,NewI) :- (Type=CurType -> NewI=I ; NewI=s(I)). |
269 | | print_bracket(I,I,_) :- !. |
270 | | print_bracket(I,_NewI,Bracket) :- |
271 | | print_indent(I), print(Bracket),nl. |
272 | | |
273 | | print_indent(s(X)):- !, |
274 | | print(' '), |
275 | | print_indent(X). |
276 | | print_indent(_). |
277 | | |
278 | | |
279 | | /* =============================================== */ |
280 | | /* Translating expressions and values into strings */ |
281 | | /* =============================================== */ |
282 | | |
283 | | translate_params_for_dot(List,TransList) :- |
284 | | translate_params_for_dot(List,TransList,3,-3). |
285 | | translate_params_for_dot_nl(List,TransList) :- % newline after every entry |
286 | | translate_params_for_dot(List,TransList,1,-1). |
287 | | |
288 | | translate_params_for_dot([],'',_,_). |
289 | | translate_params_for_dot([H|T],Res,Lim,Nr) :- |
290 | | translate_property_with_limit(H,100,TH), |
291 | | (Nr>=Lim -> N1=1 % Limit reached, add newline |
292 | | ; N1 is Nr+1), |
293 | | translate_params_for_dot(T,TT,Lim,N1), |
294 | | string_concatenate(TH,TT,Res1), |
295 | | (N1=1 |
296 | | -> string_concatenate(',\n',Res1,Res) |
297 | | ; (Nr>(-Lim) -> string_concatenate(',',Res1,Res) |
298 | | ; Res=Res1)). |
299 | | |
300 | | |
301 | | translate_channel_values(X,['_'|T],T) :- var(X),!. |
302 | | translate_channel_values([],S,S) :- !. |
303 | | translate_channel_values([tuple([])|T],S,R) :- !, |
304 | | translate_channel_values(T,S,R). |
305 | | translate_channel_values([in(tuple([]))|T],S,R) :- !, |
306 | | translate_channel_values(T,S,R). |
307 | | translate_channel_values([H|T],['.'|S],R) :- !, |
308 | | ((nonvar(H),H=in(X)) |
309 | | -> Y=X |
310 | | ; Y=H |
311 | | ), |
312 | | pp_csp_value(Y,S,S2), |
313 | | translate_channel_values(T,S2,R). |
314 | | translate_channel_values(tail_in(X),S,T) :- |
315 | | (X=[] ; X=[_|_]), !, translate_channel_values(X,S,T). |
316 | | translate_channel_values(_X,['??'|S],S). |
317 | | |
318 | | |
319 | | |
320 | | pp_single_csp_value(V,'_') :- var(V),!. |
321 | | pp_single_csp_value(X,'_cyclic_') :- cyclic_term(X),!. |
322 | | pp_single_csp_value(int(X),A) :- atomic(X),!,number_chars(X,Chars),atom_chars(A,Chars). |
323 | | |
324 | | :- assert_must_succeed((translate_cspm_expression(listExp(rangeOpen(2)),R), R == '<2..>')). |
325 | | :- assert_must_succeed((translate_cspm_expression(listFrom(2),R), R == '<2..>')). |
326 | | :- assert_must_succeed((translate_cspm_expression(listFromTo(2,6),R), R == '<2..6>')). |
327 | | :- assert_must_succeed((translate_cspm_expression(setFromTo(2,6),R), R == '{2..6}')). |
328 | | :- assert_must_succeed((translate_cspm_expression('#'(listFromTo(2,6)),R), R == '#<2..6>')). |
329 | | :- assert_must_succeed((translate_cspm_expression(inGuard(x,setFromTo(1,5)),R), R == '?x:{1..5}')). |
330 | | :- assert_must_succeed((translate_cspm_expression(builtin_call(int(3)),R), R == '3')). |
331 | | :- assert_must_succeed((translate_cspm_expression(set_to_seq(setValue([int(1),int(2)])),R), R == 'seq({1,2})')). |
332 | | :- assert_must_succeed((translate_cspm_expression(diff(setValue([int(1)]),setValue([])),R), R == 'diff({1},{})')). |
333 | | :- assert_must_succeed((translate_cspm_expression(inter(setValue([int(1)]),setValue([])),R), R == 'inter({1},{})')). |
334 | | :- assert_must_succeed((translate_cspm_expression(lambda([x,y],'*'(x,y)),R), R == '\\ x,y @ (x*y)')). |
335 | | :- assert_must_succeed((translate_cspm_expression(lambda([x,y],'/'(x,y)),R), R == '\\ x,y @ (x/y)')). |
336 | | :- assert_must_succeed((translate_cspm_expression(lambda([x,y],'%'(x,y)),R), R == '\\ x,y @ (x%y)')). |
337 | | :- assert_must_succeed((translate_cspm_expression(rename(x,y),R), R == 'x <- y')). |
338 | | :- assert_must_succeed((translate_cspm_expression(link(x,y),R), R == 'x <-> y')). |
339 | | :- assert_must_succeed((translate_cspm_expression(agent_call_curry(f,[[a,b],[c]]),R), R == 'f(a,b)(c)')). |
340 | | |
341 | | translate_cspm_expression(Expr, Text) :- |
342 | | (pp_csp_value(Expr,Atoms,[]) -> ajoin(Atoms,Text) |
343 | | ; print('Pretty printing expression failed: '),print(Expr),nl). |
344 | | |
345 | | pp_csp_value(X,[A|S],S) :- pp_single_csp_value(X,A),!. |
346 | | pp_csp_value(setValue(L),['{'|S],T) :- !,pp_csp_value_l(L,',',S,['}'|T],inf). |
347 | | pp_csp_value(setExp(rangeEnum(L)),['{'|S],T) :- !,pp_csp_value_l(L,',',S,['}'|T],inf). |
348 | | pp_csp_value(setExp(rangeEnum(L),Gen),['{'|S],T) :- !, |
349 | | copy_term((L,Gen),(L2,Gen2)), numbervars((L2,Gen2),1,_), |
350 | | pp_csp_value_l(L2,',',S,['|'|S2],inf), |
351 | | pp_csp_value_l(Gen2,',',S2,['}'|T],inf). |
352 | | pp_csp_value(avl_set(A),['{'|S],T) :- !, check_is_non_empty_avl(A), |
353 | | avl_domain(A,L),pp_csp_value_l(L,',',S,['}'|T],inf). |
354 | | pp_csp_value(setExp(rangeClosed(L,U)),['{'|S],T) :- !, pp_csp_value(L,S,['..'|S2]),pp_csp_value(U,S2,['}'|T]). |
355 | | pp_csp_value(setExp(rangeOpen(L)),['{'|S],T) :- !, pp_csp_value(L,S,['..}'|T]). |
356 | | % TO DO: pretty print comprehensionGuard; see prints in coz-example.csp ; test 1846 |
357 | | pp_csp_value(comprehensionGenerator(Var,Body),S,T) :- !, pp_csp_value(Var,S,['<-'|S1]), |
358 | | pp_csp_value(Body,S1,T). |
359 | | pp_csp_value(listExp(rangeEnum(L)),['<'|S],T) :- !,pp_csp_value_l(L,',',S,['>'|T],inf). |
360 | | pp_csp_value(listExp(rangeClosed(L,U)),['<'|S],T) :- !, pp_csp_value(L,S,['..'|S2]),pp_csp_value(U,S2,['>'|T]). |
361 | | pp_csp_value(listExp(rangeOpen(L)),['<'|S],T) :- !, pp_csp_value(L,S,['..>'|T]). |
362 | | pp_csp_value(setFromTo(L,U),['{'|S],T) :- !, |
363 | | pp_csp_value(L,S,['..'|S2]),pp_csp_value(U,S2,['}'|T]). |
364 | | pp_csp_value(setFrom(L),['{'|S],T) :- !, |
365 | | pp_csp_value(L,S,['..}'|T]). |
366 | | pp_csp_value(closure(L), ['{|'|S],T) :- !,pp_csp_value_l(L,',',S,['|}'|T],inf). |
367 | | pp_csp_value(list(L),['<'|S],T) :- !,pp_csp_value_l(L,',',S,['>'|T],inf). |
368 | | pp_csp_value(listFromTo(L,U),['<'|S],T) :- !, |
369 | | pp_csp_value(L,S,['..'|S2]),pp_csp_value(U,S2,['>'|T]). |
370 | | pp_csp_value(listFrom(L),['<'|S],T) :- !, |
371 | | pp_csp_value(L,S,['..>'|T]). |
372 | | pp_csp_value('#'(L),['#'|S],T) :- !,pp_csp_value(L,S,T). |
373 | | pp_csp_value('^'(X,Y),S,T) :- !,pp_csp_value(X,S,['^'|S1]), pp_csp_value(Y,S1,T). |
374 | | pp_csp_value(linkList(L),S,T) :- !,pp_csp_value_l(L,',',S,T,inf). |
375 | | pp_csp_value(in(X),['?'|S],T) :- !,pp_csp_value(X,S,T). |
376 | | pp_csp_value(inGuard(X,Set),['?'|S],T) :- !,pp_csp_value(X,S,[':'|S1]), |
377 | | pp_csp_value(Set,S1,T). |
378 | | pp_csp_value(out(X),['!'|S],T) :- !,pp_csp_value(X,S,T). |
379 | | pp_csp_value(alsoPat(X,_Y),S,T) :- !,pp_csp_value(X,S,T). |
380 | | pp_csp_value(appendPat(X,_Fun),S,T) :- !,pp_csp_value(X,S,T). |
381 | | pp_csp_value(tuple(vclosure),S,T) :- !, S=T. |
382 | | pp_csp_value(tuple([X]),S,T) :- !,pp_csp_value_in(X,S,T). |
383 | | pp_csp_value(tuple([X|vclosure]),S,T) :- !,pp_csp_value_in(X,S,T). |
384 | | pp_csp_value(tuple([H|TT]),S,T) :- !,pp_csp_value_in(H,S,['.'|S1]),pp_csp_value(tuple(TT),S1,T). |
385 | | pp_csp_value(dotTuple([]),['unit_channel'|S],S) :- ! . |
386 | | pp_csp_value(dotTuple([H]),S,T) :- !, pp_csp_value_in(H,S,T). |
387 | | pp_csp_value(dotTuple([H|TT]),S,T) :- !, pp_csp_value_in(H,S,['.'|S1]), |
388 | | pp_csp_value(dotTuple(TT),S1,T). |
389 | | pp_csp_value(tupleExp(Args),S,T) :- !,pp_csp_args(Args,S,T,'(',')'). |
390 | | pp_csp_value(na_tuple(Args),S,T) :- !,pp_csp_args(Args,S,T,'(',')'). |
391 | | pp_csp_value(record(Name,Args),['('|S],T) :- !,pp_csp_value(tuple([Name|Args]),S,[')'|T]). |
392 | | pp_csp_value(val_of(Name,_Span),S,T) :- !, pp_csp_value(Name,S,T). |
393 | | pp_csp_value(builtin_call(X),S,T) :- !,pp_csp_value(X,S,T). |
394 | | pp_csp_value(seq_to_set(X),['set('|S],T) :- !,pp_csp_value(X,S,[')'|T]). |
395 | | pp_csp_value(set_to_seq(X),['seq('|S],T) :- !,pp_csp_value(X,S,[')'|T]). |
396 | | %pp_csp_value('\\'(B,C,S),S1,T) :- !, pp_csp_process(ehide(B,C,S),S1,T). |
397 | | pp_csp_value(agent_call(_Span,Agent,Parameters),['('|S],T) :- !, |
398 | | pp_csp_value(Agent,S,S1), |
399 | | pp_csp_args(Parameters,S1,[')'|T],'(',')'). |
400 | | pp_csp_value(agent_call_curry(Agent,Parameters),S,T) :- !, |
401 | | pp_csp_value(Agent,S,S1), |
402 | | pp_csp_curry_args(Parameters,S1,T). |
403 | | pp_csp_value(lambda(Parameters,Body),['\\ '|S],T) :- !, |
404 | | pp_csp_args(Parameters,S,[' @ '|S1],'',''), |
405 | | pp_csp_value(Body,S1,T). |
406 | | pp_csp_value(rename(X,Y),S,T) :- !,pp_csp_value(X,S,[' <- '|S1]), |
407 | | pp_csp_value(Y,S1,T). |
408 | | pp_csp_value(link(X,Y),S,T) :- !,pp_csp_value(X,S,[' <-> '|S1]), |
409 | | pp_csp_value(Y,S1,T). |
410 | | % binary operators: |
411 | | pp_csp_value(Expr,['('|S],T) :- bynary_numeric_operation(Expr,E1,E2,OP),!, |
412 | | pp_csp_value(E1,S,[OP|S2]), |
413 | | pp_csp_value(E2,S2,[')'|T]). |
414 | | % built-in functions for sets |
415 | | pp_csp_value(empty(A),[empty,'('|S],T) :- !, pp_csp_value(A,S,[')'|T]). |
416 | | pp_csp_value(card(A),[card,'('|S],T) :- !, pp_csp_value(A,S,[')'|T]). |
417 | | pp_csp_value('Set'(A),['Set','('|S],T) :- !, pp_csp_value(A,S,[')'|T]). |
418 | | pp_csp_value('Inter'(A1),['Inter','('|S],T) :- !,pp_csp_value(A1,S,[')'|T]). |
419 | | pp_csp_value('Union'(A1),['Union','('|S],T) :- !,pp_csp_value(A1,S,[')'|T]). |
420 | | pp_csp_value(diff(A1,A2),[diff,'('|S],T) :- !,pp_csp_args([A1,A2],S,[')'|T],'',''). |
421 | | pp_csp_value(inter(A1,A2),[inter,'('|S],T) :- !,pp_csp_args([A1,A2],S,[')'|T],'',''). |
422 | | pp_csp_value(union(A1,A2),[union,'('|S],T) :- !,pp_csp_args([A1,A2],S,[')'|T],'',''). |
423 | | pp_csp_value(member(A1,A2),[member,'('|S],T) :- !,pp_csp_args([A1,A2],S,[')'|T],'',''). |
424 | | % built-in functions for sequences |
425 | | pp_csp_value(null(A),[null,'('|S],T) :- !, pp_csp_value(A,S,[')'|T]). |
426 | | pp_csp_value(length(A),[length,'('|S],T) :- !, pp_csp_value(A,S,[')'|T]). |
427 | | pp_csp_value(head(A),[head,'('|S],T) :- !, pp_csp_value(A,S,[')'|T]). |
428 | | pp_csp_value(tail(A),[tail,'('|S],T) :- !, pp_csp_value(A,S,[')'|T]). |
429 | | pp_csp_value(elem(A1,A2),[elem,'('|S],T) :- !,pp_csp_args([A1,A2],S,[')'|T],'',''). |
430 | | pp_csp_value(concat(A1,A2),[concat,'('|S],T) :- !,pp_csp_args([A1,A2],S,[')'|T],'',''). |
431 | | pp_csp_value('Seq'(A),['Seq','('|S],T) :- !, pp_csp_value(A,S,[')'|T]). |
432 | | % vclosure |
433 | | pp_csp_value(Expr,S,T) :- is_list(Expr),!,pp_csp_value(closure(Expr),S,T). |
434 | | % Type expressions |
435 | | pp_csp_value(dotTupleType([H]),S,T) :- !, pp_csp_value_in(H,S,T). |
436 | | pp_csp_value(dotTupleType([H|TT]),S,T) :- !,pp_csp_value_in(H,S,['.'|S1]), pp_csp_value(dotTupleType(TT),S1,T). |
437 | | pp_csp_value(typeTuple(Args),S,T) :- !, pp_csp_args(Args,S,T,'(',')'). |
438 | | pp_csp_value(dataType(T),[T|S],S) :- ! . |
439 | | pp_csp_value(boolType,['Bool'|S],S) :- ! . |
440 | | pp_csp_value(intType,['Int'|S],S) :- ! . |
441 | | pp_csp_value(dataTypeDef([H]),S,T) :- !, pp_csp_value(H,S,T). |
442 | | pp_csp_value(dataTypeDef([H|TT]),S,T) :- !, pp_csp_value(H,S,['|'|S1]), |
443 | | pp_csp_value(dataTypeDef(TT),S1,T). |
444 | | pp_csp_value(constructor(Name),[Name|S],S) :- ! . |
445 | | pp_csp_value(constructorC(C,Type),[C,'('|S],T) :- !, pp_csp_value(Type,S,[')'|T]). |
446 | | % Argument of function can be process |
447 | | |
448 | | pp_csp_value(Expr,S,T) :- pp_csp_process(Expr,S,T),!. % pp_csp_process has a catch-all !!! TO DO: look at this |
449 | | pp_csp_value(Expr,S,T) :- csp_with_bz_mode,!,pp_value(Expr,S,T). |
450 | | pp_csp_value(X, [A|S], S) :- % ['<< ',A,' >>'|S],S) :- % the << >> pose problems when checking against FDR |
451 | | write_to_codes(X,Codes),atom_codes_with_limit(A,Codes). |
452 | | |
453 | | pp_csp_value_in(H,S,T) :- nonvar(H),H=in(X),!, pp_csp_value(X,S,T). |
454 | | pp_csp_value_in(H,S,T) :- pp_csp_value(H,S,T). |
455 | | |
456 | | print_csp_value(Val) :- pp_csp_value(Val,Atoms,[]), ajoin(Atoms,Text), |
457 | | print(Text). |
458 | | |
459 | | translate_csp_value(Val,Text) :- pp_csp_value(Val,Atoms,[]), ajoin(Atoms,Text). |
460 | | |
461 | | return_csp_closure_value(closure(S),List) :- pp_csp_value_l1(S,List). |
462 | | return_csp_closure_value(setValue(S),List) :- pp_csp_value_l1(S,List). |
463 | | |
464 | | pp_csp_value_l1([Expr|Rest],List) :- |
465 | | ( nonvar(Rest),Rest=[] -> |
466 | | pp_csp_value(Expr,T,[]),ajoin(T,Value),List=[Value] |
467 | | ; pp_csp_value_l1(Rest,R),pp_csp_value(Expr,T,[]),ajoin(T,Value),List=[Value|R] |
468 | | ). |
469 | | |
470 | | pp_csp_args([],T,T,_LPar,_RPar). |
471 | | pp_csp_args([H|TT],[LPar|S],T,LPar,RPar) :- pp_csp_value(H,S,S1), pp_csp_args2(TT,S1,T,RPar). |
472 | | pp_csp_args2([],[RPar|T],T,RPar). |
473 | | pp_csp_args2([H|TT],[','|S],T,RPar) :- pp_csp_value(H,S,S1), pp_csp_args2(TT,S1,T,RPar). |
474 | | |
475 | | pp_csp_curry_args([],T,T). |
476 | | pp_csp_curry_args([H|TT],S,T) :- is_list(H), pp_csp_args(H,S,S1,'(',')'), pp_csp_curry_args(TT,S1,T). |
477 | | |
478 | | pp_csp_value_l(V,_Sep,['...'|S],S,N) :- (var(V) ; (N \= inf -> N<1;fail)), !. |
479 | | pp_csp_value_l([],_Sep,S,S,_). |
480 | | pp_csp_value_l([Expr|Rest],Sep,S,T,Nr) :- |
481 | | ( nonvar(Rest),Rest=[] -> |
482 | | pp_csp_value(Expr,S,T) |
483 | | ; |
484 | | (Nr=inf -> N1 = Nr ; N1 is Nr-1), |
485 | | pp_csp_value(Expr,S,[Sep|S1]),pp_csp_value_l(Rest,Sep,S1,T,N1)). |
486 | | |
487 | | :- assert_must_succeed((translate:convert_set_into_sequence([(int(1),int(5))],Seq), |
488 | | check_eqeq(Seq,[int(5)]))). |
489 | | :- assert_must_succeed((translate:convert_set_into_sequence([(int(2),X),(int(1),int(5))],Seq), |
490 | | check_eq(Seq,[int(5),X]))). |
491 | | |
492 | | convert_set_into_sequence(Set,Seq) :- |
493 | | nonvar(Set), \+ eventb_translation_mode, |
494 | | convert_set_into_sequence1(Set,Seq). |
495 | | convert_set_into_sequence1(avl_set(A),Seq) :- !, check_is_non_empty_avl(A), |
496 | | avl_size(A,Sz),size_is_in_set_limit(Sz),convert_avlset_into_sequence(A,Seq). |
497 | | convert_set_into_sequence1([],Seq) :- !, Seq=[]. |
498 | | convert_set_into_sequence1(Set,Seq) :- |
499 | | convert_set_into_sequence2(Set,0,_,SetElems,Seq),ground(SetElems). |
500 | | convert_set_into_sequence2([],_Max,([],[]),_,_Seq). |
501 | | convert_set_into_sequence2([Pair|T],Max,Last,SetElems,Seq) :- |
502 | | nonvar(Pair),nonvar(T),Pair=(Index,H),ground(Index), |
503 | | Index=int(Nr), |
504 | | insert_el_into_seq(Nr,H,Seq,SetElems,L), |
505 | | (Nr>Max -> NMax=Nr,NLast=L ; NMax=Max,NLast=Last), |
506 | | convert_set_into_sequence2(T,NMax,NLast,SetElems,Seq). |
507 | | insert_el_into_seq(1,H,[H|L],[set|L2],(L,L2)) :- !. |
508 | | insert_el_into_seq(N,H,[_|T],[_|T2],Last) :- N>1, N1 is N-1, insert_el_into_seq(N1,H,T,T2,Last). |
509 | | |
510 | | convert_avlset_into_sequence(Avl,Sequence) :- |
511 | | \+ eventb_translation_mode, |
512 | | convert_avlset_into_sequence2(Avl,1,Sequence). |
513 | | convert_avlset_into_sequence2(Avl,_Index,[]) :- |
514 | | empty_avl(Avl),!. |
515 | | convert_avlset_into_sequence2(Avl,Index,[Head|Tail]) :- |
516 | | avl_del_min(Avl, Min, _ ,NewAvl), |
517 | | nonvar(Min), Min=(L,Head), |
518 | | ground(L), L=int(Index), |
519 | | Index2 is Index + 1, |
520 | | convert_avlset_into_sequence2(NewAvl,Index2,Tail). |
521 | | |
522 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
523 | | % translate new syntax tree -- work in progress |
524 | | :- assert_must_succeed((translate_cspm_state(lambda([x,y],'|~|'(prefix(_,[],x,skip(_),_),prefix(_,[],y,skip(_),_),_)),R), R == 'CSP: \\ x,y @ (x->SKIP) |~| (y->SKIP)')). |
525 | | :- assert_must_succeed((translate_cspm_state(agent_call_curry('F',[[a,b],[c]]),R), R == 'CSP: F(a,b)(c)')). |
526 | | :- 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)')). |
527 | | :- assert_must_succeed((translate_cspm_state(aParallel([a,b],'P',[b,c],'Q',span),R), R == 'CSP: P [{|a,b|} || {|b,c|}] Q')). |
528 | | :- assert_must_succeed((translate_cspm_state(eaParallel([a,b],'P',[b,c],'Q',span),R), R == 'CSP: P [{|a,b|} || {|b,c|}] Q')). |
529 | | :- assert_must_succeed((translate_cspm_state(eexception([a,b],'P','Q',span),R), R == 'CSP: P [|{|a,b|}|> Q')). |
530 | | |
531 | | print_cspm_state(State) :- translate_cspm_state(State,T), print(T). |
532 | | |
533 | | translate_cspm_state(State,Text) :- |
534 | | ( pp_csp_process(State,Atoms,[]) -> true |
535 | | ; print(pp_csp_process_failed(State)),nl,Atoms=State), |
536 | | ajoin(['CSP: '|Atoms],Text). |
537 | | |
538 | | pp_csp_process(skip(_Span),S,T) :- !, S=['SKIP'|T]. |
539 | | pp_csp_process(stop(_Span),S,T) :- !, S=['STOP'|T]. |
540 | | pp_csp_process('CHAOS'(_Span,Set),['CHAOS('|S],T) :- !, |
541 | | pp_csp_value(Set,S,[')'|T]). |
542 | | pp_csp_process(val_of(Agent,_Span),S,T) :- !, |
543 | | pp_csp_value(Agent,S,T). |
544 | | pp_csp_process(builtin_call(X),S,T) :- !,pp_csp_process(X,S,T). |
545 | | pp_csp_process(agent(F,Body,_Span),S,T) :- !, |
546 | | F =.. [Agent|Parameters], |
547 | | pp_csp_value(Agent,S,S1), |
548 | | pp_csp_args(Parameters,S1,[' = '|S2],'(',')'), |
549 | | pp_csp_value(Body,S2,T). |
550 | | pp_csp_process(agent_call(_Span,Agent,Parameters),S,T) :- !, |
551 | | pp_csp_value(Agent,S,S1), |
552 | | pp_csp_args(Parameters,S1,T,'(',')'). |
553 | | pp_csp_process(agent_call_curry(Agent,Parameters),S,T) :- !, |
554 | | pp_csp_value(Agent,S,S1), |
555 | | pp_csp_curry_args(Parameters,S1,T). |
556 | | pp_csp_process(lambda(Parameters,Body),['\\ '|S],T) :- !, |
557 | | pp_csp_args(Parameters,S,[' @ '|S1],'',''), |
558 | | pp_csp_value(Body,S1,T). |
559 | | pp_csp_process('\\'(B,C,S),S1,T) :- !, pp_csp_process(ehide(B,C,S),S1,T). |
560 | | pp_csp_process(ehide(Body,ChList,_Span),['('|S],T) :- !, |
561 | | pp_csp_process(Body,S,[')\\('|S1]), |
562 | | pp_csp_value(ChList,S1,[')'|T]). |
563 | | pp_csp_process(let(Decls,P),['let '| S],T) :- !, |
564 | | maplist(translate_cspm_state,Decls,Texts), |
565 | | ajoin_with_sep(Texts,' ',Text), |
566 | | S=[Text,' within '|S1], |
567 | | pp_csp_process(P,S1,T). |
568 | | pp_csp_process(Expr,['('|S],T) :- binary_csp_op(Expr,X,Y,Op),!, |
569 | | pp_csp_process(X,S,[') ',Op,' ('|S1]), |
570 | | pp_csp_process(Y,S1,[')'|T]). |
571 | | pp_csp_process(Expr,S,T) :- sharing_csp_op(Expr,X,Middle,Y,Op1,Op2),!, |
572 | | pp_csp_process(X,S,[Op1|S1]), |
573 | | pp_csp_value(Middle,S1,[Op2|S2]), |
574 | | pp_csp_process(Y,S2,T). |
575 | | pp_csp_process(Expr,S,T) :- asharing_csp_op(Expr,X,MiddleX,MiddleY,Y,Op1,MOp,Op2),!, |
576 | | pp_csp_process(X,S,[Op1|S1]), |
577 | | pp_csp_value(MiddleX,S1,[MOp|S2]), |
578 | | pp_csp_value(MiddleY,S2,[Op2|S3]), |
579 | | pp_csp_process(Y,S3,T). |
580 | | pp_csp_process(Expr,S,T) :- renaming_csp_op(Expr,X,RList,Op1,Op2),!, |
581 | | pp_csp_process(X,S,[Op1|S1]), |
582 | | pp_csp_value_l(RList,',',S1,[Op2|T],10). |
583 | | pp_csp_process(prefix(_SPAN1,Values,ChannelExpr,CSP,_SPAN2),S,T) :- !, |
584 | | pp_csp_value_l([ChannelExpr|Values],'',S,['->'|S2],20), |
585 | | pp_csp_process(CSP,S2,T). |
586 | | pp_csp_process('&'(Test,Then),S,T) :- !, |
587 | | pp_csp_bool_expr(Test,S,['&'|S2]), |
588 | | pp_csp_process(Then,S2,T). |
589 | | pp_csp_process(ifte(Test,Then,Else,_SPAN1,_SPAN2,_SPAN3),[' if '|S],T) :- !, |
590 | | pp_csp_bool_expr(Test,S,[' then '|S2]), |
591 | | pp_csp_process(Then,S2,[' else '|S3]), |
592 | | pp_csp_process(Else,S3,T). |
593 | | pp_csp_process(head(A),[head,'('|S],T) :- !, pp_csp_process(A,S,[')'|T]). |
594 | | pp_csp_process(X,[X|T],T). |
595 | | |
596 | | pp_csp_bool_expr(bool_not(BE),['not('|S],T) :- !, pp_csp_bool_expr(BE,S,[')'|T]). |
597 | | pp_csp_bool_expr(BE,['('|S],T) :- binary_bool_op(BE,BE1,BE2,OP), !, |
598 | | pp_csp_bool_expr(BE1,S,[OP|S2]), |
599 | | pp_csp_bool_expr(BE2,S2,[')'|T]). |
600 | | pp_csp_bool_expr(BE,[OP,'('|S],T) :- binary_pred(BE,BE1,BE2,OP), !, |
601 | | pp_csp_value(BE1,S,[','|S2]), |
602 | | pp_csp_value(BE2,S2,[')'|T]). |
603 | | pp_csp_bool_expr(BE,S,T) :- pp_csp_value(BE,S,T). |
604 | | |
605 | | bynary_numeric_operation('+'(X,Y),X,Y,'+'). |
606 | | bynary_numeric_operation('-'(X,Y),X,Y,'-'). |
607 | | bynary_numeric_operation('*'(X,Y),X,Y,'*'). |
608 | | bynary_numeric_operation('/'(X,Y),X,Y,'/'). |
609 | | bynary_numeric_operation('%'(X,Y),X,Y,'%'). |
610 | | |
611 | | binary_pred('member'(X,Y),X,Y,member). |
612 | | binary_pred('<'(X,Y),X,Y,'<'). |
613 | | binary_pred('>'(X,Y),X,Y,'>'). |
614 | | binary_pred('>='(X,Y),X,Y,'>='). |
615 | | binary_pred('<='(X,Y),X,Y,'=<'). |
616 | | binary_pred('elem'(X,Y),X,Y,is_elem_list). |
617 | | binary_pred('=='(X,Y),X,Y,equal_element). |
618 | | binary_pred('!='(X,Y),X,Y,not_equal_element). |
619 | | |
620 | | |
621 | | binary_bool_op('<'(X,Y),X,Y,'<'). |
622 | | binary_bool_op('>'(X,Y),X,Y,'>'). |
623 | | binary_bool_op('>='(X,Y),X,Y,'>='). |
624 | | binary_bool_op('<='(X,Y),X,Y,'=<'). |
625 | | binary_bool_op('=='(X,Y),X,Y,'=='). |
626 | | binary_bool_op('!='(X,Y),X,Y,'!='). |
627 | | binary_bool_op(bool_and(X,Y),X,Y,'&&'). |
628 | | binary_bool_op(bool_or(X,Y),X,Y,'||'). |
629 | | |
630 | | binary_csp_op('|||'(X,Y,_Span),X,Y,'|||'). |
631 | | binary_csp_op('[]'(X,Y,_Span),X,Y,'[]'). |
632 | | binary_csp_op('|~|'(X,Y,_Span),X,Y,'|~|'). |
633 | | binary_csp_op(';'(X,Y,_Span),X,Y,';'). |
634 | | binary_csp_op('[>'(P,Q,_SrcSpan),P,Q,'[>'). |
635 | | binary_csp_op('/\\'(P,Q,_SrcSpan),P,Q,'/\\'). |
636 | | |
637 | | sharing_csp_op(esharing(CList,X,Y,_SrcSpan),X,CList,Y,' [|','|] '). |
638 | | sharing_csp_op(sharing(CList,X,Y,_SrcSpan),X,CList,Y,' [|','|] '). |
639 | | sharing_csp_op(lParallel(LinkList,X,Y,_Span),X,LinkList,Y,' [','] '). |
640 | | sharing_csp_op(elinkParallel(LinkList,X,Y,_Span),X,LinkList,Y,' [','] '). |
641 | | sharing_csp_op(exception(CList,X,Y,_SrcSpan),X,CList,Y,' [|','|> '). |
642 | | sharing_csp_op(eexception(CList,X,Y,_SrcSpan),X,CList,Y,' [|','|> '). |
643 | | |
644 | | asharing_csp_op(aParallel(CListX,X,CListY,Y,_SrcSpan),X,CListX,CListY,Y,' [',' || ','] '). |
645 | | asharing_csp_op(eaParallel(CListX,X,CListY,Y,_SrcSpan),X,CListX,CListY,Y,' [',' || ','] '). |
646 | | |
647 | | renaming_csp_op(procRenaming(RenameList,X,_SrcSpan),X,RenameList,'[[',']]'). |
648 | | renaming_csp_op(eprocRenaming(RenameList,X,_SrcSpan),X,RenameList,'[[',']]'). |
649 | | |
650 | | :- use_module(bmachine,[b_get_machine_operation_parameter_types/2, b_is_operation_name/1]). |
651 | | |
652 | | translate_events([],[]). |
653 | | translate_events([E|Erest],[Out|Orest]) :- |
654 | | translate_event(E,Out), |
655 | | translate_events(Erest,Orest). |
656 | | |
657 | | |
658 | | % a version of translate_event which has access to the target state id: |
659 | | % this allows to translate setup_constants, intialise by inserting target constants or values |
660 | | |
661 | | translate_event_with_target_id(Term,Dst,Limit,Str) :- |
662 | | translate_event_with_src_and_target_id(Term,unknown,Dst,Limit,Str). |
663 | | translate_event_with_src_and_target_id(Term,Src,Dst,Str) :- |
664 | | translate_event_with_src_and_target_id(Term,Src,Dst,5000,Str). |
665 | | |
666 | | translate_event_with_src_and_target_id(Term,Src,Dst,Limit,Str) :- |
667 | | get_preference(expand_avl_upto,CurLim), |
668 | | SetLim is Limit//2,% at least two symbols per element |
669 | | (CurLim<0 ; SetLim < CurLim),!, |
670 | | temporary_set_preference(expand_avl_upto,SetLim,CHNG), |
671 | | call_cleanup(translate_event_with_target_id2(Term,Src,Dst,Limit,Str), |
672 | | reset_temporary_preference(expand_avl_upto,CHNG)). |
673 | | translate_event_with_src_and_target_id(Term,Src,Dst,Limit,Str) :- |
674 | | translate_event_with_target_id2(Term,Src,Dst,Limit,Str). |
675 | | |
676 | | setup_cst_functor('$setup_constants',"SETUP_CONSTANTS"). |
677 | | setup_cst_functor('$partial_setup_constants',"PARTIAL_SETUP_CONSTANTS"). |
678 | | |
679 | | translate_event_with_target_id2(Term,_,Dst,Limit,Str) :- |
680 | | functor(Term,Functor,_), |
681 | | setup_cst_functor(Functor,UI_Name), |
682 | | get_preference(show_initialisation_arguments,true), |
683 | | state_space:visited_expression(Dst,concrete_constants(State)), |
684 | | get_non_det_constant(State,NonDetState), |
685 | | !, |
686 | | translate_b_state_to_comma_list_codes(UI_Name,NonDetState,Limit,Codes), |
687 | | atom_codes_with_limit(Str,Limit,Codes). |
688 | | translate_event_with_target_id2(Term,_,Dst,Limit,Str) :- |
689 | | functor(Term,'$initialise_machine',_), |
690 | | get_preference(show_initialisation_arguments,true), |
691 | | bmachine:b_get_operation_non_det_modifies('$initialise_machine',NDModVars), |
692 | | state_space:visited_expression(Dst,State), get_variables(State,VarsState), |
693 | | (NDModVars \= [] |
694 | | -> |
695 | | include(non_det_modified_var(NDModVars),VarsState,ModVarsState) % first show non-det variables |
696 | | % we could add a preference for whether to show the deterministicly assigned variables at all |
697 | | %exclude(non_det_modified_var(NDModVars),VarsState,ModVarsState2), |
698 | | %append(ModVarsState1,ModVarsState2,ModVarsState) |
699 | | ; ModVarsState = VarsState), |
700 | | !, |
701 | | translate_b_state_to_comma_list_codes("INITIALISATION",ModVarsState,Limit,Codes), |
702 | | atom_codes_with_limit(Str,Limit,Codes). |
703 | | translate_event_with_target_id2(Term,Src,Dst,Limit,Str) :- |
704 | | atomic(Term), % only applied to operations without parameters |
705 | | specfile:b_mode, |
706 | | get_non_det_modified_vars_in_target_id(Term,Dst,ModVarsState0), % only show non-det variables |
707 | | (Src \= unknown, |
708 | | state_space:visited_expression(Src,SrcState), get_variables(SrcState,PriorVarsState) |
709 | | -> exclude(var_not_really_modified(PriorVarsState),ModVarsState0,ModVarsState) |
710 | | % we could also optionally filter out vars which have the same value for all outgoing transitions of Src |
711 | | ; ModVarsState = ModVarsState0 |
712 | | ), |
713 | | !, |
714 | | atom_codes(Term,TermCodes), |
715 | | translate_b_state_to_comma_list_codes(TermCodes,ModVarsState,Limit,Codes), |
716 | | atom_codes_with_limit(Str,Limit,Codes). |
717 | | translate_event_with_target_id2(Term,_,_,Limit,Str) :- translate_event_with_limit(Term,Limit,Str). |
718 | | |
719 | | |
720 | | get_non_det_modified_vars_in_target_id(OpName,DstId,ModVarsState0) :- |
721 | | bmachine:b_get_operation_non_det_modifies(OpName,NDModVars), |
722 | | NDModVars \= [], % a variable is non-deterministically written |
723 | | state_space:visited_expression(DstId,State), % TO DO: unpack only NModVars |
724 | | get_variables(State,VarsState), |
725 | | include(non_det_modified_var(NDModVars),VarsState,ModVarsState0). |
726 | | |
727 | | :- use_module(library(ordsets)). |
728 | | non_det_modified_var(NDModVars,bind(Var,_)) :- ord_member(Var,NDModVars). |
729 | | |
730 | | var_not_really_modified(PriorState,bind(Var,Val)) :- |
731 | | (member(bind(Var,PVal),PriorState) -> PVal=Val). |
732 | | |
733 | | get_variables(const_and_vars(_,VarsState),S) :- !, S=VarsState. |
734 | | get_variables(S,S). |
735 | | |
736 | | :- dynamic non_det_constants/2. |
737 | | |
738 | | % compute which constants are non-deterministically assigned and which ones not |
739 | | % TODO: maybe move to state space and invalidate info in case execute operation by predicate used |
740 | | get_non_det_constant(Template,Result) :- non_det_constants(A,B),!, (A,B)=(Template,Result). |
741 | | get_non_det_constant(Template,Result) :- |
742 | | state_space:transition(root,_,DstID), |
743 | | state_space:visited_expression(DstID,concrete_constants(State)), %print(get_non_det_constant(DstID)),nl, |
744 | | !, |
745 | | findall(D,(state_space:transition(root,_,D),D \= DstID),OtherDst), |
746 | | compute_non_det_constants2(OtherDst,State), |
747 | | non_det_constants(Template,Result). |
748 | | get_non_det_constant(A,A). |
749 | | |
750 | | compute_non_det_constants2([],State) :- adapt_state(State,Template,Result), |
751 | | (Result = [] -> assertz(non_det_constants(A,A)) % in case all variables are deterministic: just show them |
752 | | ; assertz(non_det_constants(Template,Result))). |
753 | | compute_non_det_constants2([Dst|T],State) :- |
754 | | state_space:visited_expression(Dst,concrete_constants(State2)), |
755 | | lub_state(State,State2,NewState), |
756 | | compute_non_det_constants2(T,NewState). |
757 | | |
758 | | lub_state([],[],[]). |
759 | | lub_state([bind(V,H1)|T1],[bind(V,H2)|T2],[bind(V,H3)|T3]) :- |
760 | | (H1==H2 -> H3=H1 ; H3='$NONDET'), lub_state(T1,T2,T3). |
761 | | |
762 | | adapt_state([],[],[]). |
763 | | adapt_state([bind(ID,Val)|T],[bind(ID,X)|TX],[bind(ID,X)|TY]) :- Val='$NONDET',!, |
764 | | adapt_state(T,TX,TY). |
765 | | adapt_state([bind(ID,_)|T],[bind(ID,_)|TX],TY) :- % Value is deterministic: do not copy |
766 | | adapt_state(T,TX,TY). |
767 | | |
768 | | |
769 | | |
770 | | % ------------------------------------ |
771 | | |
772 | | translate_event_with_limit(Event,Limit,Out) :- |
773 | | translate_event2(Event,Atoms,[]),!, |
774 | | ajoin_with_limit(Atoms,Limit,Out). |
775 | | %,print(done),debug:print_debug_stats,nl.% , print(Out),nl. |
776 | | translate_event_with_limit(Event,_,Out) :- add_error(translate_event_with_limit,'Could not translate event: ', Event), |
777 | | Out = '???'. |
778 | | |
779 | | translate_event(Event,Out) :- %print(translate),print_debug_stats,nl, |
780 | | translate_event2(Event,Atoms,[]),!, |
781 | | ajoin(Atoms,Out). |
782 | | %,print(done),debug:print_debug_stats,nl.% , print(Out),nl. |
783 | | translate_event(Event,Out) :- |
784 | | add_error(translate_event,'Could not translate event: ', Event), |
785 | | Out = '???'. |
786 | | /* BEGIN CSP */ |
787 | | translate_event2(start_cspm(Process),['start_cspm('|S],T) :- process_algebra_mode,!,pp_csp_value(Process,S,[')'|T]). |
788 | | %% translate_event2(i(_Span),['i'|T],T) :- process_algebra_mode,!. /* CSP */ %% deprecated |
789 | | translate_event2(tick(_Span),['tick'|T],T) :- process_algebra_mode,!. /* CSP */ |
790 | | translate_event2(tau(hide(Action)),['tau(hide('|S],T) :- process_algebra_mode,nonvar(Action), !, |
791 | | translate_event2(Action,S,['))'|T]). /* CSP */ |
792 | | translate_event2(tau(link(Action1,Action2)),['tau(link('|S],T) :- /* CSP */ |
793 | | nonvar(Action1), nonvar(Action2), process_algebra_mode, !, |
794 | | translate_event2(Action1,S,['<->'|S1]), |
795 | | translate_event2(Action2,S1,['))'|T]). |
796 | | translate_event2(tau(Info),['tau(',Fun,')'|T],T) :- |
797 | | nonvar(Info), process_algebra_mode,!, /* CSP */ |
798 | | functor(Info,Fun,_). %(translate_event(Info,Fun) -> true ; functor(Info,Fun,_)), |
799 | | translate_event2(io(V,Ch,_Span),S,T) :- process_algebra_mode,!, /* CSP */ |
800 | | (specfile:csp_with_bz_mode -> |
801 | | S=['CSP:'|S1], |
802 | | translate_event2(io(V,Ch),S1,T) |
803 | | ; |
804 | | translate_event2(io(V,Ch),S,T) |
805 | | ). |
806 | | translate_event2(io(X,Channel),S,T) :- process_algebra_mode,!, /* CSP */ |
807 | | (X=[] -> translate_event2(Channel,S,T) |
808 | | ; (translate_event2(Channel,S,S1), |
809 | | translate_channel_values(X,S1,T)) |
810 | | ). |
811 | | /* END CSP */ |
812 | | translate_event2('$JUMP'(Name),[A|T],T) :- write_to_codes(Name,Codes), |
813 | | atom_codes_with_limit(A,Codes). |
814 | | translate_event2('-->'(Operation,ResultValues),S,T) :- nonvar(ResultValues), |
815 | | ResultValues=[_|_],!, |
816 | | translate_event2(Operation,S,['-->',ValuesStr|T]), |
817 | | translate_bvalues(ResultValues,ValuesStr). |
818 | | translate_event2(Op,S,T) :- |
819 | | nonvar(Op), Op =.. [OpName|Args], |
820 | | translate_b_operation_call(OpName,Args,S,T),!. |
821 | | translate_event2(Op,[A|T],T) :- |
822 | | %['<< ',A,' >>'|T],T) :- % the << >> pose problems when checking against FDR |
823 | | write_to_codes(Op,Codes), |
824 | | atom_codes_with_limit(A,Codes). |
825 | | |
826 | | % translate a B operation call to list of atoms in dcg style |
827 | | translate_b_operation_call(OpName,Args,[TOpName|S],T) :- |
828 | | translate_operation_name(OpName,TOpName), |
829 | | ( Args=[] -> S=T |
830 | | ; |
831 | | S=['(',ValuesStr,')'|T], |
832 | | ( get_preference(show_eventb_any_arguments,false), % otherwise we have additional ANY parameters ! |
833 | | \+ 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) |
834 | | specfile:b_mode, |
835 | | b_is_operation_name(OpName), |
836 | | b_get_machine_operation_parameter_types(OpName,ParTypes), |
837 | | ParTypes \= [] |
838 | | -> translate_bvalues_with_types(Args,ParTypes,ValuesStr) |
839 | | %; is_init(OpName) -> b_get_machine_operation_typed_parameters(OpName,TypedParas), |
840 | | ; translate_bvalues(Args,ValuesStr)) |
841 | | ). |
842 | | |
843 | | % ----------------- |
844 | | |
845 | | % translate call stacks as stored in wait flag info fields |
846 | | % (managed by push_wait_flag_call_stack_info) |
847 | | |
848 | | translate_call_stack(Stack,Msg) :- |
849 | | Opts = [detailed], |
850 | | split_calls(Stack,DStack), |
851 | | get_cs_avl_limit(ALimit), |
852 | | temporary_set_preference(expand_avl_upto,ALimit,CHNG), |
853 | | set_unicode_mode, |
854 | | call_cleanup(render_call_stack(DStack,1,Opts,A,[]), |
855 | | (unset_unicode_mode, |
856 | | reset_temporary_preference(expand_avl_upto,CHNG))), |
857 | | ajoin(['call stack: '|A],Msg). |
858 | | render_call_stack([],_,_) --> []. |
859 | | render_call_stack([H],Nr,Opts) --> !, |
860 | | render_nr(Nr,H,_,Opts), render_call(H,Opts). |
861 | | render_call_stack([H|T],Nr,Opts) --> |
862 | | render_nr(Nr,H,Nr1,Opts), |
863 | | render_call(H,Opts), |
864 | | render_seperator(Opts), |
865 | | render_call_stack(T,Nr1,Opts). |
866 | | |
867 | | % render nr of call in call stack |
868 | | render_nr(Pos,H,Pos1,Opts) --> {member(detailed,Opts)},!, ['\n '], render_pos_nr(Pos,H,Pos1). |
869 | | render_nr(Pos,_,Pos,_) --> []. |
870 | | |
871 | | render_pos_nr(Pos,definition_call(_,_),Pos) --> !, |
872 | | [' ']. % definition calls are virtual and can appear multiple times for different entries in the call stack |
873 | | % see e.g., public_examples/B/FeatureChecks/DEFINITIONS/DefCallStackDisplay2.mch |
874 | | render_pos_nr(Pos,_,Pos1) --> [Pos] , {Pos1 is Pos+1}, [': ']. |
875 | | |
876 | | render_seperator(Opts) --> {member(detailed,Opts)},!. % we put newlines in render_nr |
877 | | render_seperator(_Opts) --> |
878 | | {call_stack_arrow_atom_symbol(Symbol)}, [Symbol]. |
879 | | |
880 | | render_call(definition_call(Name,Pos),Opts) --> !, |
881 | | ['within DEFINITION call '],[Name], |
882 | | render_span(Pos,Opts). |
883 | | render_call(operation_call(Op,Paras,Pos),Opts) --> !, |
884 | | translate_b_operation_call(Op,Paras), % TODO: limit size? |
885 | | render_span(Pos,Opts). |
886 | | render_call(using_state(Name,State),_Opts) --> !, |
887 | | [Name], [' with state: '], |
888 | | {get_cs_limit(Limit),translate_bstate_limited(State,Limit,Str)}, |
889 | | [Str]. |
890 | | render_call(after_event(OpTerm),_Opts) --> !, |
891 | | ['after event: '], |
892 | | {get_cs_limit(Limit),translate_event_with_limit(OpTerm,Limit,Str)}, |
893 | | [Str]. |
894 | | render_call(function_call(Fun,Paras,Pos),Opts) --> !, |
895 | | render_function_call(Fun,Paras), |
896 | | render_span(Pos,Opts). |
897 | | render_call(b_operator_call(OP,Paras,Pos),Opts) --> !, |
898 | | render_operator_arg(b_operator(OP,Paras)), |
899 | | render_span(Pos,Opts). |
900 | | render_call(id_equality_evaluation(ID,Kind,Pos),Opts) --> !, |
901 | | ['equality for '],[Kind],[' '],[ID], |
902 | | render_span(Pos,Opts). |
903 | | render_call(b_operator_arg_evaluation(OP,PosNr,Args,Pos),Opts) --> !, |
904 | | ['arg '],[PosNr],[' of '], |
905 | | render_operator_arg(b_operator(OP,Args)), |
906 | | render_span(Pos,Opts). |
907 | | render_call(external_call(Name,Paras,Pos),Opts) --> !, |
908 | | ['external call '], [Name],['('], |
909 | | {get_cs_limit(Limit),translate_bvalues_with_limit(Paras,Limit,PS)},[PS], [')'], |
910 | | render_span(Pos,Opts). |
911 | | render_call(prob_command_context(Name,Pos),Opts) --> !, |
912 | | ['checking '], render_prob_command(Name), |
913 | | render_span(Pos,Opts). |
914 | | render_call(quantifier_call(comprehension_set,ParaNames,ParaValues,Pos),Opts) --> % special case for lambda |
915 | | {nth1(LPos,ParaNames,LambdaRes,RestParaNames), |
916 | | is_lambda_result_name(LambdaRes,_), |
917 | | nth1(LPos,ParaValues,LambdaVal,RestParaValues)},!, % we have found '_lambda_res_' amongst paras |
918 | | render_quantifier(lambda), ['('], |
919 | | render_paras(RestParaNames,RestParaValues), |
920 | | ['|'], render_para_val(LambdaVal), |
921 | | [')'], |
922 | | render_span(Pos,Opts). |
923 | | render_call(quantifier_call(Kind,ParaNames,ParaValues,Pos),Opts) --> !, |
924 | | render_quantifier(Kind), ['('], |
925 | | render_paras(ParaNames,ParaValues), [')'], |
926 | | render_span(Pos,Opts). |
927 | | render_call(top_level_call(SpanPred),Opts) --> |
928 | | render_call(SpanPred,Opts). |
929 | | render_call(b_expr_call(Context,Expr),Opts) --> !, |
930 | | [Context],[': '], |
931 | | render_b_expr(Expr), |
932 | | render_span(Expr,Opts). |
933 | | render_call(span_predicate(Pred,LS,S),Opts) --> % Pred can also be an expression like function/2 |
934 | | % infos could contain was(extended_expr(Op)); special case for: assertion_expression |
935 | | {Pred=b(_,_,Pos), |
936 | | b_compiler:b_compile(Pred,[],LS,S,CPred,no_wf_available) % inline actual parameters |
937 | | }, |
938 | | !, |
939 | | render_b_expr(CPred), |
940 | | render_function_name(Pred), % try show function name from uncompiled Expr |
941 | | render_span(Pos,Opts). |
942 | | render_call(Other,_) --> [Other]. |
943 | | |
944 | | %render_operator(OP) --> |
945 | | % {(unicode_translation(OP,Unicode) -> FOP=Unicode ; FOP=OP)}, [FOP]. |
946 | | |
947 | | % render b operator arguments/calls: |
948 | | render_operator_arg(Var) --> {var(Var)},!,['_VARIABLE_']. % should not happen |
949 | | render_operator_arg(b_operator(OP,[Arg1,Arg2])) --> |
950 | | {binary_infix_in_mode(OP,Symbol,_,_)},!, |
951 | | {(unicode_translation(OP,Unicode) -> FOP=Unicode ; FOP=Symbol)}, %TODO: add parentheses if necessary |
952 | | render_operator_arg(Arg1), |
953 | | [' '],[FOP], [' '], |
954 | | render_operator_arg(Arg2). |
955 | | render_operator_arg(b_operator(OP,Args)) --> !, |
956 | | {(unicode_translation(OP,Unicode) -> FOP=Unicode ; function_like(OP,FOP) -> true ; FOP=OP)}, |
957 | | [FOP], ['('], |
958 | | render_operator_args(Args), |
959 | | [')']. |
960 | | render_operator_arg(bind(Name,Value)) --> !, |
961 | | [Name], ['='], |
962 | | render_operator_arg(Value). |
963 | | render_operator_arg(identifier(ID)) --> !, [ID]. |
964 | | render_operator_arg(Val) --> render_para_val(Val). |
965 | | |
966 | | render_operator_args([]) --> !, []. |
967 | | render_operator_args([H]) --> !, render_operator_arg(H). |
968 | | render_operator_args([H|T]) --> !, render_operator_arg(H), [','], render_operator_args(T). |
969 | | render_operator_args(A) --> {add_internal_error('Not a list: ',A)}, ['???']. |
970 | | |
971 | | render_prob_command(check_pred_command(PredKind,Arg)) --> !, ['predicate '], render_pred_nr(Arg), ['of '],[PredKind]. |
972 | | render_prob_command(eval_expr_command(Kind,Arg)) --> !, ['expression '], render_pred_nr(Arg), ['of '],[Kind]. |
973 | | render_prob_command(trace_replay(OpName,FromId)) --> !, ['Trace replay predicate for '],[OpName], [' from '],[FromId]. |
974 | | render_prob_command(Cmd) --> [Cmd]. |
975 | | |
976 | | render_pred_nr(0) --> !. % 0 is special value to indicate we have no number/id within outer kind |
977 | | render_pred_nr(Nr) --> {number(Nr)},!,['# '],[Nr],[' ']. |
978 | | render_pred_nr('') --> !. |
979 | | render_pred_nr(AtomId) --> ['for '], [AtomId],[' ']. |
980 | | |
981 | | render_function_name(b(function(Fun,_),_,_)) --> {try_get_identifier(Fun,FID)},!, |
982 | | % TODO: other means of extracting name; maybe we should render anything that is not a value? |
983 | | ['\n (Function applied: '], [FID], [')']. |
984 | | render_function_name(b(_,_,Infos)) --> {member(was(extended_expr(OpID)),Infos)},!, |
985 | | ['\n (Theory operator applied: '], [OpID], [')']. |
986 | | render_function_name(_) --> []. |
987 | | |
988 | | try_get_identifier(Expr,Id) :- (get_texpr_id(Expr,Id) -> true ; get_was_identifier(Expr,Id)). |
989 | | |
990 | | render_span(Span,Opts) --> {member(detailed,Opts),translate_span(Span,Atom), Atom \= ''},!, |
991 | | ['\n '], [Atom], |
992 | | ({member(additional_descr,Opts),translate_additional_description(Span,Descr)} |
993 | | -> [' within ',Descr] |
994 | | ; []). |
995 | | render_span(_,_) --> []. |
996 | | |
997 | | render_function_call(Fun,Paras) --> |
998 | | {(atomic(Fun) -> FS=Fun ; translate_bexpr_for_call_stack(Fun,FS))}, % memoization will only register atomic name |
999 | | [FS],['('], render_para_val(Paras), [')']. |
1000 | | |
1001 | | render_b_expr(b(function(Fun,Paras),_,_)) --> !, % ensure we print both function and paras at least partially |
1002 | | {translate_bexpr_for_call_stack(Fun,FS)}, [FS],['('], |
1003 | | {translate_bexpr_for_call_stack(Paras,PS)},[PS], [')']. |
1004 | | render_b_expr(b(assertion_expression(Pred,Msg,b(value(_),string,_)),_,_)) --> !, |
1005 | | % Body is not source of error; probably better to use special call stack entry for assertion_expression |
1006 | | ['ASSERT '],[Msg],['\n '], |
1007 | | {translate_bexpr_for_call_stack(Pred,PS)}, [PS]. |
1008 | | render_b_expr(CPred) --> {translate_bexpr_for_call_stack(CPred,PS)}, [PS]. |
1009 | | |
1010 | | translate_bexpr_for_call_stack(Expr,TS) :- |
1011 | | get_cs_limit(Limit), |
1012 | | translate_bexpression_with_limit(Expr,Limit,TS). |
1013 | | |
1014 | | get_cs_limit(2000) :- !. |
1015 | | get_cs_limit(Limit) :- debug_mode(on),!, debug_level(Level), % 19 regular, 5 very verbose |
1016 | | Limit is 1000 - Level*20. |
1017 | | get_cs_limit(200) :- get_preference(provide_trace_information,true),!. |
1018 | | get_cs_limit(100). |
1019 | | |
1020 | | get_cs_avl_limit(40) :- debug_mode(on),!. |
1021 | | get_cs_avl_limit(6) :- get_preference(provide_trace_information,true),!. |
1022 | | get_cs_avl_limit(4). |
1023 | | |
1024 | | get_call_stack_span(operation_call(_,_,Pos),Pos). |
1025 | | %get_call_stack_span(after_event(_),unknown). |
1026 | | get_call_stack_span(function_call(_,_,Pos),Pos). |
1027 | | get_call_stack_span(id_equality_evaluation(_ID,_Kind,Pos),Pos). |
1028 | | get_call_stack_span(quantifier_call(_,_,_,Pos),Pos). |
1029 | | get_call_stack_span(definition_call(_,Pos),Pos). |
1030 | | get_call_stack_span(external_call(_,_,Pos),Pos). |
1031 | | get_call_stack_span(prob_command_context(_,Pos),Pos). |
1032 | | get_call_stack_span(top_level_call(Pos),Pos). |
1033 | | get_call_stack_span(b_operator_call(_,_,Pos),Pos). |
1034 | | get_call_stack_span(b_operator_arg_evaluation(_,_,_,Pos),Pos). |
1035 | | get_call_stack_span(b_expr_call(_,Expr),Expr). |
1036 | | get_call_stack_span(span_predicate(A,B,C),span_predicate(A,B,C)). |
1037 | | |
1038 | | nop_call(top_level_call(X)) :- \+ is_top_level_function_call(X). |
1039 | | % just there to insert virtual DEFINITION calls at top-level of call-stack |
1040 | | is_top_level_function_call(span_predicate(b(Expr,_,_),_,_)) :- |
1041 | | Expr = function(_,_), |
1042 | | get_preference(provide_trace_information,false). |
1043 | | % otherwise we push function_calls onto the stack; see opt_push_wait_flag_call_stack_info |
1044 | | |
1045 | | % expand the call stack by creating entries for the definition calls |
1046 | | split_calls([],[]). |
1047 | | split_calls([Call|T],NewCalls) :- nop_call(Call),!, %print(nop(Call)),nl, |
1048 | | split_calls(T,NewCalls). |
1049 | | split_calls([Call|T],NewCalls) :- |
1050 | | get_call_stack_span(Call,Span),!, |
1051 | | NewCalls = [Call|New2], |
1052 | | extract_def_calls(Span,New2,ST), |
1053 | | split_calls(T,ST). |
1054 | | split_calls([Call|T],[Call|ST]) :- |
1055 | | split_calls(T,ST). |
1056 | | |
1057 | | extract_def_calls(Span) --> |
1058 | | {extract_pos_context(Span,MainPos,Context,CtxtPos)}, |
1059 | | {Context = definition_call(Name)}, |
1060 | | !, |
1061 | | extract_def_calls(MainPos), |
1062 | | [definition_call(Name,CtxtPos)], |
1063 | | extract_def_calls(CtxtPos). % do we need this?? |
1064 | | extract_def_calls(_) --> []. |
1065 | | |
1066 | | % a shorter version of extract_additional_description only accepting definition_calls |
1067 | | translate_additional_description(Span,Desc) :- |
1068 | | extract_pos_context(Span,MainPos,Context,CtxtPos), |
1069 | | translate_span(CtxtPos,CtxtAtom), |
1070 | | extract_def_context_msg(Context,OuterCMsg), |
1071 | | (translate_additional_description(MainPos,InnerCMsg) |
1072 | | -> ajoin([InnerCMsg,' within ',OuterCMsg, ' ', CtxtAtom],Desc) |
1073 | | ; ajoin([OuterCMsg, ' ', CtxtAtom],Desc) |
1074 | | ). |
1075 | | |
1076 | | % try and get an immediate definition call context for a position |
1077 | | get_definition_context_from_span(Span,DefCtxtMsg) :- |
1078 | | extract_pos_context(Span,_MainPos,Context,_CtxtPos), |
1079 | | extract_def_context_msg(Context,DefCtxtMsg). |
1080 | | |
1081 | | extract_def_context_msg(definition_call(Name),Msg) :- !, % static Definition macro expansion call stack |
1082 | | ajoin(['DEFINITION call of ',Name],Msg). |
1083 | | |
1084 | | render_paras([],[]) --> !, []. |
1085 | | render_paras([],_Vals) --> ['...?...']. % should not happen |
1086 | | render_paras([Name],[Val]) --> !, render_para_name(Name), ['='], render_para_val(Val). |
1087 | | render_paras([Name|TN],[Val|TV]) --> !, |
1088 | | render_para_name(Name), ['='], render_para_val(Val), [','], |
1089 | | render_paras(TN,TV). |
1090 | | render_paras([N|Names],[]) --> !, render_para_name(N), render_paras(Names,[]). % value list can be empty |
1091 | | |
1092 | | render_para_val(Val) --> {get_cs_limit(Limit),translate_bvalue_with_limit(Val,Limit,VS)}, [VS]. |
1093 | | |
1094 | | % accept typed and atomic ids |
1095 | | render_para_name(b(identifier(ID),_,_)) --> !, {translated_identifier(ID,TID)},[TID]. |
1096 | | render_para_name(ID) --> {translated_identifier(ID,TID)},[TID]. |
1097 | | |
1098 | | render_quantifier(lambda) --> !, {unicode_translation(lambda,Symbol)},[Symbol]. % ['{|}']. |
1099 | | render_quantifier(comprehension_set) --> !, ['{|}']. |
1100 | | render_quantifier(comprehension_set(NegationContext)) --> !, |
1101 | | render_negation_context(NegationContext), [' {|}']. |
1102 | | render_quantifier(exists) --> !, {unicode_translation(exists,Symbol)},[Symbol]. |
1103 | | render_quantifier(let_quantifier) --> !, ['LET']. |
1104 | | render_quantifier(optimize) --> !, ['#optimize']. |
1105 | | render_quantifier(forall) --> !, {unicode_translation(forall,Symbol)},[Symbol]. |
1106 | | render_quantifier(not(Q)) --> !, {unicode_translation(negation,Symbol)}, % not(exists) |
1107 | | [Symbol, '('], render_quantifier(Q), [')']. |
1108 | | render_quantifier(Q) --> !, [Q]. |
1109 | | |
1110 | | render_negation_context(positive) --> !, ['one solution']. |
1111 | | render_negation_context(negative) --> !, ['no solution']. |
1112 | | render_negation_context(all_solutions) --> !,['all solutions']. |
1113 | | render_negation_context(C) --> [C]. |
1114 | | |
1115 | | call_stack_arrow_atom_symbol(' \x2192\ '). % see total function |
1116 | | %call_stack_arrow_atom_symbol('\x27FF\ '). % long rightwards squiggle arrow |
1117 | | |
1118 | | % ----------------- |
1119 | | |
1120 | | |
1121 | | is_init('$initialise_machine'). |
1122 | | is_init('$setup_constants'). |
1123 | | |
1124 | | translate_bvalues_with_types(Values,Types,Output) :- |
1125 | | %set_up_limit_reached(Codes,1000,LimitReached), |
1126 | | pp_value_l_with_types(Values,',',Types,_LimitReached,Codes,[]),!, |
1127 | | atom_codes_with_limit(Output,Codes). |
1128 | | translate_bvalues_with_types(Values,T,Output) :- |
1129 | | add_internal_error('Call failed: ',translate_bvalues_with_types(Values,T,Output)), |
1130 | | translate_bvalues(Values,Output). |
1131 | | |
1132 | | pp_value_l_with_types([],_Sep,[],_) --> !. |
1133 | | pp_value_l_with_types([Expr|Rest],Sep,[TE|TT],LimitReached) --> |
1134 | | ( {nonvar(Rest),Rest=[]} -> |
1135 | | pp_value_with_type(Expr,TE,LimitReached) |
1136 | | ; |
1137 | | pp_value_with_type(Expr,TE,LimitReached),ppatom(Sep), |
1138 | | pp_value_l_with_types(Rest,Sep,TT,LimitReached)). |
1139 | | |
1140 | | |
1141 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1142 | | |
1143 | | % pretty-print properties |
1144 | | translate_properties_with_limit([],[]). |
1145 | | translate_properties_with_limit([P|Prest],[Out|Orest]) :- |
1146 | | translate_property_with_limit(P,320,Out), % reduced limit as we now have evaluation view + possibility to inspect all of value |
1147 | | translate_properties_with_limit(Prest,Orest). |
1148 | | |
1149 | | translate_property_with_limit(Prop,Limit,Output) :- |
1150 | | (pp_property(Prop,Limit,Output) -> true ; (add_error(translate_property,'Could not translate property: ',Prop),Output='???')). |
1151 | | pp_property(Prop,Limit,Output) :- |
1152 | | pp_property_without_plugin(Prop,Limit,Output). |
1153 | | pp_property_without_plugin(=(Key,Value),_,A) :- |
1154 | | !,ajoin([Key,' = ',Value],A). |
1155 | | pp_property_without_plugin(':'(Key,Value),_,A) :- |
1156 | | !,ajoin([Key,' : ',Value],A). |
1157 | | pp_property_without_plugin(info(I),_,I) :- !. |
1158 | | pp_property_without_plugin(Prop,Limit,A) :- |
1159 | | write_to_codes(Prop,Codes), |
1160 | | atom_codes_with_limit(A,Limit,Codes). |
1161 | | |
1162 | | |
1163 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1164 | | :- use_module(tools_meta,[translate_term_into_atom_with_max_depth/3]). |
1165 | | |
1166 | | % pretty-print errors belonging to a certain state |
1167 | | translate_error_term(Term,S) :- translate_error_term(Term,unknown,S). |
1168 | | translate_error_term(Var,_,S) :- var(Var),!, |
1169 | | translate_term_into_atom_with_max_depth(Var,5,S). |
1170 | | translate_error_term('@fun'(X,F),Span,S) :- |
1171 | | translate_bvalue(X,TX), |
1172 | | (get_function_from_span(Span,Fun,LocState,State), |
1173 | | translate_bexpression_with_limit(Fun,200,TSF) |
1174 | | -> % we managed to extract the function from the span_predicate |
1175 | | (is_compiled_value(Fun) |
1176 | | -> (get_was_identifier(Fun,WasFunId) -> Rest = [', function: ',WasFunId | Rest1] |
1177 | | ; Rest = Rest1 |
1178 | | ), |
1179 | | TVal=TSF % use as value |
1180 | | ; Rest = [', function: ',TSF | Rest1], |
1181 | | % try and extract value from span_predicate (often F=[] after traversing avl) |
1182 | | (get_texpr_id(Fun,FID), |
1183 | | (member(bind(FID,FVal),LocState) ; member(bind(FID,FVal),State)) |
1184 | | -> translate_bvalue(FVal,TVal) |
1185 | | ; translate_bvalue(F,TVal) |
1186 | | ) |
1187 | | ) |
1188 | | ; Rest=[], translate_bvalue(F,TVal) |
1189 | | ),!, |
1190 | | % translate_term_into_atom_with_max_depth('@fun'(TX,TVal),5,S). |
1191 | | (get_error_span_for_value(F,NewSpanTxt) % triggers in test 953 |
1192 | | -> Rest1 = [' defined at ',NewSpanTxt] |
1193 | | ; Rest1 = [] |
1194 | | ), |
1195 | | ajoin(['Function argument: ',TX, ', function value: ',TVal | Rest],S). |
1196 | | translate_error_term('@rel'(Arg,Res1,Res2),_,S) :- |
1197 | | translate_bvalue(Arg,TA), translate_bvalue(Res1,R1), |
1198 | | translate_bvalue(Res2,R2),!, |
1199 | | ajoin(['Function argument: ',TA, ', two possible values: ',R1,', ',R2],S). |
1200 | | translate_error_term([operation(Name,Env)],_,S) :- |
1201 | | translate_any_state(Env,TEnv), !, |
1202 | | translate_term_into_atom_with_max_depth(operation(Name,TEnv),10,S). |
1203 | | translate_error_term(error(E1,E2),_,S) :- !, translate_prolog_error(E1,E2,S). |
1204 | | translate_error_term(b(B,T,I),_,S) :- |
1205 | | 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 |
1206 | | translate_error_term([H|T],_,S) :- nonvar(H), H=b(_,_,_), % typically a list of typed ids |
1207 | | E=b(sequence_extension([H|T]),any,[]), |
1208 | | translate_subst_or_bexpr_with_limit(E,1000,do_not_report_errors,S),!. |
1209 | | translate_error_term([H|T],_,S) :- nonvar(H), H=bind(_,_), % a store |
1210 | | translate_bstate_limited([H|T],1000,S),!. |
1211 | | translate_error_term(Term,_,S) :- |
1212 | | is_bvalue(Term), |
1213 | | translate_bvalue_with_limit(Term,1000,S),!. |
1214 | | translate_error_term(T,_,S) :- |
1215 | | (debug_mode(on) -> Depth = 20 ; Depth = 5), |
1216 | | translate_term_into_atom_with_max_depth(T,Depth,S). |
1217 | | |
1218 | | get_function_from_span(Var,Fun,_,_) :- var(Var), !, |
1219 | | add_internal_error('Variable span:',get_function_from_span(Var,Fun)),fail. |
1220 | | get_function_from_span(pos_context(Span,_,_),Fun,LS,S) :- get_function_from_span(Span,Fun,LS,S). |
1221 | | get_function_from_span(span_predicate(b(function(Function,_Arg),_T,_I),LocalState,State),Function,LocalState,State). |
1222 | | |
1223 | | is_compiled_value(b(value(_),_,_)). |
1224 | | |
1225 | | get_was_identifier(b(_,_,Info),Id) :- member(was_identifier(Id),Info). % added e.g. by b_compiler |
1226 | | |
1227 | | % TODO: complete this |
1228 | | % for recognising B values as error terms and automatically translating them |
1229 | | is_bvalue(V) :- var(V),!,fail. |
1230 | | is_bvalue([]). |
1231 | | is_bvalue(closure(_,_,_)). |
1232 | | is_bvalue(fd(_,_)). |
1233 | | is_bvalue(freetype(_)). |
1234 | | is_bvalue(freeval(_,_,_)). |
1235 | | is_bvalue(avl_set(_)). |
1236 | | is_bvalue(int(_)). |
1237 | | is_bvalue(global_set(_)). |
1238 | | is_bvalue(pred_true). |
1239 | | is_bvalue(pred_false). |
1240 | | is_bvalue(string(_)). |
1241 | | is_bvalue(term(_)). % typically term(floating(_)) |
1242 | | is_bvalue(rec(Fields)) :- nonvar(Fields), Fields=[F1|_], nonvar(F1), |
1243 | | F1=field(_,V1), is_bvalue(V1). |
1244 | | is_bvalue((A,B)) :- |
1245 | | (nonvar(A) -> is_bvalue(A) ; true), |
1246 | | (nonvar(B) -> is_bvalue(B) ; true). |
1247 | | |
1248 | | % try and get error location for span: |
1249 | | get_error_span_for_value(Var,_) :- var(Var),!,fail. |
1250 | | get_error_span_for_value(closure(_,_,Body),Span) :- translate_span_with_filename(Body,Span), Span \= ''. |
1251 | | |
1252 | | |
1253 | | % translate something that was caught with catch/3 |
1254 | | translate_prolog_exception(user_interrupt_signal,R) :- !, R='User-Interrupt (CTRL-C)'. |
1255 | | translate_prolog_exception(enumeration_warning(_,_,_,_,_),R) :- !, R='Enumeration Warning'. |
1256 | | translate_prolog_exception(error(E1,E2),S) :- !, translate_prolog_error(E1,E2,S). |
1257 | | translate_prolog_exception(E1,S) :- translate_term_into_atom_with_max_depth(E1,8,S). |
1258 | | |
1259 | | % translate a Prolog error(E1,E2) exception |
1260 | | translate_prolog_error(existence_error(procedure,Pred),_,S) :- !, |
1261 | | translate_term_into_atom_with_max_depth('Unknown Prolog predicate:'(Pred),8,S). |
1262 | | translate_prolog_error(existence_error(source_sink,File),_,S) :- !, |
1263 | | translate_term_into_atom_with_max_depth('File does not exist:'(File),8,S). |
1264 | | translate_prolog_error(permission_error(Action,source_sink,File),_,S) :- !, % Action = open, ... |
1265 | | ajoin(['Permission denied to ',Action,' the file: ',File],S). |
1266 | | translate_prolog_error(permission_error(Action,past_end_of_stream,File),_,S) :- !, % Action = open, ... |
1267 | | ajoin(['Permission denied to ',Action,' past end of file: ',File],S). |
1268 | | translate_prolog_error(system_error,system_error('SPIO_E_NET_CONNRESET'),S) :- !, |
1269 | | S = 'System error: connection to process lost (SPIO_E_NET_CONNRESET)'. |
1270 | | translate_prolog_error(system_error,system_error('SPIO_E_ENCODING_UNMAPPABLE'),S) :- !, |
1271 | | S = 'System error: illegal character or encoding encountered (SPIO_E_ENCODING_UNMAPPABLE)'. |
1272 | | translate_prolog_error(system_error,system_error('SPIO_E_NET_HOST_NOT_FOUND'),S) :- !, |
1273 | | S = 'System error: could not find host (SPIO_E_NET_HOST_NOT_FOUND)'. |
1274 | | translate_prolog_error(system_error,system_error('SPIO_E_CHARSET_NOT_FOUND'),S) :- !, |
1275 | | S = 'System error: could not find character set encoding'. |
1276 | | translate_prolog_error(system_error,system_error('SPIO_E_OS_ERROR'),S) :- !, |
1277 | | S = 'System error due to some OS/system call (SPIO_E_OS_ERROR)'. |
1278 | | translate_prolog_error(system_error,system_error('SPIO_E_END_OF_FILE'),S) :- !, |
1279 | | S = 'System error: end of file (SPIO_E_END_OF_FILE)'. |
1280 | | translate_prolog_error(system_error,system_error('SPIO_E_TOO_MANY_OPEN_FILES'),S) :- !, |
1281 | | S = 'System error: too many open files (SPIO_E_TOO_MANY_OPEN_FILES)'. |
1282 | | translate_prolog_error(system_error,system_error(dlopen(Msg)),S) :- !, |
1283 | | translate_term_into_atom_with_max_depth(Msg,4,MS), |
1284 | | 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). |
1285 | | translate_prolog_error(system_error,system_error(Err),S) :- !, |
1286 | | % or Err is an atom dlopen( mach-o file, but is an incompatible architecture ...) |
1287 | | % E.g., SPIO_E_NOT_SUPPORTED when doing open('/usr',r,S) |
1288 | | translate_term_into_atom_with_max_depth('System error:'(Err),8,S). |
1289 | | translate_prolog_error(existence_error(procedure,Module:Pred/Arity),_,S) :- !, |
1290 | | ajoin(['Prolog predicate does not exist: ',Module,':', Pred, '/',Arity],S). |
1291 | | translate_prolog_error(instantiation_error,instantiation_error(Call,_ArgNo),S) :- !, |
1292 | | translate_term_into_atom_with_max_depth('Prolog instantiation error:'(Call),8,S). |
1293 | | translate_prolog_error(uninstantiation_error(_),uninstantiation_error(Call,_ArgNo,_Culprit),S) :- !, |
1294 | | translate_term_into_atom_with_max_depth('Prolog uninstantiation error:'(Call),8,S). |
1295 | | translate_prolog_error(evaluation_error(zero_divisor),evaluation_error(Call,_,_,_),S) :- !, |
1296 | | translate_term_into_atom_with_max_depth('Division by zero error:'(Call),8,S). |
1297 | | translate_prolog_error(evaluation_error(float_overflow),evaluation_error(Call,_,_,_),S) :- !, |
1298 | | translate_term_into_atom_with_max_depth('Float overflow:'(Call),8,S). |
1299 | | translate_prolog_error(representation_error(Err),representation_error(Call,_,_),S) :- |
1300 | | memberchk(Err, ['CLPFD integer overflow','max_clpfd_integer','min_clpfd_integer']),!, |
1301 | | translate_term_into_atom_with_max_depth('Prolog CLP(FD) overflow:'(Call),8,S). |
1302 | | translate_prolog_error(syntax_error(Err),_,S) :- !, |
1303 | | translate_term_into_atom_with_max_depth('Prolog syntax error:'(Err),8,S). |
1304 | | translate_prolog_error(_,resource_error(open(File,Mode,_),Kind),S) :- !, % Kind e.g. file_handle |
1305 | | ajoin(['Resource error (',Kind, |
1306 | | '), could not open file ',File,' in mode ',Mode],S). |
1307 | | :- if(predicate_property(message_to_string(_, _), _)). |
1308 | | translate_prolog_error(E1,E2,S) :- |
1309 | | % SWI-Prolog way to translate an arbitrary message term (such as an exception) to a string, |
1310 | | % the same way that the built-in message handling system would print it. |
1311 | | message_to_string(error(E1,E2), String), |
1312 | | !, |
1313 | | atom_string(S, String). |
1314 | | :- endif. |
1315 | | translate_prolog_error(E1,_,S) :- translate_term_into_atom_with_max_depth(E1,8,S). |
1316 | | % we also have permission_error, context_error, domain_error |
1317 | | |
1318 | | translate_state_errors([],[]). |
1319 | | translate_state_errors([E|ERest],[Out|ORest]) :- |
1320 | | ( E = eventerror(Event,EError,_) -> |
1321 | | translate_event_error(EError,Msg), |
1322 | | ajoin([Event,': ',Msg],Out) |
1323 | | ; translate_state_error(E,Out) -> true |
1324 | | ; functor(E,Out,_) ), |
1325 | | translate_state_errors(ERest,ORest). |
1326 | | |
1327 | | translate_error_context(E,TE) :- translate_error_context2(E,Codes,[]), |
1328 | | atom_codes_with_limit(TE,Codes). |
1329 | | translate_error_context2(span_context(Span,Context)) --> !, |
1330 | | translate_error_context2(Context), |
1331 | | translate_span(Span,only_subsidiary). |
1332 | | translate_error_context2([H]) --> !,translate_error_context2(H). |
1333 | | translate_error_context2(checking_invariant) --> !, |
1334 | | {get_specification_description_codes(invariant,A)}, A. %"INVARIANT". |
1335 | | translate_error_context2(checking_assertions) --> !, |
1336 | | {get_specification_description_codes(assertions,A)}, A. %"ASSERTIONS". |
1337 | | translate_error_context2(checking_negation_of_invariant(_State)) --> !, |
1338 | | "not(INVARIANT)". |
1339 | | translate_error_context2(operation(OpName,_State)) --> !, |
1340 | | {translate_operation_name(OpName,TOp)}, |
1341 | | ppterm(TOp). |
1342 | | translate_error_context2(checking_context(Check,Name)) --> !, |
1343 | | ppterm(Check),ppterm(Name). |
1344 | | translate_error_context2(loading_context(_Name)) --> !. |
1345 | | translate_error_context2(visb_error_context(Class,SvgId,OpNameOrAttr,Span)) --> !, |
1346 | | "VisB ", ppterm(Class), " for SVG ID ", |
1347 | | ppterm(SvgId), " and attribute/event ", |
1348 | | {translate_operation_name(OpNameOrAttr,TOp)}, |
1349 | | ppterm(TOp), |
1350 | | translate_span(Span,only_subsidiary). |
1351 | | translate_error_context2(X) --> "???:", ppterm(X). |
1352 | | |
1353 | | print_span(Span) :- translate_span(Span,Atom), !, print(Atom). |
1354 | | print_span(S) :- print(span(S)). |
1355 | | |
1356 | | print_span_nl(Span) :- translate_span(Span,Atom), !,(Atom='' -> true ; print(Atom)),nl. |
1357 | | print_span_nl(S) :- print(span(S)),nl. |
1358 | | |
1359 | | |
1360 | | translate_span(Span,Atom) :- translate_span(Span,only_subsidiary,Codes,[]), |
1361 | | atom_codes_with_limit(Atom,Codes). |
1362 | | translate_span_with_filename(Span,Atom) :- |
1363 | | translate_span(Span,always_print_filename,Codes,[]), |
1364 | | atom_codes_with_limit(Atom,Codes). |
1365 | | |
1366 | | translate_span(Span,_) --> {var(Span)},!, {add_internal_error('Variable span:',translate_span(Span,_))}, "_". |
1367 | | translate_span(Span,PrintFileNames) --> {extract_line_col(Span,Srow,Scol,_Erow,_Ecol)},!, |
1368 | | "(Line:",ppterm(Srow)," Col:",ppterm(Scol), |
1369 | | %"-",ppterm(Erow),":",ppterm(Ecol), |
1370 | | translate_span_file_opt(Span,PrintFileNames), |
1371 | | % TO DO: print short version of extract_additional_description ? |
1372 | | ")". |
1373 | | translate_span(Span,_PrintFileNames) --> {extract_symbolic_label(Span,Label)},!, "(label @",ppterm(Label),")". |
1374 | | translate_span(Span,PrintFileNames) --> |
1375 | | % for Event-B, e.g., line-col fails but we can get a section/file name |
1376 | | "(File:",translate_span_file(Span,PrintFileNames),!,")". |
1377 | | translate_span(_,_PrintFileNames) --> "". |
1378 | | |
1379 | | translate_span_file(Span,always_print_filename) --> |
1380 | | {extract_tail_file_name(Span,Filename)},!, |
1381 | | %{bmachine:b_get_main_filenumber(MainFN), Nr \= MainFN},!, |
1382 | | " File:", ppterm(Filename). |
1383 | | translate_span_file(Span,_) --> |
1384 | | {extract_subsidiary_tail_file_name(Span,Filename)}, |
1385 | | %{bmachine:b_get_main_filenumber(MainFN), Nr \= MainFN},!, |
1386 | | !, |
1387 | | " File:", ppterm(Filename). |
1388 | | translate_span_file_opt(Span,Print) --> translate_span_file(Span,Print),!. |
1389 | | translate_span_file_opt(_,_) --> "". |
1390 | | |
1391 | | |
1392 | | explain_span_file(Span) --> |
1393 | | {extract_subsidiary_tail_file_name(Span,Filename)}, |
1394 | | %{bmachine:b_get_main_filenumber(MainFN), Nr \= MainFN},!, |
1395 | | "\n### File: ", ppterm(Filename). |
1396 | | explain_span_file(_) --> "". |
1397 | | |
1398 | | explain_span(V) --> {var(V)},!, "Internal error: Illegal variable span". |
1399 | | explain_span(span_predicate(Pred,LS,S)) --> !, explain_span2(span_predicate(Pred,LS,S)), |
1400 | | explain_local_state(LS). %, explain_global_state(S). |
1401 | | explain_span(Span) --> explain_span2(Span). |
1402 | | explain_span2(Span) --> {extract_line_col(Span,Srow,Scol,Erow,Ecol)},!, |
1403 | | "\n### Line: ", ppterm(Srow), ", Column: ", ppterm(Scol), |
1404 | | " until Line: ", ppterm(Erow), ", Column: ", ppterm(Ecol), |
1405 | | explain_span_file(Span), |
1406 | | explain_span_context(Span). |
1407 | | explain_span2(Span) --> {extract_symbolic_label_pos(Span,Msg)},!, |
1408 | | "\n @label: ", ppterm(Msg), |
1409 | | explain_span_context(Span). |
1410 | | explain_span2(Span) --> explain_span_context(Span). |
1411 | | |
1412 | | explain_span_context(Span) --> {extract_additional_description(Span,Msg),!}, |
1413 | | "\n### within ", ppterm(Msg). % context of span, such as definition call hierarchy |
1414 | | explain_span_context(_) --> "". |
1415 | | |
1416 | | explain_local_state([]) --> !, "". |
1417 | | explain_local_state(LS) --> "\n Local State: ", pp_b_state(LS,1000). |
1418 | | %explain_global_state([]) --> !, "". |
1419 | | %explain_global_state(LS) --> "\n Global State: ", pp_b_state(LS). |
1420 | | |
1421 | | translate_event_error(Error,Out) :- |
1422 | | ( translate_event_error2(Error,Out) -> true |
1423 | | ; |
1424 | | functor(Error,F,_), |
1425 | | ajoin(['** Unable to translate event error: ',F,' **'],Out)). |
1426 | | translate_event_error2(no_witness_found(Type,Var,_Predicate),Out) :- |
1427 | | def_get_texpr_id(Var,Id), |
1428 | | ajoin(['no witness was found for ',Type,' ',Id],Out). |
1429 | | translate_event_error2(simulation_error(_Events),Out) :- |
1430 | | Out = 'no matching abstract event was found'. |
1431 | | translate_event_error2(action_not_executable(_Action,WDErr),Out) :- |
1432 | | (WDErr=wd_error_possible -> Out = 'action was not executable (maybe with WD error)' |
1433 | | ; Out = 'action was not executable'). |
1434 | | translate_event_error2(invalid_modification(Var,_Pre,_Post),Out) :- |
1435 | | def_get_texpr_id(Var,Id), |
1436 | | ajoin(['modification of variable ', Id, ' not allowed'],Out). |
1437 | | translate_event_error2(variant_negative(_CType,_Variant,_Value),Out) :- |
1438 | | Out = 'enabled for negative variant'. |
1439 | | translate_event_error2(invalid_variant(anticipated,_Expr,_Pre,_Post),Out) :- |
1440 | | Out = 'variant increased'. |
1441 | | translate_event_error2(invalid_variant(convergent,_Expr,_Pre,_Post),Out) :- |
1442 | | Out = 'variant not decreased'. |
1443 | | translate_event_error2(invalid_theorem_in_guard(_Theorem),Out) :- |
1444 | | Out = 'theorem in guard evaluates to false'. |
1445 | | translate_event_error2(event_wd_error(_TExpr,Source),Out) :- |
1446 | | ajoin(['WD error for ',Source],Out). |
1447 | | translate_event_error2(event_other_error(Msg),Out) :- Out=Msg. |
1448 | | |
1449 | | translate_state_error(abort_error(_TYPE,Msg,ErrTerm,ErrorContext),Out) :- !, |
1450 | | translate_error_term(ErrTerm,ES), |
1451 | | translate_error_context(ErrorContext,EC), |
1452 | | ajoin([EC,': ',Msg,': ',ES],Out). |
1453 | | translate_state_error(clpfd_overflow_error(Context),Out) :- !, % 'CLPFD_integer_overflow' |
1454 | | ajoin(['CLPFD integer overflow while ', Context],Out). |
1455 | | translate_state_error(max_state_errors_reached(Nr),Out) :- !, |
1456 | | ajoin(['Max. number of state errors reached: ', Nr],Out). |
1457 | | translate_state_error(Unknown,Out) :- |
1458 | | add_error(translate_state_error,'Unknown state error: ',Unknown), |
1459 | | Out = '*** Unknown State Error ***'. |
1460 | | |
1461 | | |
1462 | | get_span_from_context([H],Span) :- !, get_span_from_context(H,Span). |
1463 | | get_span_from_context(span_context(Span,_),Res) :- !, Res=Span. |
1464 | | get_span_from_context(_,unknown). |
1465 | | |
1466 | | explain_error_context1([H]) --> !,explain_error_context1(H). |
1467 | | explain_error_context1(span_context(Span,Context)) --> !, |
1468 | | explain_span(Span),"\n", |
1469 | | explain_error_context2(Context). |
1470 | | explain_error_context1(Ctxt) --> explain_error_context2(Ctxt). |
1471 | | |
1472 | | explain_error_context2([H]) --> !,explain_error_context2(H). |
1473 | | explain_error_context2(span_context(Span,Context)) --> !, |
1474 | | explain_span(Span),"\n", |
1475 | | explain_error_context2(Context). |
1476 | | explain_error_context2(checking_invariant) --> !, |
1477 | | {get_specification_description_codes(invariant,I)}, I, ":\n ", %"INVARIANT:\n ", |
1478 | | pp_current_state. % assumes explain is called in the right state ! ; otherwise we need to store the state id |
1479 | | explain_error_context2(checking_assertions) --> !, |
1480 | | {get_specification_description_codes(assertions,A)}, A, ":\n ", %"ASSERTIONS:\n ", |
1481 | | pp_current_state. % assumes explain is called in the right state ! ; otherwise we need to store the state id |
1482 | | explain_error_context2(checking_negation_of_invariant(State)) --> !, |
1483 | | "not(INVARIANT):\n State: ", |
1484 | | pp_b_state(State,1000). |
1485 | | explain_error_context2(operation('$setup_constants',StateID)) --> !, |
1486 | | {get_specification_description_codes(properties,P)}, P, ":\n State: ", |
1487 | | pp_context_state(StateID). |
1488 | | explain_error_context2(operation(OpName,StateID)) --> !, |
1489 | | {get_specification_description_codes(operation,OP)}, OP, ": ", %"EVENT/OPERATION: ", |
1490 | | {translate_operation_name(OpName,TOp)}, |
1491 | | ppterm(TOp), "\n ", |
1492 | | pp_context_state(StateID). |
1493 | | explain_error_context2(checking_context(Check,Name)) --> !, |
1494 | | ppterm(Check),ppterm(Name), "\n ". |
1495 | | explain_error_context2(loading_context(Name)) --> !, |
1496 | | "Loading: ",ppterm(Name), "\n ". |
1497 | | explain_error_context2(visb_error_context(Class,SvgId,OpNameOrAttr,Span)) --> !, |
1498 | | translate_error_context2(visb_error_context(Class,SvgId,OpNameOrAttr,Span)). |
1499 | | explain_error_context2(X) --> "UNKNOWN ERROR CONTEXT:\n ", ppterm(X). |
1500 | | |
1501 | | :- use_module(specfile,[get_specification_description/2]). |
1502 | | get_specification_description_codes(Tag,Codes) :- get_specification_description(Tag,Atom), atom_codes(Atom,Codes). |
1503 | | |
1504 | | explain_state_error(Error,Span,Out) :- |
1505 | | explain_state_error2(Error,Span,Out,[]),!. |
1506 | | explain_state_error(_Error,unknown,"Sorry, the detailed output failed.\n"). |
1507 | | |
1508 | | explain_abort_error_type(well_definedness_error) --> !, "An expression was not well-defined.\n". |
1509 | | explain_abort_error_type(card_overflow_error) --> !, "The cardinality of a finite set was too large to be represented.\n". |
1510 | | explain_abort_error_type(while_variant_error) --> !, "A while-loop VARIANT error occurred.\n". |
1511 | | explain_abort_error_type(while_invariant_violation) --> !, "A while-loop INVARIANT error occurred.\n". |
1512 | | explain_abort_error_type(precondition_error) --> !, "A precondition (PRE) error occurred.\n". |
1513 | | explain_abort_error_type(assert_error) --> !, "An ASSERT error occurred.\n". |
1514 | | explain_abort_error_type(Type) --> "Error occurred: ", ppterm(Type), "\n". |
1515 | | |
1516 | | explain_state_error2(abort_error(TYPE,Msg,ErrTerm,ErrContext),Span) --> |
1517 | | explain_abort_error_type(TYPE), |
1518 | | "Reason: ", ppterm(Msg), "\n", |
1519 | | {get_span_from_context(ErrContext,Span)}, |
1520 | | ({ErrTerm=''} -> "" |
1521 | | ; "Details: ", {translate_error_term(ErrTerm,Span,ErrS)},ppterm(ErrS), "\n" |
1522 | | ), |
1523 | | "Context: ", explain_error_context1(ErrContext). |
1524 | | explain_state_error2(max_state_errors_reached(Nr),unknown) --> |
1525 | | "Too many error occurred for this state.\n", |
1526 | | "Not all errors are shown.\n", |
1527 | | "Number of errors is at least: ", ppterm(Nr). |
1528 | | explain_state_error2(eventerror(_Event,Error,Trace),Span) --> % TO DO: also extract loc info ? |
1529 | | {translate_event_error(Error,Msg)}, |
1530 | | ppatom(Msg), |
1531 | | "\nA detailed trace containing the error:\n", |
1532 | | "--------------------------------------\n", |
1533 | | explain_event_trace(Trace,Span). |
1534 | | explain_state_error2(clpfd_overflow_error(Context),unknown) --> % CLPFD_integer_overflow |
1535 | | "An overflow occurred inside the CLP(FD) library.\n", |
1536 | | "Context: ", ppterm(Context), "\n", |
1537 | | "You may try and set the CLPFD preference to FALSE.\n". |
1538 | | |
1539 | | % try and get span from state error: |
1540 | | get_state_error_span(abort_error(_,_,_,Context),Span) :- get_span_context_span(Context,Span). |
1541 | | |
1542 | | get_span_context_span(span_context(Span,_),Span). |
1543 | | get_span_context_span([H],Span) :- get_span_context_span(H,Span). |
1544 | | |
1545 | | |
1546 | | |
1547 | | show_parameter_values([],[]) --> !. |
1548 | | show_parameter_values([P|Prest],[V|Vrest]) --> |
1549 | | show_parameter_value(P,V), |
1550 | | show_parameter_values(Prest,Vrest). |
1551 | | show_parameter_value(P,V) --> |
1552 | | " ",pp_expr(P,_,_LR)," = ",pp_value(V),"\n". |
1553 | | |
1554 | | % translate an Event-B error trace (error occurred during multi-level animation) |
1555 | | % into a textual description (Codes) and a span_predicate term which can be visualised |
1556 | | explain_event_trace(Trace,Codes,Span) :- |
1557 | | explain_event_trace(Trace,Span,Codes,[]). |
1558 | | |
1559 | | explain_event_trace(Trace,span_predicate(SpanPred,[],[])) --> |
1560 | | % evaluating the span predicate will require access to current state, which needs to be added later |
1561 | | explain_event_trace4(Trace,'?','?',SpanPred). |
1562 | | |
1563 | | explain_event_trace4([],_,_,b(truth,pred,[])) --> !. |
1564 | | explain_event_trace4([event(Name,Section)|Trest],_,_,SpanPred) --> !, |
1565 | | "\n", |
1566 | | "Event ",ppterm(Name)," in model ",ppterm(Section), |
1567 | | ":\n", |
1568 | | % pass new current event name and section for processing tail: |
1569 | | explain_event_trace4(Trest,Name,Section,SpanPred). |
1570 | | explain_event_trace4([Step|Trest],Name,Section,SpanPred) --> |
1571 | | "\n", |
1572 | | ( explain_event_step4(Step,StepPred) -> "" |
1573 | | ; {functor(Step,F,_)} -> |
1574 | | " (no rule to explain event step ",ppatom(F),")\n"), |
1575 | | explain_event_trace4(Trest,Name,Section,RestSpanPred), |
1576 | | {combine_span_pred(StepPred,RestSpanPred,Name,Section,SpanPred)}. |
1577 | | |
1578 | | % create a span predicate from the event error trace to display relevant values and predicates |
1579 | | combine_span_pred(unknown,S,_,_,Res) :- !, Res=S. |
1580 | | combine_span_pred(new_scope(Kind,Paras,Vals,P1),P2,Name,Section,Res) :- !, |
1581 | | maplist(create_tvalue,Paras,Vals,TVals), |
1582 | | add_span_label(Kind,Name,Section,P1,P1L), |
1583 | | conjunct_predicates([P1L,P2],Body), |
1584 | | (Paras=[] -> Res=Body ; Res = b(let_predicate(Paras,TVals,Body),pred,[])). % translate:print_bexpr(Res),nl. |
1585 | | % we could also do: add_texpr_description |
1586 | | combine_span_pred(P1,P2,_,_,Res) :- |
1587 | | conjunct_predicates([P1,P2],Res). |
1588 | | |
1589 | | add_span_label(Kind,Name,Section,Pred,NewPred) :- |
1590 | | (Kind=[Label] -> true % already has position info |
1591 | | ; create_label(Kind,Name,Section,Label)), |
1592 | | add_labels_to_texpr(Pred,[Label],NewPred). |
1593 | | create_label(Kind,Name,Section,Label) :- ajoin([Kind,' in ',Section,':',Name],Label). |
1594 | | |
1595 | | create_tvalue(b(_,Type,_),Value,b(value(Value),Type,[])). |
1596 | | |
1597 | | explain_event_step4(true_guard(Parameters,Values,Guard),new_scope('guard true',Parameters,Values,Guard)) --> !, |
1598 | | ( {Parameters==[]} -> "" |
1599 | | ; " for the parameters:\n", |
1600 | | show_parameter_values(Parameters,Values)), |
1601 | | " the guard is true:", |
1602 | | explain_predicate(Guard,4),"\n". |
1603 | | explain_event_step4(eval_witness(Type,Id,Value,Predicate),new_scope('witness',[Id],[Value],Predicate)) --> |
1604 | | witness_intro(Id,Predicate,Type), |
1605 | | " found witness:\n", |
1606 | | " ", pp_expr(Id,_,_LR), " = ", pp_value(Value), "\n". |
1607 | | explain_event_step4(simulation_error(Errors),SpanPred) --> |
1608 | | " no guard of a refined event was satisfiable:\n", |
1609 | | explain_simulation_errors(Errors,Guards), |
1610 | | {disjunct_predicates(Guards,SpanPred)}. |
1611 | | explain_event_step4(invalid_theorem_in_guard(Theorem),new_scope('false theorem',[],[],Theorem)) --> |
1612 | | " the following theorem evaluates to false:", |
1613 | | explain_predicate(Theorem,4),"\n". |
1614 | | explain_event_step4(invalid_modification(Var,Pre,Post), |
1615 | | new_scope('invalid modification',[Var],[Post],b(falsity,pred,[]))) --> |
1616 | | " the variable ", pp_expr(Var,_,_LR), " has been modified.\n", |
1617 | | " The event is not allowed to modify the variable because its abstract event does not modify it.\n", |
1618 | | " Old value: ", pp_value(Pre), "\n", |
1619 | | " New value: ", pp_value(Post), "\n". |
1620 | | explain_event_step4(action_not_executable(TAction,WDErr),new_scope('action not executable',[],[],Equalities)) --> |
1621 | | {exctract_span_pred_from_subst(TAction,Equalities)}, |
1622 | | explain_action_not_executable(TAction,WDErr). |
1623 | | explain_event_step4(Step,unknown) --> |
1624 | | explain_event_step(Step). |
1625 | | % TODO: add span predicates for the errors below: |
1626 | | |
1627 | | extract_equality(Infos,TID,NewExpr,b(equal(TID,NewExpr),pred,Infos)). % TODO: introduce TID' primed? |
1628 | | exctract_span_pred_from_subst(b(assign(TIDs,Exprs),subst,Infos),SpanPred) :- |
1629 | | maplist(extract_equality(Infos),TIDs,Exprs,List), |
1630 | | conjunct_predicates(List,SpanPred). |
1631 | | % todo: becomes_such, ... |
1632 | | |
1633 | | explain_event_step(variant_checked_pre(CType,Variant,Value)) --> |
1634 | | " ",ppatom(CType)," event: checking if the variant is non-negative:\n", |
1635 | | " variant: ",pp_expr(Variant,_,_LR),"\n", |
1636 | | " its value: ",pp_value(Value),"\n". |
1637 | | explain_event_step(variant_negative(CType,Variant,Value)) --> |
1638 | | explain_event_step(variant_checked_pre(CType,Variant,Value)), |
1639 | | " ERROR: variant is negative\n". |
1640 | | explain_event_step(variant_checked_post(CType,Variant,EntryValue,ExitValue)) --> |
1641 | | " ",ppatom(CType)," event: checking if the variant is ", |
1642 | | ( {CType==convergent} -> "decreased:\n" ; "not increased:\n"), |
1643 | | " variant: ", pp_expr(Variant,_,_LR), "\n", |
1644 | | " its value before: ", pp_value(EntryValue),"\n", |
1645 | | " its value after: ", pp_value(ExitValue),"\n". |
1646 | | explain_event_step(invalid_variant(CType,Variant,EntryValue,ExitValue)) --> |
1647 | | explain_event_step(variant_checked_post(CType,Variant,EntryValue,ExitValue)), |
1648 | | " ERROR: variant has ", |
1649 | | ({CType==convergent} -> "not been decreased\n"; "has been increased\n"). |
1650 | | explain_event_step(no_witness_found(Type,Id,Predicate)) --> |
1651 | | witness_intro(Id,Predicate,Type), |
1652 | | " ERROR: no solution for witness predicate found!\n". |
1653 | | explain_event_step(action(Lhs,_Rhs,Values)) --> |
1654 | | " executing an action:\n", |
1655 | | show_assignments(Lhs,Values). |
1656 | | explain_event_step(action_set(Lhs,_Rhs,ValueSet,Values)) --> |
1657 | | " executing an action:\n ", |
1658 | | pp_expr_l(Lhs,_LR)," :: ",pp_value(ValueSet),"\n choosing\n", |
1659 | | show_assignments(Lhs,Values). |
1660 | | explain_event_step(action_pred(Ids,Pred,Values)) --> |
1661 | | " executing an action:\n ", |
1662 | | pp_expr_l(Ids,_LR1)," :| ",pp_expr(Pred,_,_LR2),"\n choosing\n", |
1663 | | show_assignments(Ids,Values). |
1664 | | explain_event_step(error(Error,_Id)) --> |
1665 | | % the error marker serves to link to a stored state-error by its ID |
1666 | | explain_event_step(Error). |
1667 | | explain_event_step(event_wd_error(TExpr,Source)) --> |
1668 | | " Well-Definedness ERROR for ", ppatom(Source), "\n", |
1669 | | " ", pp_expr(TExpr,_,_LR), "\n". |
1670 | | explain_event_step(event_other_error(Msg)) --> ppatom(Msg). |
1671 | | |
1672 | | explain_action_not_executable(TAction,no_wd_error) --> {is_assignment_to(TAction,IDs)},!, |
1673 | | " ERROR: the following assignment to ", ppatoms(IDs),"was not executable\n", |
1674 | | " (probably in conflict with another assignment, check SIM or EQL PO):", % or WD error |
1675 | | translate_subst_with_indention_and_label(TAction,4). |
1676 | | explain_action_not_executable(TAction,wd_error_possible) --> !, |
1677 | | " ERROR: the following action was not executable\n", |
1678 | | " (possibly due to a WD error):", |
1679 | | translate_subst_with_indention_and_label(TAction,4). |
1680 | | explain_action_not_executable(TAction,_WDErr) --> |
1681 | | " ERROR: the following action was not executable:", |
1682 | | translate_subst_with_indention_and_label(TAction,4). |
1683 | | |
1684 | | is_assignment_to(b(assign(LHS,_),_,_),IDs) :- get_texpr_ids(LHS,IDs). |
1685 | | |
1686 | | witness_intro(Id,Predicate,Type) --> |
1687 | | " evaluating witness for abstract ", ppatom(Type), " ", pp_expr(Id,_,_LR1), "\n", |
1688 | | " witness predicate: ", pp_expr(Predicate,_,_LR2), "\n". |
1689 | | |
1690 | | show_assignments([],[]) --> !. |
1691 | | show_assignments([Lhs|Lrest],[Val|Vrest]) --> |
1692 | | " ",pp_expr(Lhs,_,_LimitReached), " := ", pp_value(Val), "\n", |
1693 | | show_assignments(Lrest,Vrest). |
1694 | | |
1695 | | /* unused at the moment: |
1696 | | explain_state([]) --> !. |
1697 | | explain_state([bind(Varname,Value)|Rest]) --> !, |
1698 | | " ",ppterm(Varname)," = ",pp_value(Value),"\n", |
1699 | | explain_state(Rest). |
1700 | | explain_guards([]) --> "". |
1701 | | explain_guards([Event|Rest]) --> |
1702 | | {get_texpr_expr(Event,rlevent(Name,_Section,_Status,_Params,Guard,_Theorems,_Act,_VWit,_PWit,_Unmod,_Evt))}, |
1703 | | "\n",ppatom(Name),":", |
1704 | | explain_predicate(Guard), |
1705 | | explain_guards(Rest). |
1706 | | explain_predicate(Guard,I,O) :- |
1707 | | explain_predicate(Guard,2,I,O). |
1708 | | */ |
1709 | | explain_predicate(Guard,Indention,I,O) :- |
1710 | | pred_over_lines(0,'@grd',Guard,(Indention,I),(_,O)). |
1711 | | |
1712 | | explain_simulation_errors([],[]) --> !. |
1713 | | explain_simulation_errors([Error|Rest],[Grd|Gs]) --> |
1714 | | explain_simulation_error(Error,Grd), |
1715 | | explain_simulation_errors(Rest,Gs). |
1716 | | explain_simulation_error(event(Name,Section,Guard),SpanPred) --> |
1717 | | {add_span_label('guard false',Name,Section,Guard,SpanPred)}, |
1718 | | " guard for event ", ppatom(Name), |
1719 | | " in ", ppatom(Section), ":", |
1720 | | explain_predicate(Guard,6),"\n". |
1721 | | |
1722 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1723 | | % pretty-print a state |
1724 | | |
1725 | | |
1726 | | print_state(State) :- b_state(State), !,print_bstate(State). |
1727 | | print_state(csp_and_b_root) :- csp_with_bz_mode, !, |
1728 | | print('(MAIN || B)'). |
1729 | | print_state(csp_and_b(CSPState,BState)) :- csp_with_bz_mode, !, |
1730 | | print_bstate(BState), translate_cspm_state(CSPState,Text), print(Text). |
1731 | | print_state(CSPState) :- csp_mode,!,translate_cspm_state(CSPState,Text), print(Text). |
1732 | | print_state(State) :- animation_mode(xtl),!,print(State). |
1733 | | print_state(State) :- print('*** Unknown state: '),print(State). |
1734 | | |
1735 | | b_state(root). |
1736 | | b_state(concrete_constants(_)). |
1737 | | b_state(const_and_vars(_,_)). |
1738 | | b_state(expanded_const_and_vars(_,_,_,_)). |
1739 | | b_state(expanded_vars(_,_)). |
1740 | | b_state([bind(_,_)|_]). |
1741 | | b_state([]). |
1742 | | |
1743 | | print_bstate(State) :- print_bstate_limited(State,1000,-1). |
1744 | | print_bstate_limited(State,VarLimit,OverallLimit) :- |
1745 | | translate_bstate_limited(State,VarLimit,OverallLimit,Output), print(' '),print(Output). |
1746 | | |
1747 | | translate_any_state(State,Output) :- |
1748 | | get_pp_state_limit(Limit), |
1749 | | pp_any_state(State,Limit,Codes,[]), |
1750 | | atom_codes_with_limit(Output,Codes). |
1751 | | translate_bstate(State,Output) :- |
1752 | | get_pp_state_limit(Limit), |
1753 | | pp_b_state(State,Limit,Codes,[]), |
1754 | | atom_codes_with_limit(Output,Codes). |
1755 | | |
1756 | | get_pp_state_limit(Limit) :- |
1757 | | (get_preference(expand_avl_upto,-1) -> Limit = -1 ; Limit = 1000). |
1758 | | |
1759 | | % a version which tries to generate smaller strings |
1760 | | translate_bstate_limited(State,Output) :- |
1761 | | temporary_set_preference(expand_avl_upto,2,CHNG), |
1762 | | call_cleanup(translate_bstate_limited(State,200,Output), |
1763 | | reset_temporary_preference(expand_avl_upto,CHNG)). |
1764 | | |
1765 | | translate_bstate_limited(State,Limit,Output) :- |
1766 | | translate_bstate_limited(State,Limit,Limit,Output). |
1767 | | translate_bstate_limited(State,VarLimit,Limit,Output) :- |
1768 | | pp_b_state(State,VarLimit,Codes,[]), % this limit VarLimit applies to every variable |
1769 | | atom_codes_with_limit(Output,Limit,Codes). % Limit applies to the full translation |
1770 | | |
1771 | | pp_b_state(X,Limit) --> try_pp_b_state(X,Limit),!. |
1772 | | pp_b_state(X,_Limit) --> {add_error(pp_b_state,'Could not translate state: ',X)}. |
1773 | | |
1774 | | % Limit is pretty-print limit for every value printed |
1775 | | try_pp_b_state(VAR,_) --> {var(VAR)},!, "_?VAR?_", {add_error(pp_b_state,'Variable state: ',VAR)}. |
1776 | | try_pp_b_state(root,_) --> !, "root". |
1777 | | try_pp_b_state(concrete_constants(Constants),Limit) --> !,"Constants: ", |
1778 | | pp_b_state(Constants,Limit). |
1779 | | try_pp_b_state(const_and_vars(ID,Vars),Limit) --> !, |
1780 | | "Constants:",ppterm(ID),", Vars:", |
1781 | | {set_translation_constants(ID)}, /* extract constants which stand for deferred set elements */ |
1782 | | pp_b_state(Vars,Limit), |
1783 | | {clear_translation_constants}. |
1784 | | try_pp_b_state(expanded_const_and_vars(ID,Vars,_,_Infos),Limit) --> !, "EXPANDED ", |
1785 | | try_pp_b_state(const_and_vars(ID,Vars),Limit). |
1786 | | try_pp_b_state(expanded_vars(Vars,_Infos),Limit) --> !, "EXPANDED ", |
1787 | | try_pp_b_state(Vars,Limit). |
1788 | | try_pp_b_state([],_) --> !, "/* empty state */". |
1789 | | try_pp_b_state([bind(Varname,Value)|Rest],Limit) --> !, |
1790 | | "( ",ppterm(Varname),"=", |
1791 | | dcg_set_up_limit_reached(Limit,LimitReached), |
1792 | | pp_value(Value,LimitReached), |
1793 | | ({Rest = []} -> []; " ",and_symbol,"\n "), |
1794 | | pp_b_state_list(Rest,Limit). |
1795 | | |
1796 | | |
1797 | | pp_b_state_list([],_) --> !, " )". |
1798 | | pp_b_state_list([bind(Varname,Value)|Rest],Limit) --> !, |
1799 | | ppterm(Varname),"=", |
1800 | | dcg_set_up_limit_reached(Limit,LimitReached), |
1801 | | pp_value(Value,LimitReached), |
1802 | | ({Rest = []} -> [] ; " ",and_symbol,"\n "), |
1803 | | pp_b_state_list(Rest,Limit). |
1804 | | pp_b_state_list(X,_) --> {add_error(pp_b_state_list,'Could not translate: ',X)}. |
1805 | | |
1806 | | % a version of pp which generates no newline; can be used for printing SETUP_CONSTANTS, INITIALISATION |
1807 | | pp_b_state_comma_list([],_,_) --> !, ")". |
1808 | | pp_b_state_comma_list(_,Cur,Limit) --> {Cur >= Limit}, !, "...". |
1809 | | pp_b_state_comma_list([bind(Varname,Value)|Rest],Cur,Limit) --> !, |
1810 | | %{print(c(Varname,Cur,Limit)),nl}, |
1811 | | start_size(Ref), |
1812 | | ppterm(Varname),"=", |
1813 | | pp_value(Value), |
1814 | | ({Rest = []} |
1815 | | -> ")" |
1816 | | ; ",", |
1817 | | end_size(Ref,Size), % compute size increase wrt Ref point |
1818 | | {Cur1 is Cur+Size}, |
1819 | | pp_b_state_comma_list(Rest,Cur1,Limit) |
1820 | | ). |
1821 | | pp_b_state_comma_list(X,_,_) --> {add_error(pp_b_state_comma_list,'Could not translate: ',X)}. |
1822 | | |
1823 | | start_size(X,X,X). |
1824 | | end_size(RefVar,Len,X,X) :- % compute how many chars the dcg has added wrt start_size |
1825 | | len(RefVar,X,Len). |
1826 | | len(Var,X,Len) :- (var(Var) ; Var==X),!, Len=0. |
1827 | | len([],_,0). |
1828 | | len([_|T],X,Len) :- len(T,X,L1), Len is L1+1. |
1829 | | |
1830 | | % can be used e.g. for setup_constants, initialise |
1831 | | translate_b_state_to_comma_list_codes(FUNCTORCODES,State,Limit,ResCodes) :- |
1832 | | pp_b_state_comma_list(State,0,Limit,Codes,[]), |
1833 | | append("(",Codes,C0), |
1834 | | append(FUNCTORCODES,C0,ResCodes). |
1835 | | |
1836 | | % translate to a single line without newlines |
1837 | | translate_b_state_to_comma_list(State,Limit,ResAtom) :- |
1838 | | pp_b_state_comma_list(State,0,Limit,Codes,[]), |
1839 | | append("(",Codes,C0), |
1840 | | atom_codes(ResAtom,C0). |
1841 | | |
1842 | | % ---------------- |
1843 | | |
1844 | | % printing and translating error contexts |
1845 | | print_context(State) :- translate_context(State,Output), print(Output). |
1846 | | |
1847 | | translate_context(Context,Output) :- |
1848 | | pp_b_context(Context,Codes,[]), |
1849 | | atom_codes_with_limit(Output,250,Codes). |
1850 | | |
1851 | | pp_b_context([]) --> !. |
1852 | | pp_b_context([C|Rest]) --> !, |
1853 | | pp_b_context(C), |
1854 | | pp_b_context(Rest). |
1855 | | pp_b_context(translate_context) --> !, " ERROR CONTEXT: translate_context". % error occurred within translate_context |
1856 | | pp_b_context(span_context(Span,Context)) --> !, |
1857 | | pp_b_context(Context), " ", translate_span(Span,only_subsidiary). |
1858 | | pp_b_context(operation(Name,StateID)) --> !, |
1859 | | " ERROR CONTEXT: ", |
1860 | | {get_specification_description_codes(operation,OP)}, OP, ":", % "OPERATION:" |
1861 | | ({var(Name)} -> ppterm('ALL') ; {translate_operation_name(Name,TName)},ppterm(TName)), |
1862 | | ",",pp_context_state(StateID). |
1863 | | pp_b_context(checking_invariant) --> !, |
1864 | | " ERROR CONTEXT: INVARIANT CHECKING,", pp_cur_context_state. |
1865 | | pp_b_context(checking_negation_of_invariant(State)) --> !, |
1866 | | " ERROR CONTEXT: NEGATION_OF_INVARIANT CHECKING, State:", pp_b_state(State,1000). |
1867 | | pp_b_context(checking_assertions) --> !, |
1868 | | " ERROR CONTEXT: ASSERTION CHECKING,", pp_cur_context_state. |
1869 | | pp_b_context(checking_context(Check,Name)) --> !, |
1870 | | " ERROR CONTEXT: ", ppterm(Check),ppterm(Name). |
1871 | | pp_b_context(loading_context(_FName)) --> !. |
1872 | | pp_b_context(unit_test_context(Module,TotNr,Line,Call)) --> !, |
1873 | | " ERROR CONTEXT: Unit Test ", ppterm(TotNr), " in module ", ppterm(Module), |
1874 | | " at line ", ppterm(Line), " calling ", pp_functor(Call). |
1875 | | pp_b_context(visb_error_context(Class,ID,OpNameOrAttr,Span)) --> !, |
1876 | | " ERROR CONTEXT: VisB ", ppterm(Class), " with ID ", ppterm(ID), |
1877 | | ({OpNameOrAttr='all_attributes'} -> "" |
1878 | | ; " and attribute/event ", ppterm(OpNameOrAttr) |
1879 | | ), |
1880 | | " ", translate_span(Span,only_subsidiary). |
1881 | | pp_b_context(C) --> ppterm(C),pp_cur_context_state. |
1882 | | |
1883 | | pp_functor(V) --> {var(V)},!, ppterm(V). |
1884 | | pp_functor(T) --> {functor(T,F,N)}, ppterm(F),"/",ppterm(N). |
1885 | | |
1886 | | pp_cur_context_state --> {state_space:get_current_context_state(ID)}, !,pp_context_state(ID). |
1887 | | pp_cur_context_state --> ", unknown context state.". |
1888 | | |
1889 | | % assumes we are in the right state: |
1890 | | pp_current_state --> {state_space:current_expression(ID,_)}, !,pp_context_state(ID). |
1891 | | pp_current_state --> ", unknown current context state.". |
1892 | | |
1893 | | % TO DO: limit length/size of generated error description |
1894 | | pp_context_state(ID) --> {state_space:visited_expression(ID,State)},!, % we have a state ID |
1895 | | " State ID:", ppterm(ID), |
1896 | | pp_context_state2(State). |
1897 | | pp_context_state(State) --> pp_context_state3(State). |
1898 | | |
1899 | | pp_context_state2(_) --> {debug:debug_mode(off)},!. |
1900 | | pp_context_state2(State) --> ",", pp_context_state3(State). |
1901 | | |
1902 | | pp_context_state3(State) --> " State: ",pp_any_state_with_limit(State,10). |
1903 | | |
1904 | | pp_any_state_with_limit(State,Limit) --> |
1905 | | { get_preference(expand_avl_upto,CurLim), |
1906 | | (CurLim<0 ; Limit < CurLim), |
1907 | | !, |
1908 | | temporary_set_preference(expand_avl_upto,Limit,CHNG), |
1909 | | VarLimit is Limit*10 |
1910 | | }, |
1911 | | pp_any_state(State,VarLimit), |
1912 | | {reset_temporary_preference(expand_avl_upto,CHNG)}. |
1913 | | pp_any_state_with_limit(State,_Limit) --> |
1914 | | {get_preference(expand_avl_upto,CurLim), VarLimit is CurLim*10}, |
1915 | | pp_any_state(State,VarLimit). |
1916 | | |
1917 | | pp_any_state(X,VarLimit) --> try_pp_b_state(X,VarLimit),!. |
1918 | | pp_any_state(csp_and_b(P,B),VarLimit) --> "CSP: ",{pp_csp_process(P,Atoms,[])},!,atoms_to_codelist(Atoms), |
1919 | | " || B: ", try_pp_b_state(B,VarLimit). |
1920 | | pp_any_state(X,_) --> {animation_mode(xtl)}, !, "XTL: ",ppterm(X). % CSP state |
1921 | | pp_any_state(P,_) --> "CSP: ",{pp_csp_process(P,Atoms,[])},!,atoms_to_codelist(Atoms). |
1922 | | pp_any_state(X,_) --> "Other formalism: ",ppterm(X). % CSP state |
1923 | | |
1924 | | atoms_to_codelist([]) --> []. |
1925 | | atoms_to_codelist([Atom|T]) --> ppterm(Atom), atoms_to_codelist(T). |
1926 | | |
1927 | | % ---------------- |
1928 | | |
1929 | | :- dynamic deferred_set_constant/3. |
1930 | | |
1931 | | set_translation_context(const_and_vars(ConstID,_)) :- !, |
1932 | | %% print_message(setting_translation_constants(ConstID)), |
1933 | | set_translation_constants(ConstID). |
1934 | | set_translation_context(expanded_const_and_vars(ConstID,_,_,_)) :- !, |
1935 | | set_translation_constants(ConstID). |
1936 | | set_translation_context(_). |
1937 | | |
1938 | | set_translation_constants(_) :- clear_translation_constants, |
1939 | | get_preference(dot_print_use_constants,false),!. |
1940 | | set_translation_constants(ConstID) :- var(ConstID),!, |
1941 | | add_error(set_translation_constants,'Variable used as ConstID: ',ConstID). |
1942 | | set_translation_constants(ConstID) :- |
1943 | | state_space:visited_expression(ConstID,concrete_constants(ConstantsStore)),!, |
1944 | | %% print_message(setting_constants(ConstID)),%% |
1945 | | (treat_constants(ConstantsStore) -> true ; print_message(fail)). |
1946 | | set_translation_constants(ConstID) :- |
1947 | | add_error(set_translation_constants,'Unknown ConstID: ',ConstID). |
1948 | | |
1949 | | clear_translation_constants :- %print_message(clearing),%% |
1950 | | retractall(deferred_set_constant(_,_,_)). |
1951 | | |
1952 | | treat_constants([]). |
1953 | | treat_constants([bind(CstName,Val)|T]) :- |
1954 | | ((Val=fd(X,GSet),b_global_deferred_set(GSet)) |
1955 | | -> (deferred_set_constant(GSet,X,_) |
1956 | | -> true /* duplicate def of value */ |
1957 | | ; assertz(deferred_set_constant(GSet,X,CstName)) |
1958 | | ) |
1959 | | ; true |
1960 | | ), |
1961 | | treat_constants(T). |
1962 | | |
1963 | | |
1964 | | |
1965 | | translate_bvalue_with_tlatype(Value,Type,Output) :- |
1966 | | ( pp_tla_value(Type,Value,Codes,[]) -> |
1967 | | atom_codes_with_limit(Output,Codes) |
1968 | | ; add_error(translate_bvalue,'Could not translate TLA value: ',Value), |
1969 | | Output='???'). |
1970 | | |
1971 | | pp_tla_value(function(_Type1,_Type2),[]) --> !, |
1972 | | ppcodes("<<>>"). |
1973 | | pp_tla_value(function(integer,T2),avl_set(Set)) --> |
1974 | | {convert_avlset_into_sequence(Set,Seq)}, !, |
1975 | | pp_tla_with_sep("<< "," >>",",",T2,Seq). |
1976 | | pp_tla_value(function(T1,T2),Set) --> |
1977 | | {is_printable_set(Set,Values)},!, |
1978 | | pp_tla_with_sep("(",")"," @@ ",function_value(T1,T2),Values). |
1979 | | pp_tla_value(function_value(T1,T2),(L,R)) --> |
1980 | | !,pp_tla_value(T1,L),":>",pp_tla_value(T2,R). |
1981 | | pp_tla_value(set(Type),Set) --> |
1982 | | {is_printable_set(Set,Values)},!, |
1983 | | pp_tla_with_sep("{","}",",",Type,Values). |
1984 | | pp_tla_value(tuple(Types),Value) --> |
1985 | | {pairs_to_list(Types,Value,Values,[]),!}, |
1986 | | pp_tla_with_sep("<< "," >>",",",Types,Values). |
1987 | | pp_tla_value(record(Fields),rec(FieldValues)) --> |
1988 | | % TODO: Check if we can safely assume that Fields and FieldValues have the |
1989 | | % same order |
1990 | | !, {sort_tla_fields(Fields,FieldValues,RFields,RFieldValues)}, |
1991 | | pp_tla_with_sep("[","]",", ",RFields,RFieldValues). |
1992 | | pp_tla_value(field(Name,Type),field(_,Value)) --> |
1993 | | !, ppatom_opt_scramble(Name)," |-> ",pp_tla_value(Type,Value). |
1994 | | pp_tla_value(_Type,Value) --> |
1995 | | % fallback: use B's pretty printer |
1996 | | pp_value(Value). |
1997 | | |
1998 | | is_printable_set(avl_set(A),List) :- avl_domain(A,List). |
1999 | | is_printable_set([],[]). |
2000 | | is_printable_set([H|T],[H|T]). |
2001 | | |
2002 | | pairs_to_list([_],Value) --> !,[Value]. |
2003 | | pairs_to_list([_|Rest],(L,R)) --> |
2004 | | pairs_to_list(Rest,L),[R]. |
2005 | | |
2006 | | |
2007 | | sort_tla_fields([],_,[],[]). |
2008 | | sort_tla_fields([Field|RFields],ValueFields,RFieldTypes,ResultValueFields) :- |
2009 | | ( Field=field(Name,Type) -> true |
2010 | | ; Field= opt(Name,Type) -> true), |
2011 | | ( selectchk(field(Name,Value),ValueFields,RestValueFields), |
2012 | | field_value_present(Field,Value,Result) -> |
2013 | | % Found the field in the record value |
2014 | | RFieldTypes = [field(Name,Type) |RestFields], |
2015 | | ResultValueFields = [field(Name,Result)|RestValues], |
2016 | | sort_tla_fields(RFields,RestValueFields,RestFields,RestValues) |
2017 | | ; |
2018 | | % didn't found the field in the value -> igore |
2019 | | sort_tla_fields(RFields,ValueFields,RFieldTypes,ResultValueFields) |
2020 | | ). |
2021 | | field_value_present(field(_,_),RecValue,RecValue). % Obligatory fields are always present |
2022 | | field_value_present(opt(_,_),OptValue,Value) :- |
2023 | | % Optional fields are present if the field is of the form TRUE |-> Value. |
2024 | | ( is_printable_set(OptValue,Values) -> Values=[(_TRUE,Value)] |
2025 | | ; |
2026 | | add_error(translate,'exptected set for TLA optional record field'), |
2027 | | fail |
2028 | | ). |
2029 | | |
2030 | | pp_tla_with_sep(Start,End,Sep,Type,Values) --> |
2031 | | ppcodes(Start),pp_tla_with_sep_aux(Values,End,Sep,Type). |
2032 | | pp_tla_with_sep_aux([],End,_Sep,_Type) --> |
2033 | | ppcodes(End). |
2034 | | pp_tla_with_sep_aux([Value|Rest],End,Sep,Type) --> |
2035 | | % If a single type is given, we interpret it as the type |
2036 | | % for each element of the list, if it is a list, we interpret |
2037 | | % it one different type for every value in the list. |
2038 | | { (Type=[CurrentType|RestTypes] -> true ; CurrentType = Type, RestTypes=Type) }, |
2039 | | pp_tla_value(CurrentType,Value), |
2040 | | ( {Rest=[_|_]} -> ppcodes(Sep); {true} ), |
2041 | | pp_tla_with_sep_aux(Rest,End,Sep,RestTypes). |
2042 | | |
2043 | | |
2044 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2045 | | % pretty-print a value |
2046 | | |
2047 | | translate_bvalue_for_dot(string(S),Translation) :- !, |
2048 | | % normal quotes confuse dot |
2049 | | %ajoin(['''''',S,''''''],Translation). |
2050 | | string_escape(S,ES), |
2051 | | ajoin(['\\"',ES,'\\"'],Translation). |
2052 | | translate_bvalue_for_dot(Val,ETranslation) :- |
2053 | | translate_bvalue(Val,Translation), |
2054 | | string_escape(Translation,ETranslation). |
2055 | | |
2056 | | translate_bvalue_to_codes(V,Output) :- |
2057 | | ( pp_value(V,_LimitReached,Codes,[]) -> |
2058 | | Output=Codes |
2059 | | ; add_error(translate_bvalue_to_codes,'Could not translate bvalue: ',V), |
2060 | | Output="???"). |
2061 | | translate_bvalue_to_codes_with_limit(V,Limit,Output) :- |
2062 | | set_up_limit_reached(Codes,Limit,LimitReached), % TODO: also limit expand_avl_upto |
2063 | | ( pp_value(V,LimitReached,Codes,[]) -> |
2064 | | Output=Codes |
2065 | | ; add_error(translate_bvalue_to_codes,'Could not translate bvalue: ',V), |
2066 | | Output="???"). |
2067 | | |
2068 | | translate_bvalue(V,Output) :- |
2069 | | %set_up_limit_reached(Codes,1000000,LimitReached), % we could set a very high-limit, like max_atom_length |
2070 | | ( pp_value(V,_LimitReached,Codes,[]) -> |
2071 | | atom_codes_with_limit(Output,Codes) % just catches representation error |
2072 | | ; add_error(translate_bvalue,'Could not translate bvalue: ',V), |
2073 | | Output='???'). |
2074 | | :- use_module(preferences). |
2075 | | translate_bvalue_with_limit(V,Limit,Output) :- |
2076 | | get_preference(expand_avl_upto,Max), |
2077 | | ((Max>Limit % no sense in printing larger AVL trees |
2078 | | ; Max = -1) % or setting limit to -1 for full value |
2079 | | -> temporary_set_preference(expand_avl_upto,Limit,CHNG) |
2080 | | ; CHNG=false), |
2081 | | call_cleanup(translate_bvalue_with_limit_aux(V,Limit,Output), |
2082 | | reset_temporary_preference(expand_avl_upto,CHNG)). |
2083 | | translate_bvalue_with_limit_aux(V,Limit,OutputAtom) :- |
2084 | | set_up_limit_reached(Codes,Limit,LimitReached), |
2085 | | ( pp_value(V,LimitReached,Codes,[]) -> |
2086 | | atom_codes_with_limit(OutputAtom,Limit,Codes) |
2087 | | % ,length(Codes,Len), (Len>Limit -> format('pp(~w) codes:~w, limit:~w, String=~s~n~n',[LimitReached,Len,Limit,Codes]) ; true) |
2088 | | ; add_error(translate_bvalue_with_limit,'Could not translate bvalue: ',V), |
2089 | | OutputAtom='???'). |
2090 | | |
2091 | | translate_bvalues(Values,Output) :- |
2092 | | translate_bvalues_with_limit(Values,no_limit,Output). % we could set a very high-limit, like max_atom_length |
2093 | | |
2094 | | translate_bvalues_with_limit(Values,Limit,Output) :- |
2095 | | (Limit==no_limit -> true % |
2096 | | ; set_up_limit_reached(Codes,Limit,LimitReached) |
2097 | | ), |
2098 | | pp_value_l(Values,',',LimitReached,Codes,[]),!, |
2099 | | atom_codes_with_limit(Output,Codes). |
2100 | | translate_bvalues_with_limit(Values,Limit,O) :- |
2101 | | add_internal_error('Call failed: ',translate_bvalues(Values,Limit,O)), O='??'. |
2102 | | |
2103 | | translate_bvalue_for_expression(Value,TExpr,Output) :- |
2104 | | animation_minor_mode(tla), |
2105 | | expression_has_tla_type(TExpr,TlaType),!, |
2106 | | translate_bvalue_with_tlatype(Value,TlaType,Output). |
2107 | | translate_bvalue_for_expression(Value,TExpr,Output) :- |
2108 | | get_texpr_type(TExpr,Type), |
2109 | | translate_bvalue_with_type(Value,Type,Output). |
2110 | | |
2111 | | translate_bvalue_for_expression_with_limit(Value,TExpr,_Limit,Output) :- |
2112 | | animation_minor_mode(tla), |
2113 | | expression_has_tla_type(TExpr,TlaType),!, |
2114 | | translate_bvalue_with_tlatype(Value,TlaType,Output). % TO DO: treat Limit |
2115 | | translate_bvalue_for_expression_with_limit(Value,TExpr,Limit,Output) :- |
2116 | | get_texpr_type(TExpr,Type), |
2117 | | translate_bvalue_with_type_and_limit(Value,Type,Limit,Output). |
2118 | | |
2119 | | expression_has_tla_type(TExpr,Type) :- |
2120 | | get_texpr_info(TExpr,Infos), |
2121 | | memberchk(tla_type(Type),Infos). |
2122 | | |
2123 | | |
2124 | | translate_bvalue_to_parseable_classicalb(Val,Str) :- |
2125 | | % corresponds to set_print_type_infos(needed) |
2126 | | temporary_set_preference(translate_force_all_typing_infos,false,CHNG), |
2127 | | temporary_set_preference(translate_print_typing_infos,true,CHNG2), |
2128 | | (animation_minor_mode(X) |
2129 | | -> remove_animation_minor_mode, |
2130 | | call_cleanup(translate_bvalue_to_parseable_aux(Val,Str), |
2131 | | (reset_temporary_preference(translate_force_all_typing_infos,CHNG), |
2132 | | reset_temporary_preference(translate_print_typing_infos,CHNG2), |
2133 | | set_animation_minor_mode(X))) |
2134 | | ; call_cleanup(translate_bvalue_to_parseable_aux(Val,Str), |
2135 | | (reset_temporary_preference(translate_force_all_typing_infos,CHNG), |
2136 | | reset_temporary_preference(translate_print_typing_infos,CHNG2))) |
2137 | | ). |
2138 | | translate_bvalue_to_parseable_aux(Val,Str) :- |
2139 | | call_pp_with_no_limit_and_parseable(translate_bvalue(Val,Str)). |
2140 | | |
2141 | | |
2142 | | translate_bexpr_to_parseable(Expr,Str) :- |
2143 | | call_pp_with_no_limit_and_parseable(translate_bexpression(Expr,Str)). |
2144 | | |
2145 | | % a more refined pretty printing: takes Type information into account; useful for detecting sequences |
2146 | | translate_bvalue_with_type(Value,_,Output) :- var(Value),!, |
2147 | | translate_bvalue(Value,Output). |
2148 | | translate_bvalue_with_type(Value,Type,Output) :- |
2149 | | adapt_value_according_to_type(Type,Value,NewValue), |
2150 | | translate_bvalue(NewValue,Output). |
2151 | | |
2152 | | translate_bvalue_with_type_and_limit(Value,Type,Limit,Output) :- |
2153 | | get_preference(expand_avl_upto,CurLim), |
2154 | | SetLim is Limit//2, % at least two symbols per element |
2155 | | %print(translate(SetLim,CurLim)),nl, |
2156 | | (CurLim<0 ; SetLim < CurLim),!, |
2157 | | temporary_set_preference(expand_avl_upto,SetLim,CHNG), |
2158 | | translate_bvalue_with_type_and_limit2(Value,Type,Limit,Output), |
2159 | | reset_temporary_preference(expand_avl_upto,CHNG). |
2160 | | translate_bvalue_with_type_and_limit(Value,Type,Limit,Output) :- |
2161 | | translate_bvalue_with_type_and_limit2(Value,Type,Limit,Output). |
2162 | | translate_bvalue_with_type_and_limit2(Value,_,Limit,Output) :- var(Value),!, |
2163 | | translate_bvalue_with_limit(Value,Limit,Output). |
2164 | | translate_bvalue_with_type_and_limit2(Value,Type,Limit,Output) :- |
2165 | | adapt_value_according_to_type(Type,Value,NewValue), |
2166 | | translate:translate_bvalue_with_limit(NewValue,Limit,Output). |
2167 | | %debug:watch(translate:translate_bvalue_with_limit(NewValue,Limit,Output)). |
2168 | | |
2169 | | :- use_module(avl_tools,[quick_avl_approximate_size/2]). |
2170 | | adapt_value_according_to_type(_,Var,R) :- var(Var),!,R=Var. |
2171 | | adapt_value_according_to_type(T,V,R) :- var(T),!, |
2172 | | add_internal_error('Variable type: ',adapt_value_according_to_type(T,V,R)), |
2173 | | R=V. |
2174 | | adapt_value_according_to_type(integer,V,R) :- !,R=V. |
2175 | | adapt_value_according_to_type(string,V,R) :- !,R=V. |
2176 | | adapt_value_according_to_type(boolean,V,R) :- !,R=V. |
2177 | | adapt_value_according_to_type(global(_),V,R) :- !,R=V. |
2178 | | adapt_value_according_to_type(couple(TA,TB),(VA,VB),R) :- !, R=(RA,RB), |
2179 | | adapt_value_according_to_type(TA,VA,RA), |
2180 | | adapt_value_according_to_type(TB,VB,RB). |
2181 | | adapt_value_according_to_type(set(Type),avl_set(A),Res) :- check_is_non_empty_avl(A), |
2182 | | quick_avl_approximate_size(A,S),S<20, |
2183 | | custom_explicit_sets:expand_custom_set_to_list(avl_set(A),List),!, |
2184 | | maplist(adapt_value_according_to_type(Type),List,Res). |
2185 | | adapt_value_according_to_type(set(_Type),V,R) :- !,R=V. |
2186 | | adapt_value_according_to_type(seq(Type),V,R) :- !, % the type tells us it is a sequence |
2187 | | (convert_set_into_sequence(V,VS) |
2188 | | -> l_adapt_value_according_to_type(VS,Type,AVS), |
2189 | | R=sequence(AVS) |
2190 | | ; R=V). |
2191 | | adapt_value_according_to_type(record(_Fields),Value,R) :- !, % to do: convert inside record |
2192 | | R=Value. |
2193 | | adapt_value_according_to_type(freetype(_),Value,R) :- !, R=Value. |
2194 | | adapt_value_according_to_type(any,Value,R) :- !, R=Value. |
2195 | | adapt_value_according_to_type(_,term(V),R) :- !, R=term(V). % appears for unknown values (no_value_for) when ALLOW_INCOMPLETE_SETUP_CONSTANTS is true |
2196 | | adapt_value_according_to_type(Type,Value,R) :- print(adapt_value_according_to_type_unknown(Type,Value)),nl, |
2197 | | R=Value. |
2198 | | |
2199 | | l_adapt_value_according_to_type([],_Type,R) :- !,R=[]. |
2200 | | l_adapt_value_according_to_type([H|T],Type,[AH|AT]) :- |
2201 | | adapt_value_according_to_type(Type,H,AH), |
2202 | | l_adapt_value_according_to_type(T,Type,AT). |
2203 | | |
2204 | | pp_value_with_type(E,T,LimitReached) --> {adapt_value_according_to_type(T,E,AdaptedE)}, |
2205 | | pp_value(AdaptedE,LimitReached). |
2206 | | |
2207 | | pp_value(V,In,Out) :- |
2208 | | set_up_limit_reached(In,1000,LimitReached), |
2209 | | pp_value(V,LimitReached,In,Out). |
2210 | | |
2211 | | % LimitReached is a flag: when it is grounded to limit_reached this instructs pp_value to stop generating output |
2212 | | pp_value(_,LimitReached) --> {LimitReached==limit_reached},!, "...". |
2213 | | pp_value(V,_) --> {var(V)},!, pp_variable(V). |
2214 | | pp_value('$VAR'(N),_) --> !,pp_numberedvar(N). |
2215 | | pp_value(X,_) --> {cyclic_term(X)},!,underscore_symbol,"cyclic",underscore_symbol. |
2216 | | pp_value(fd(X,GSet),_) --> {var(X)},!, |
2217 | | ppatom(GSet),":", ppnumber(X). %":??". |
2218 | | pp_value(fd(X,GSet),_) --> |
2219 | | {b_global_sets:is_b_global_constant_hash(GSet,X,Res)},!, |
2220 | | pp_identifier(Res). |
2221 | | pp_value(fd(X,GSet),_) --> {deferred_set_constant(GSet,X,Cst)},!, |
2222 | | pp_identifier(Cst). |
2223 | | pp_value(fd(X,M),_) --> !,ppatom_opt_scramble(M),ppnumber(X). |
2224 | | pp_value(int(X),_) --> !,ppnumber(X). |
2225 | | pp_value(term(floating(X)),_) --> !,ppnumber(X). |
2226 | | pp_value(string(X),_) --> !,string_start_symbol,ppstring_opt_scramble(X),string_end_symbol. |
2227 | | pp_value(global_set(X),_) --> {atomic(X),integer_set_mapping(X,Kind,Y)},!, |
2228 | | ({Kind=integer_set} -> ppatom(Y) ; ppatom_opt_scramble(X)). |
2229 | | pp_value(term(X),_) --> {var(X)},!,"term(",pp_variable(X),")". |
2230 | | pp_value(freetype(X),_) --> {pretty_freetype(X,P)},!,ppatom_opt_scramble(P). |
2231 | | pp_value(pred_true /* bool_true */,_) --> %!,"TRUE". % TO DO: in latex_mode: surround by mathit |
2232 | | {constants_in_mode(pred_true,Symbol)},!,ppatom(Symbol). |
2233 | | pp_value(pred_false /* bool_false */,_) --> %!,"FALSE". |
2234 | | {constants_in_mode(pred_false,Symbol)},!,ppatom(Symbol). |
2235 | | %pp_value(bool_true) --> !,"TRUE". % old version; still in some test traces which are printed |
2236 | | %pp_value(bool_false) --> !,"FALSE". |
2237 | | pp_value([],_) --> !,empty_set_symbol. |
2238 | | pp_value(sequence(List),LimitReached) --> !, |
2239 | | ({List=[]} -> pp_empty_sequence ; pp_sequence_with_limit(List,LimitReached)). |
2240 | | pp_value([Head|Tail],LimitReached) --> {get_preference(translate_print_all_sequences,true), |
2241 | | convert_set_into_sequence([Head|Tail],Elements)}, |
2242 | | !, |
2243 | | pp_sequence(Elements,LimitReached). |
2244 | | pp_value([Head|Tail],LimitReached) --> !, {set_brackets(L,R)}, |
2245 | | ppatom(L), |
2246 | | pp_value_l_with_limit([Head|Tail],',',LimitReached), |
2247 | | ppatom(R). |
2248 | | %pp_value([Head|Tail]) --> !, |
2249 | | % {( convert_set_into_sequence([Head|Tail],Elements) -> |
2250 | | % (Start,End) = ('[',']') |
2251 | | % ; |
2252 | | % Elements = [Head|Tail], |
2253 | | % (Start,End) = ('{','}'))}, |
2254 | | % ppatom(Start),pp_value_l(Elements,','),ppatom(End). |
2255 | | pp_value( (A,B) ,LimitReached) --> !, |
2256 | | "(",pp_inner_value(A,LimitReached), |
2257 | | maplet_symbol, |
2258 | | pp_value(B,LimitReached),")". |
2259 | | pp_value(avl_set(A),LimitReached) --> !, |
2260 | | {check_is_non_empty_avl(A),avl_size(A,Sz)}, |
2261 | | {set_brackets(LBrace,RBrace)}, |
2262 | | ( {size_is_in_set_limit(Sz), |
2263 | | %(Sz>2 ; get_preference(translate_print_all_sequences,true)), |
2264 | | get_preference(translate_print_all_sequences,true), % no longer try and convert any sequence longer than 2 to sequence notation |
2265 | | avl_max(A,(int(Sz),_)), % a sequence has minimum int(1) and maximum int(Sz) |
2266 | | convert_avlset_into_sequence(A,Seq)} -> |
2267 | | pp_sequence(Seq,LimitReached) |
2268 | | ; |
2269 | | ( {Sz=0} -> left_set_bracket," /* empty avl_set */ ",right_set_bracket |
2270 | | ; {(size_is_in_set_limit(Sz) ; Sz < 3)} -> % if Sz 3 we will print at least two elements anyway |
2271 | | {avl_domain(A,List)}, |
2272 | | ppatom(LBrace),pp_value_l(List,',',LimitReached),ppatom(RBrace) |
2273 | | ; {(Sz<5 ; \+ size_is_in_set_limit(4))} -> |
2274 | | {avl_min(A,Min),avl_max(A,Max)}, |
2275 | | hash_card_symbol, % "#" |
2276 | | ppnumber(Sz),":", left_set_bracket, |
2277 | | pp_value(Min,LimitReached),",",ldots,",",pp_value(Max,LimitReached),right_set_bracket |
2278 | | ; |
2279 | | {avl_min(A,Min),avl_next(Min,A,Nxt),avl_max(A,Max),avl_prev(Max,A,Prev)}, |
2280 | | hash_card_symbol, % "#", |
2281 | | ppnumber(Sz),":", left_set_bracket, |
2282 | | pp_value(Min,LimitReached),",",pp_value(Nxt,LimitReached),",",ldots,",", |
2283 | | pp_value(Prev,LimitReached),",",pp_value(Max,LimitReached),right_set_bracket )). |
2284 | | |
2285 | | pp_value(field(Name,Value),LimitReached) --> !, |
2286 | | pp_identifier(Name),":",pp_value(Value,LimitReached). % : for fields has priority 120 in French manual |
2287 | | pp_value(rec(Rec),LimitReached) --> !, |
2288 | | {function_like_in_mode(rec,Symbol)}, |
2289 | | ppatom(Symbol), "(",pp_value_l(Rec,',',LimitReached),")". |
2290 | | pp_value(struct(Rec),LimitReached) --> !, |
2291 | | {function_like_in_mode(struct,Symbol)}, |
2292 | | ppatom(Symbol), "(", pp_value_l(Rec,',',LimitReached),")". |
2293 | | pp_value(term(no_value_for(Id)),_) --> !, |
2294 | | "undefined ",ppatom(Id). |
2295 | | pp_value(closure(Variables,Types,Predicate),LimitReached) --> !, |
2296 | | pp_closure_value(Variables,Types,Predicate,LimitReached). |
2297 | | pp_value(freeval(Freetype,Case,Value),LimitReached) --> !, |
2298 | | ({ground(Case),ground(Value),Value=term(Case)} -> ppatom_opt_scramble(Case) |
2299 | | ; {ground(Case)} -> ppatom_opt_scramble(Case),"(",pp_value(Value,LimitReached),")" |
2300 | | ; {pretty_freetype(Freetype,P)}, |
2301 | | "FREEVALUE[",ppatom_opt_scramble(P), |
2302 | | ",",write_to_codes(Case), |
2303 | | "](",pp_value(Value,LimitReached),")" |
2304 | | ). |
2305 | | pp_value(X,_) --> {animation_mode(xtl)},!, |
2306 | | write_to_codes(X). |
2307 | | pp_value(X,_) --> % the << >> pose problems when checking against FDR |
2308 | | "<< ",write_to_codes(X)," >>". |
2309 | | |
2310 | | pp_variable(V) --> write_to_codes(V). %underscore_symbol. |
2311 | | |
2312 | | :- use_module(closures,[is_recursive_closure/3]). |
2313 | | |
2314 | | pp_closure_value(Ids,Type,B,_LimitReached) --> |
2315 | | {var(Ids) ; var(Type) ; var(B)},!, |
2316 | | add_internal_error('Illegal value: ',pp_value_illegal_closure(Ids,Type,B)), |
2317 | | "<< ILLEGAL ",write_to_codes(closure(Ids,Type,B))," >>". |
2318 | | pp_closure_value(Variables,Types,Predicate,LimitReached) --> {\+ size_is_in_set_limit(1)}, |
2319 | | !, % do not print body; just print hash value |
2320 | | {make_closure_ids(Variables,Types,Ids), term_hash(Predicate,PH)}, |
2321 | | left_set_bracket, % { Ids | #PREDICATE#(HASH) } |
2322 | | pp_expr_l_pair_in_mode(Ids,LimitReached), |
2323 | | pp_such_that_bar, |
2324 | | " ",hash_card_symbol,"PREDICATE",hash_card_symbol,"(",ppnumber(PH),") ", right_set_bracket. |
2325 | | pp_closure_value(Variables,Types,Predicate,LimitReached) --> |
2326 | | {get_preference(translate_ids_to_parseable_format,true), |
2327 | | is_recursive_closure(Variables,Types,Predicate), |
2328 | | get_texpr_info(Predicate,Infos), |
2329 | | member(prob_annotation(recursive(TID)),Infos), |
2330 | | def_get_texpr_id(TID,ID)}, !, |
2331 | | % write recursive let for f as : CHOOSE(.) or MU({f|f= SET /*@desc letrec */ }) |
2332 | | % an alternate syntax could be RECLET f BE f = SET IN f END |
2333 | | "MU({", pp_identifier(ID), "|", |
2334 | | pp_identifier(ID)," = ", |
2335 | | pp_closure_value2(Variables,Types,Predicate,LimitReached), |
2336 | | "/*@desc letrec */ }) ". |
2337 | | pp_closure_value([Id],[Type],Membership,LimitReached) --> |
2338 | | { get_texpr_expr(Membership,member(Elem,Set)), |
2339 | | get_texpr_id(Elem,Id), |
2340 | | \+ occurs_in_expr(Id,Set), % detect things like {s|s : 1 .. card(s) --> T} (test 1030) |
2341 | | get_texpr_type(Elem,Type), |
2342 | | !}, |
2343 | | pp_expr_m(Set,299,LimitReached). |
2344 | | pp_closure_value(Variables,Types,Predicate,LimitReached) --> pp_closure_value2(Variables,Types,Predicate,LimitReached). |
2345 | | |
2346 | | pp_closure_value2(Variables,Types,Predicate,LimitReached) --> !, |
2347 | | {make_closure_ids(Variables,Types,Ids)}, |
2348 | | pp_comprehension_set(Ids,Predicate,[],LimitReached). % TODO: propagate LimitReached |
2349 | | |
2350 | | % avoid printing parentheses: |
2351 | | % (x,y,z) = ((x,y),z) |
2352 | | pp_inner_value( AB , LimitReached) --> {nonvar(AB),AB=(A,B)}, !, % do not print parentheses in this context |
2353 | | pp_inner_value(A,LimitReached),maplet_symbol, |
2354 | | pp_value(B,LimitReached). |
2355 | | pp_inner_value( Value , LimitReached) --> pp_value( Value , LimitReached). |
2356 | | |
2357 | | size_is_in_set_limit(Size) :- get_preference(expand_avl_upto,Max), |
2358 | | (Max<0 -> true /* no limit */ |
2359 | | ; Size =< Max). |
2360 | | |
2361 | | dcg_set_up_limit_reached(Limit,LimitReached,InList,InList) :- set_up_limit_reached(InList,Limit,LimitReached). |
2362 | | |
2363 | | % instantiate LimitReached argument as soon as a list exceeds a certain limit |
2364 | | set_up_limit_reached(_,Neg,_) :- Neg<0,!. % negative number means unlimited |
2365 | | set_up_limit_reached(_,0,LimitReached) :- !, LimitReached = limit_reached. |
2366 | | set_up_limit_reached(List,Limit,LimitReached) :- |
2367 | | block_set_up_limit_reached(List,Limit,LimitReached). |
2368 | | :- block block_set_up_limit_reached(-,?,?). |
2369 | | block_set_up_limit_reached([],_,_). |
2370 | | block_set_up_limit_reached([_|T],Limit,LimitReached) :- |
2371 | | (Limit<1 -> LimitReached=limit_reached |
2372 | | ; L1 is Limit-1, block_set_up_limit_reached(T,L1,LimitReached)). |
2373 | | |
2374 | | % pretty print LimitReached, requires %:- block block_set_up_limit_reached(-,?,-). |
2375 | | /* |
2376 | | pp_lr(LR) --> {LR==limit_reached},!, " *LR* ". |
2377 | | pp_lr(LR) --> {frozen(LR,translate:block_set_up_limit_reached(_,Lim,_))},!, " ok(", ppnumber(Lim),") ". |
2378 | | pp_lr(LR) --> {frozen(LR,G)},!, " ok(", ppterm(G),") ". |
2379 | | pp_lr(_) --> " ok ". |
2380 | | */ |
2381 | | |
2382 | | |
2383 | | pp_value_l_with_limit(V,Sep,LimitReached) --> {get_preference(expand_avl_upto,Max)}, |
2384 | | pp_value_l(V,Sep,Max,LimitReached). |
2385 | | pp_value_l(V,Sep,LimitReached) --> pp_value_l(V,Sep,-1,LimitReached). |
2386 | | |
2387 | | pp_value_l(V,_Sep,_,_) --> {var(V)},!,"...". |
2388 | | pp_value_l(_,_,_,LimitReached) --> {LimitReached==limit_reached},!,"...". |
2389 | | pp_value_l('$VAR'(N),_Sep,_,_) --> !,"}\\/{",pp_numberedvar(N),"}". |
2390 | | pp_value_l([],_Sep,_,_) --> !. |
2391 | | pp_value_l([Expr|Rest],Sep,Limit,LimitReached) --> |
2392 | | ( {nonvar(Rest),Rest=[]} -> |
2393 | | pp_value(Expr,LimitReached) |
2394 | | ; {Limit=0} -> "..." |
2395 | | ; |
2396 | | pp_value(Expr,LimitReached), |
2397 | | % no separator for closure special case |
2398 | | ({nonvar(Rest) , Rest = closure(_,_,_)} -> {true} ; ppatom(Sep)) , |
2399 | | {L1 is Limit-1} , |
2400 | | % convert avl_set(_) in a list's tail to a Prolog list |
2401 | | {nonvar(Rest) , Rest = avl_set(_) -> custom_explicit_sets:expand_custom_set_to_list(Rest,LRest) ; LRest = Rest} , |
2402 | | pp_value_l(LRest,Sep,L1,LimitReached)). |
2403 | | pp_value_l(avl_set(A),_Sep,_,LimitReached) --> pp_value(avl_set(A),LimitReached). |
2404 | | pp_value_l(closure(A,B,C),_Sep,_,LimitReached) --> "}\\/", pp_value(closure(A,B,C),LimitReached). |
2405 | | |
2406 | | make_closure_ids([],[],[]). |
2407 | | make_closure_ids([V|Vrest],[T|Trest],[TExpr|TErest]) :- |
2408 | | (var(V) -> V2='_', format('Illegal variable identifier in make_closure_ids: ~w~n',[V]) |
2409 | | ; V2=V), |
2410 | | create_texpr(identifier(V2),T,[],TExpr), |
2411 | | make_closure_ids(Vrest,Trest,TErest). |
2412 | | |
2413 | | % symbol for starting and ending a sequence: |
2414 | | pp_begin_sequence --> {animation_minor_mode(tla)},!,"<<". |
2415 | | pp_begin_sequence --> {get_preference(translate_print_cs_style_sequences,true)},!,"". |
2416 | | pp_begin_sequence --> "[". |
2417 | | pp_end_sequence --> {animation_minor_mode(tla)},!,">>". |
2418 | | pp_end_sequence --> {get_preference(translate_print_cs_style_sequences,true)},!,"". |
2419 | | pp_end_sequence --> "]". |
2420 | | |
2421 | | pp_separator_sequence('') :- get_preference(translate_print_cs_style_sequences,true),!. |
2422 | | pp_separator_sequence(','). |
2423 | | |
2424 | | % string for empty sequence |
2425 | | pp_empty_sequence --> {animation_minor_mode(tla)},!, "<< >>". |
2426 | | pp_empty_sequence --> {get_preference(translate_print_cs_style_sequences,true)},!, |
2427 | | ( {latex_mode} -> "\\lambda" ; [955]). % 955 is lambda symbol in Unicode |
2428 | | pp_empty_sequence --> {atelierb_mode(pp)},!, "{}". |
2429 | | pp_empty_sequence --> "[]". |
2430 | | |
2431 | | % symbols for function application: |
2432 | | pp_function_left_bracket --> {animation_minor_mode(tla)},!, "[". |
2433 | | pp_function_left_bracket --> "(". |
2434 | | |
2435 | | pp_function_right_bracket --> {animation_minor_mode(tla)},!, "]". |
2436 | | pp_function_right_bracket --> ")". |
2437 | | |
2438 | | pp_sequence(Elements,LimitReached) --> {pp_separator_sequence(Sep)}, |
2439 | | pp_begin_sequence, |
2440 | | pp_value_l(Elements,Sep,LimitReached), |
2441 | | pp_end_sequence. |
2442 | | pp_sequence_with_limit(Elements,LimitReached) --> {pp_separator_sequence(Sep)}, |
2443 | | pp_begin_sequence, |
2444 | | pp_value_l_with_limit(Elements,Sep,LimitReached), |
2445 | | pp_end_sequence. |
2446 | | |
2447 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2448 | | % machines |
2449 | | |
2450 | | :- use_module(eventhandling,[register_event_listener/3]). |
2451 | | :- register_event_listener(clear_specification,reset_translate, |
2452 | | 'Reset Translation Caches.'). |
2453 | | reset_translate :- retractall(bugly_scramble_id_cache(_,_)), retractall(non_det_constants(_,_)). |
2454 | | %reset_translate :- set_print_type_infos(none), |
2455 | | % set_preference(translate_suppress_rodin_positions_flag,false). |
2456 | | |
2457 | | suppress_rodin_positions(CHNG) :- set_suppress_rodin_positions(true,CHNG). |
2458 | | set_suppress_rodin_positions(Value,CHNG) :- |
2459 | | temporary_set_preference(translate_suppress_rodin_positions_flag,Value,CHNG). |
2460 | | reset_suppress_rodin_positions(CHNG) :- |
2461 | | reset_temporary_preference(translate_suppress_rodin_positions_flag,CHNG). |
2462 | | |
2463 | | set_print_type_infos(none) :- !, |
2464 | | set_preference(translate_force_all_typing_infos,false), |
2465 | | set_preference(translate_print_typing_infos,false). |
2466 | | set_print_type_infos(needed) :- !, |
2467 | | set_preference(translate_force_all_typing_infos,false), |
2468 | | set_preference(translate_print_typing_infos,true). |
2469 | | set_print_type_infos(all) :- !, |
2470 | | set_preference(translate_force_all_typing_infos,true), |
2471 | | set_preference(translate_print_typing_infos,true). |
2472 | | set_print_type_infos(Err) :- |
2473 | | add_internal_error('Illegal type: ',set_print_type_infos(Err)). |
2474 | | |
2475 | | |
2476 | | :- use_module(tools_files,[put_codes/2]). |
2477 | | print_machine(M) :- |
2478 | | nl, translate_machine(M,Msg,true), put_codes(Msg,user_output), nl, |
2479 | | flush_output(user_output),!. |
2480 | | print_machine(M) :- add_internal_error('Printing failed: ',print_machine(M)). |
2481 | | |
2482 | | % |
2483 | | translate_machine(M,Codes,AdditionalInfo) :- |
2484 | | retractall(print_additional_machine_info), |
2485 | | (AdditionalInfo=true -> assertz(print_additional_machine_info) ; true), |
2486 | | call_pp_with_no_limit_and_parseable(translate_machine1(M,(0,Codes),(_,[]))). |
2487 | | |
2488 | | % perform a call by forcing parseable output and removing limit to set |
2489 | | call_pp_with_no_limit_and_parseable(PP_Call) :- |
2490 | | temporary_set_preference(translate_ids_to_parseable_format,true,CHNG), |
2491 | | temporary_set_preference(expand_avl_upto,-1,CHNG2), |
2492 | | call_cleanup(call(PP_Call), |
2493 | | (reset_temporary_preference(translate_ids_to_parseable_format,CHNG), |
2494 | | reset_temporary_preference(expand_avl_upto,CHNG2))). |
2495 | | |
2496 | | |
2497 | | % useful if we wish to translate just a selection of sections without MACHINE/END |
2498 | | translate_section_list(SL,Codes) :- init_machine_translation, |
2499 | | translate_machine2(SL,SL,no_end,(0,Codes),(_,[])). |
2500 | | |
2501 | | translate_machine1(machine(Name,Sections)) --> |
2502 | | indent('MACHINE '), {adapt_machine_name(Name,AName)}, insertstr(AName), |
2503 | | {init_machine_translation}, |
2504 | | translate_machine2(Sections,Sections,end). |
2505 | | translate_machine2([],_,end) --> !, insertstr('\nEND\n'). |
2506 | | translate_machine2([],_,_) --> !, insertstr('\n'). |
2507 | | translate_machine2([P|Rest],All,End) --> |
2508 | | translate_mpart(P,All), |
2509 | | translate_machine2(Rest,All,End). |
2510 | | |
2511 | | adapt_machine_name('dummy(uses)',R) :- !,R='MAIN'. |
2512 | | adapt_machine_name(X,X). |
2513 | | |
2514 | | :- dynamic section_header_generated/1. |
2515 | | :- dynamic print_additional_machine_info/0. |
2516 | | print_additional_machine_info. |
2517 | | |
2518 | | init_machine_translation :- retractall(section_header_generated(_)). |
2519 | | |
2520 | | % start a part of a section |
2521 | | mpstart(Title,I) --> |
2522 | | insertstr('\n'),insertstr(Title), |
2523 | | indention_level(I,I2), {I2 is I+2}. |
2524 | | % end a part of a section |
2525 | | mpend(I) --> |
2526 | | indention_level(_,I). |
2527 | | |
2528 | | mpstart_section(Section,Title,AltTitle,I,In,Out) :- |
2529 | | (\+ section_header_generated(Section) |
2530 | | -> mpstart(Title,I,In,Out), assertz(section_header_generated(Section)) |
2531 | | ; mpstart(AltTitle,I,In,Out) /* use alternative title; section header already generated */ |
2532 | | ). |
2533 | | |
2534 | | translate_mpart(Section/I,All) --> %{print(Section),nl}, |
2535 | | ( {I=[]} -> {true} |
2536 | | ; translate_mpart2(Section,I,All) -> {true} |
2537 | | ; |
2538 | | insertstr('\nSection '),insertstr(Section),insertstr(': '), |
2539 | | insertstr('<< pretty-print failed >>') |
2540 | | ). |
2541 | | translate_mpart2(deferred_sets,I,_) --> |
2542 | | mpstart_section(sets,'SETS /* deferred */',' ; /* deferred */',P), |
2543 | | indent_expr_l_sep(I,';'),mpend(P). |
2544 | | translate_mpart2(enumerated_sets,_I,_) --> []. % these are now pretty printed below |
2545 | | %mpstart('ENUMERATED SETS',P),indent_expr_l_sep(I,';'),mpend(P). |
2546 | | translate_mpart2(enumerated_elements,I,_) --> %{print(enum_els(I)),nl}, |
2547 | | {translate_enums(I,[],Res)}, |
2548 | | mpstart_section(sets,'SETS /* enumerated */',' ; /* enumerated */',P), |
2549 | | indent_expr_l_sep(Res,';'),mpend(P). |
2550 | | translate_mpart2(parameters,I,_) --> mpstart('PARAMETERS',P),indent_expr_l_sep(I,','),mpend(P). |
2551 | | translate_mpart2(internal_parameters,I,_) --> {print_additional_machine_info},!, |
2552 | | mpstart('/* INTERNAL_PARAMETERS',P),indent_expr_l_sep(I,','),insertstr(' */'),mpend(P). |
2553 | | translate_mpart2(internal_parameters,_I,_) --> []. |
2554 | | translate_mpart2(abstract_variables,I,_) --> mpstart('ABSTRACT_VARIABLES',P),indent_exprs(I),mpend(P). |
2555 | | translate_mpart2(concrete_variables,I,_) --> mpstart('CONCRETE_VARIABLES',P),indent_exprs(I),mpend(P). |
2556 | | translate_mpart2(abstract_constants,I,_) --> mpstart('ABSTRACT_CONSTANTS',P),indent_exprs(I),mpend(P). |
2557 | | translate_mpart2(concrete_constants,I,_) --> mpstart('CONCRETE_CONSTANTS',P),indent_exprs(I),mpend(P). |
2558 | | translate_mpart2(promoted,I,_) --> {print_additional_machine_info},!, |
2559 | | mpstart('/* PROMOTED OPERATIONS',P),indent_expr_l_sep(I,','),insertstr(' */'),mpend(P). |
2560 | | translate_mpart2(promoted,_I,_) --> []. |
2561 | | translate_mpart2(unpromoted,I,_) --> {print_additional_machine_info},!, |
2562 | | mpstart('/* NOT PROMOTED OPERATIONS',P),indent_expr_l_sep(I,','),insertstr(' */'),mpend(P). |
2563 | | translate_mpart2(unpromoted,_I,_) --> []. |
2564 | | translate_mpart2(constraints,I,All) --> mpart_typing(constraints,[parameters],All,I). |
2565 | | translate_mpart2(invariant,I,All) --> mpart_typing(invariant, [abstract_variables,concrete_variables],All,I). |
2566 | | translate_mpart2(linking_invariant,_I,_) --> []. |
2567 | | translate_mpart2(properties,I,All) --> mpart_typing(properties,[abstract_constants,concrete_constants],All,I). |
2568 | | translate_mpart2(assertions,I,_) --> |
2569 | | mpstart_spec_desc(assertions,P), |
2570 | | %indent_expr_l_sep(I,';'), |
2571 | | preds_over_lines(1,'@thm','; ',I), |
2572 | | mpend(P). % TO DO: |
2573 | | translate_mpart2(initialisation,S,_) --> mpstart_spec_desc(initialisation,P),translate_inits(S),mpend(P). |
2574 | | translate_mpart2(definitions,Defs,_) --> {(standard_library_required(Defs,_) ; set_pref_used(Defs))},!, |
2575 | | mpstart('DEFINITIONS',P), |
2576 | | insertstr('\n'), |
2577 | | {findall(Lib,standard_library_required(Defs,Lib),Libs)}, |
2578 | | insert_library_usages(Libs), |
2579 | | translate_set_pref_defs(Defs), |
2580 | | mpend(P), |
2581 | | translate_other_defpart(Defs). |
2582 | | translate_mpart2(definitions,Defs,_) --> !, translate_other_defpart(Defs). |
2583 | | translate_mpart2(operation_bodies,Ops,_) --> mpstart_spec_desc(operations,P),translate_ops(Ops),mpend(P). |
2584 | | translate_mpart2(used,Used,_) --> {print_additional_machine_info},!, |
2585 | | mpstart('/* USED',P),translate_used(Used),insertstr(' */'),mpend(P). |
2586 | | translate_mpart2(used,_Used,_) --> []. |
2587 | | translate_mpart2(freetypes,Freetypes,_) --> |
2588 | | mpstart('FREETYPES',P),translate_freetypes(Freetypes),mpend(P). |
2589 | | translate_mpart2(meta,_Infos,_) --> []. |
2590 | | translate_mpart2(operators,Operators,_) --> |
2591 | | insertstr('\n/* Event-B operators:'), % */ |
2592 | | indention_level(I,I2), {I2 is I+2}, |
2593 | | translate_eventb_operators(Operators), |
2594 | | indention_level(I2,I), |
2595 | | insertstr('\n*/'). |
2596 | | translate_mpart2(values,Values,_) --> |
2597 | | mpstart('VALUES',P),indent_expr_l_sep(Values,';'),mpend(P). |
2598 | | |
2599 | | indent_exprs(I) --> {force_eventb_rodin_mode},!, indent_expr_l_sep(I,' '). % Event-B Camille style |
2600 | | indent_exprs(I) --> indent_expr_l_sep(I,','). |
2601 | | |
2602 | | |
2603 | | % Add typing predicates to a predicate |
2604 | | mpart_typing(Title,Section,Sections,PredI) --> |
2605 | | {mpart_typing2(Section,Sections,PredI,PredO)}, |
2606 | | ( {is_truth(PredO)} -> [] % TO DO: in animation_minor_mode(z) for INVARIANT: force adding typing predicates (translate_print_typing_infos) |
2607 | | ; |
2608 | | mpstart_spec_desc(Title,P), |
2609 | | section_pred_over_lines(0,Title,PredO), |
2610 | | mpend(P)). |
2611 | | |
2612 | | mpstart_spec_desc(Title,P) --> {get_specification_description(Title,Atom)},!, mpstart(Atom,P). |
2613 | | mpstart_spec_desc(Title,P) --> mpstart(Title,P). |
2614 | | |
2615 | | mpart_typing2(Sections,AllSections,PredI,PredO) :- |
2616 | | get_preference(translate_print_typing_infos,true),!, |
2617 | | get_all_ids(Sections,AllSections,Ids), |
2618 | | add_typing_predicates(Ids,PredI,PredO). |
2619 | | mpart_typing2(_Section,_Sections,Pred,Pred). |
2620 | | |
2621 | | get_all_ids([],_Sections,[]). |
2622 | | get_all_ids([Section|Srest],Sections,Ids) :- |
2623 | | memberchk(Section/Ids1,Sections), |
2624 | | append(Ids1,Ids2,Ids), |
2625 | | get_all_ids(Srest,Sections,Ids2). |
2626 | | |
2627 | | add_optional_typing_predicates(Ids,In,Out) :- |
2628 | | ( get_preference(translate_print_typing_infos,true) -> add_typing_predicates(Ids,In,Out) |
2629 | | ; is_truth(In) -> add_typing_predicates(Ids,In,Out) |
2630 | | ; In=Out). |
2631 | | |
2632 | | add_normal_typing_predicates(Ids,In,Out) :- % used to call add_typing_predicates directly |
2633 | | (add_optional_typing_predicates(Ids,In,Out) -> true |
2634 | | ; add_internal_error('Failed: ',add_normal_typing_predicates(Ids)), In=Out). |
2635 | | |
2636 | | add_typing_predicates([],P,P) :- !. |
2637 | | add_typing_predicates(Ids,Pin,Pout) :- |
2638 | | remove_already_typed_ids(Pin,Ids,UntypedIds), |
2639 | | KeepSeq=false, |
2640 | | generate_typing_predicates(UntypedIds,KeepSeq,Typing), |
2641 | | conjunction_to_list(Pin,Pins), |
2642 | | remove_duplicate_predicates(Typing,Pins,Typing2), |
2643 | | append(Typing2,[Pin],Preds), |
2644 | | conjunct_predicates(Preds,Pout). |
2645 | | |
2646 | | remove_already_typed_ids(_TExpr,Ids,Ids) :- |
2647 | | get_preference(translate_force_all_typing_infos,true),!. |
2648 | | remove_already_typed_ids(TExpr,Ids,UntypedIds) :- |
2649 | | get_texpr_expr(TExpr,Expr),!, |
2650 | | remove_already_typed_ids2(Expr,Ids,UntypedIds). |
2651 | | remove_already_typed_ids(TExpr,Ids,Res) :- |
2652 | | add_internal_error('Not a typed expression: ',remove_already_typed_ids(TExpr,Ids,_)), |
2653 | | Res=Ids. |
2654 | | remove_already_typed_ids2(conjunct(A,B),Ids,UntypedIds) :- !, |
2655 | | remove_already_typed_ids(A,Ids,I1), |
2656 | | remove_already_typed_ids(B,I1,UntypedIds). |
2657 | | remove_already_typed_ids2(lazy_let_pred(_,_,A),Ids,UntypedIds) :- !, |
2658 | | remove_already_typed_ids(A,Ids,UntypedIds). % TO DO: check for variable clases with lazy_let ids ??? |
2659 | | remove_already_typed_ids2(Expr,Ids,UntypedIds) :- |
2660 | | is_typing_predicate(Expr,Id), |
2661 | | create_texpr(identifier(Id),_,_,TId), |
2662 | | select(TId,Ids,UntypedIds),!. |
2663 | | remove_already_typed_ids2(_,Ids,Ids). |
2664 | | is_typing_predicate(member(A,_),Id) :- get_texpr_id(A,Id). |
2665 | | is_typing_predicate(subset(A,_),Id) :- get_texpr_id(A,Id). |
2666 | | is_typing_predicate(subset_strict(A,_),Id) :- get_texpr_id(A,Id). |
2667 | | |
2668 | | remove_duplicate_predicates([],_Old,[]). |
2669 | | remove_duplicate_predicates([Pred|Prest],Old,Result) :- |
2670 | | (is_duplicate_predicate(Pred,Old) -> Result = Rest ; Result = [Pred|Rest]), |
2671 | | remove_duplicate_predicates(Prest,Old,Rest). |
2672 | | is_duplicate_predicate(Pred,List) :- |
2673 | | remove_all_infos(Pred,Pattern), |
2674 | | memberchk(Pattern,List). |
2675 | | |
2676 | | :- use_module(typing_tools,[create_type_set/3]). |
2677 | | generate_typing_predicates(TIds,Preds) :- |
2678 | | generate_typing_predicates(TIds,true,Preds). |
2679 | | generate_typing_predicates(TIds,KeepSeq,Preds) :- |
2680 | | maplist(generate_typing_predicate(KeepSeq), TIds, Preds). |
2681 | | generate_typing_predicate(KeepSeq,TId,Pred) :- |
2682 | | get_texpr_type(TId,Type), |
2683 | | remove_all_infos_and_ground(TId,TId2), % clear all infos |
2684 | | (create_type_set(Type,KeepSeq,TSet) -> create_texpr(member(TId2,TSet),pred,[],Pred) |
2685 | | ; TId = b(_,any,[raw]) -> is_truth(Pred) % this comes from transform_raw |
2686 | | ; add_error(generate_typing_predicate,'Illegal type: ',Type), |
2687 | | is_truth(Pred) |
2688 | | ). |
2689 | | |
2690 | | |
2691 | | |
2692 | | |
2693 | | % translate enumerated constant list into enumerate set definition |
2694 | | translate_enums([],Acc,Acc). |
2695 | | translate_enums([EnumCst|T],Acc,Res) :- %get_texpr_id(EnumCst,Id), |
2696 | | get_texpr_type(EnumCst,global(GlobalSet)), |
2697 | | insert_enum_cst(Acc,EnumCst,GlobalSet,Acc2), |
2698 | | translate_enums(T,Acc2,Res). |
2699 | | |
2700 | | insert_enum_cst([],ID,Type,[enumerated_set_def(Type,[ID])]). |
2701 | | insert_enum_cst([enumerated_set_def(Type,Lst)|T],ID,Type2,[enumerated_set_def(Type,Lst2)|TT]) :- |
2702 | | (Type=Type2 |
2703 | | -> Lst2 = [ID|Lst], TT=T |
2704 | | ; Lst2 = Lst, insert_enum_cst(T,ID,Type2,TT) |
2705 | | ). |
2706 | | |
2707 | | % pretty-print the initialisation section of a machine |
2708 | | translate_inits(Inits) --> |
2709 | | ( {is_list_simple(Inits)} -> |
2710 | | translate_inits2(Inits) |
2711 | | ; |
2712 | | indention_level(I,I2),{I2 is I+2}, |
2713 | | translate_subst_begin_end(Inits), |
2714 | | indention_level(_,I)). |
2715 | | translate_inits2([]) --> !. |
2716 | | translate_inits2([init(Name,Subst)|Rest]) --> |
2717 | | indent('/* '),insertstr(Name),insertstr(': */ '), |
2718 | | translate_subst_begin_end(Subst), |
2719 | | translate_inits2(Rest). |
2720 | | |
2721 | | translate_other_defpart(Defs) --> {print_additional_machine_info},!, |
2722 | | mpstart('/* DEFINITIONS',P),translate_defs(Defs),insertstr(' */'),mpend(P). |
2723 | | translate_other_defpart(_) --> []. |
2724 | | |
2725 | | % pretty-print the definitions of a machine |
2726 | | translate_defs([]) --> !. |
2727 | | translate_defs([Def|Rest]) --> translate_def(Def),translate_defs(Rest). |
2728 | | translate_def(definition_decl(Name,_DefType,_Pos,_Args,Expr,_Deps)) --> |
2729 | | {dummy_def_body(Name,Expr)},!. |
2730 | | % this is a DEFINITION from a standard library; do not show it |
2731 | | translate_def(definition_decl(Name,DefType,_Pos,Args,Expr,_Deps)) --> |
2732 | | {def_description(DefType,Desc)}, indent(Desc),insertstr(Name), |
2733 | | {transform_raw_list(Args,TArgs)}, |
2734 | | translate_op_params(TArgs), |
2735 | | ( {show_def_body(Expr)} |
2736 | | -> insertstr(' '),{translate_in_mode(eqeq,'==',EqEqStr)}, insertstr(EqEqStr), insertstr(' '), |
2737 | | {transform_raw(Expr,TExpr)}, |
2738 | | (translate_def_body(DefType,TExpr) -> [] ; insertstr('CANNOT PRETTY PRINT')) |
2739 | | ; {true} |
2740 | | ), |
2741 | | insertstr(';'). |
2742 | | def_description(substitution,'SUBSTITUTION '). |
2743 | | def_description(expression,'EXPRESSION '). |
2744 | | def_description(predicate,'PREDICATE '). |
2745 | | translate_def_body(substitution,B) --> translate_subst_begin_end(B). |
2746 | | translate_def_body(expression,B) --> indent_expr(B). |
2747 | | translate_def_body(predicate,B) --> indent_expr(B). |
2748 | | |
2749 | | show_def_body(integer(_,_)). |
2750 | | show_def_body(boolean_true(_)). |
2751 | | show_def_body(boolean_false(_)). |
2752 | | % show_def_body(_) % comment in to pretty print all defs |
2753 | | |
2754 | | % check if we have a dummy definition body from a ProB Library file for external functions: |
2755 | | dummy_def_body(Name,Expr) :- |
2756 | | functor(Expr,F,_), (F=external_function_call ; F=external_pred_call), |
2757 | | arg(2,Expr,Name). |
2758 | | %external_function_declarations:external_function_library(Name,NrArgs,DefType,_),length(Args,NrArgs) |
2759 | | |
2760 | | % utility to print definitions in JSON format for use in a VisB file: |
2761 | | % useful when converting a B DEFINITIONS file for use in Event-B, TLA+,... |
2762 | | :- public print_defs_as_json/0. |
2763 | | print_defs_as_json :- |
2764 | | findall(json([name=string(Name), value=string(BS)]), ( |
2765 | | bmachine:b_get_definition_with_pos(Name,expression,_DefPos,_Args,RawExpr,_Deps), |
2766 | | \+ dummy_def_body(Name,RawExpr), |
2767 | | transform_raw(RawExpr,Body), |
2768 | | translate_subst_or_bexpr(Body,BS) |
2769 | | ), Defs), |
2770 | | Json = json([svg=string(''), definitions=array(Defs)]), |
2771 | | json_write_stream(Json). |
2772 | | |
2773 | | set_pref_used(Defs) :- member(definition_decl(Name,_,_,[],_,_),Defs), |
2774 | | (is_set_pref_def_name(Name,_,_) -> true). |
2775 | | |
2776 | | is_set_pref_def_name(Name,Pref,CurValAtom) :- |
2777 | | atom_codes(Name,Codes),append("SET_PREF_",RestCodes,Codes), |
2778 | | atom_codes(Pref,RestCodes), |
2779 | | (eclipse_preference(Pref,P) -> get_preference(P,CurVal), translate_pref_val(CurVal,CurValAtom) |
2780 | | ; deprecated_eclipse_preference(Pref,_,NewP,Mapping) -> get_preference(NewP,V), member(CurVal/V,Mapping) |
2781 | | ; get_preference(Pref,CurVal), translate_pref_val(CurVal,CurValAtom)), |
2782 | | translate_pref_val(CurVal,CurValAtom). |
2783 | | translate_pref_val(true,'TRUE'). |
2784 | | translate_pref_val(false,'FALSE'). |
2785 | | translate_pref_val(Nr,NrAtom) :- number(Nr),!, number_codes(Nr,C), atom_codes(NrAtom,C). |
2786 | | translate_pref_val(Atom,Atom) :- atom(Atom). |
2787 | | |
2788 | | is_set_pref(definition_decl(Name,_,_Pos,[],_Expr,_Deps)) :- |
2789 | | is_set_pref_def_name(Name,_,_). |
2790 | | translate_set_pref_defs(Defs) --> |
2791 | | {include(is_set_pref,Defs,SPDefs), |
2792 | | sort(SPDefs,SortedDefs)}, |
2793 | | translate_set_pref_defs1(SortedDefs). |
2794 | | translate_set_pref_defs1([]) --> !. |
2795 | | translate_set_pref_defs1([Def|Rest]) --> |
2796 | | translate_set_pref_def(Def),translate_set_pref_defs1(Rest). |
2797 | | translate_set_pref_def(definition_decl(Name,_,_Pos,[],_Expr,_Deps)) --> |
2798 | | {is_set_pref_def_name(Name,_Pref,CurValAtom)},!, |
2799 | | insertstr(' '),insertstr(Name), |
2800 | | insertstr(' '), |
2801 | | {translate_in_mode(eqeq,'==',EqEqStr)}, insertstr(EqEqStr), insertstr(' '), |
2802 | | insertstr(CurValAtom), % pretty print current value; Expr could be a more complicated non-atomic expression |
2803 | | insertstr(';\n'). |
2804 | | translate_set_pref_def(_) --> []. |
2805 | | |
2806 | | standard_library_required(Defs,Library) :- |
2807 | | member(Decl,Defs), |
2808 | | definition_decl_from_library(Decl,Library). |
2809 | | |
2810 | | % TODO: we could also look in the list of loaded files and search for standard libraries |
2811 | | definition_decl_from_library(definition_decl(printf,predicate,_,[_,_],_,_Deps),'LibraryIO.def'). |
2812 | | definition_decl_from_library(definition_decl('STRING_IS_DECIMAL',predicate,_,[_],_,_Deps),'LibraryStrings.def'). |
2813 | | definition_decl_from_library(definition_decl('SHA_HASH',expression,_,[_],_,_Deps),'LibraryHash.def'). |
2814 | | definition_decl_from_library(definition_decl('CHOOSE',expression,_,[_],_,_Deps),'CHOOSE.def'). |
2815 | | definition_decl_from_library(definition_decl('SCCS',expression,_,[_],_,_Deps),'SCCS.def'). |
2816 | | definition_decl_from_library(definition_decl('SORT',expression,_,[_],_,_Deps),'SORT.def'). |
2817 | | definition_decl_from_library(definition_decl('random_element',expression,_,[_],_,_Deps),'LibraryRandom.def'). |
2818 | | definition_decl_from_library(definition_decl('SIN',expression,_,[_],_,_Deps),'LibraryMath.def'). |
2819 | | definition_decl_from_library(definition_decl('RMUL',expression,_,[_,_],_,_Deps),'LibraryReals.def'). |
2820 | | definition_decl_from_library(definition_decl('REGEX_MATCH',predicate,_,[_,_],_,_Deps),'LibraryRegex.def'). |
2821 | | definition_decl_from_library(definition_decl('ASSERT_EXPR',expression,_,[_,_,_],_,_Deps),'LibraryProB.def'). |
2822 | | definition_decl_from_library(definition_decl('svg_points',expression,_,[_],_,_Deps),'LibrarySVG.def'). |
2823 | | definition_decl_from_library(definition_decl('FULL_FILES',expression,_,[_],_,_Deps),'LibraryFiles.def'). |
2824 | | definition_decl_from_library(definition_decl('READ_XML_FROM_STRING',expression,_,[_],_,_Deps),'LibraryXML.def'). |
2825 | | definition_decl_from_library(definition_decl('READ_CSV',expression,_,[_],_,_Deps),'LibraryCSV.def'). |
2826 | | |
2827 | | insert_library_usages([]) --> []. |
2828 | | insert_library_usages([Library|T]) --> |
2829 | | insertstr(' "'),insertstr(Library),insertstr('";\n'), % insert inclusion of ProB standard library |
2830 | | insert_library_usages(T). |
2831 | | |
2832 | | % ------------- RAW EXPRESSIONS |
2833 | | |
2834 | | % try and print raw machine term or parts thereof (e.g. sections) |
2835 | | print_raw_machine_terms(Var) :- var(Var), !,print('VAR !!'),nl. |
2836 | | print_raw_machine_terms([]) :- !. |
2837 | | print_raw_machine_terms([H|T]) :- !, |
2838 | | print_raw_machine_terms(H), print(' '), |
2839 | | print_raw_machine_terms(T). |
2840 | | print_raw_machine_terms(Term) :- raw_machine_term(Term,String,Sub),!, |
2841 | | format('~n~w ',[String]), |
2842 | | print_raw_machine_terms(Sub),nl. |
2843 | | print_raw_machine_terms(expression_definition(A,B,C,D)) :- !, |
2844 | | print_raw_machine_terms(predicate_definition(A,B,C,D)). |
2845 | | print_raw_machine_terms(substitution_definition(A,B,C,D)) :- !, |
2846 | | print_raw_machine_terms(predicate_definition(A,B,C,D)). |
2847 | | print_raw_machine_terms(predicate_definition(_,Name,Paras,RHS)) :- |
2848 | | Paras==[],!, |
2849 | | format('~n ~w == ',[Name]), |
2850 | | print_raw_machine_terms(RHS),nl. |
2851 | | print_raw_machine_terms(predicate_definition(_,Name,Paras,RHS)) :- !, |
2852 | | format('~n ~w(',[Name]), |
2853 | | print_raw_machine_terms_sep(Paras,','), |
2854 | | format(') == ',[]), |
2855 | | print_raw_machine_terms(RHS),nl. |
2856 | | print_raw_machine_terms(operation(_,Name,Return,Paras,RHS)) :- !, |
2857 | | format('~n ',[]), |
2858 | | (Return=[] -> true |
2859 | | ; print_raw_machine_terms_sep(Return,','), |
2860 | | format(' <-- ',[]) |
2861 | | ), |
2862 | | print_raw_machine_terms(Name), |
2863 | | (Paras=[] -> true |
2864 | | ; format(' (',[]), |
2865 | | print_raw_machine_terms_sep(Paras,','), |
2866 | | format(')',[]) |
2867 | | ), |
2868 | | format(' = ',[]), |
2869 | | print_raw_machine_terms(RHS),nl. |
2870 | | print_raw_machine_terms(Term) :- print_raw_bexpr(Term). |
2871 | | |
2872 | | |
2873 | | print_raw_machine_terms_sep([],_) :- !. |
2874 | | print_raw_machine_terms_sep([H],_) :- !, |
2875 | | print_raw_machine_terms(H). |
2876 | | print_raw_machine_terms_sep([H|T],Sep) :- !, |
2877 | | print_raw_machine_terms(H),print(Sep),print_raw_machine_terms_sep(T,Sep). |
2878 | | |
2879 | | raw_machine_term(machine(M),'',M). |
2880 | | raw_machine_term(generated(_,M),'',M). |
2881 | | raw_machine_term(machine_header(_,Name,_Params),Name,[]). % TO DO: treat Params |
2882 | | raw_machine_term(abstract_machine(_,_,Header,M),'MACHINE',[Header,M]). |
2883 | | raw_machine_term(properties(_,P),'PROPERTIES',P). |
2884 | | raw_machine_term(operations(_,P),'OPERATIONS',P). |
2885 | | raw_machine_term(definitions(_,P),'DEFINITIONS',P). |
2886 | | raw_machine_term(constants(_,P),'CONSTANTS',P). |
2887 | | raw_machine_term(variables(_,P),'VARIABLES',P). |
2888 | | raw_machine_term(invariant(_,P),'INVARIANT',P). |
2889 | | raw_machine_term(assertions(_,P),'ASSERTIONS',P). |
2890 | | raw_machine_term(constraints(_,P),'CONSTRAINTS',P). |
2891 | | raw_machine_term(sets(_,P),'SETS',P). |
2892 | | raw_machine_term(deferred_set(_,P),P,[]). % TO DO: enumerated_set ... |
2893 | | %raw_machine_term(identifier(_,P),P,[]). |
2894 | | |
2895 | | l_print_raw_bexpr([]). |
2896 | | l_print_raw_bexpr([Raw|T]) :- write(' '), |
2897 | | print_raw_bexpr(Raw),nl, l_print_raw_bexpr(T). |
2898 | | |
2899 | | print_raw_bexpr(Raw) :- % a tool (not perfect) to print raw ASTs |
2900 | | transform_raw(Raw,TExpr),!, |
2901 | | print_bexpr_or_subst(TExpr). |
2902 | | |
2903 | | translate_raw_bexpr_with_limit(Raw,Limit,TS) :- transform_raw(Raw,TExpr), |
2904 | | translate_subst_or_bexpr_with_limit(TExpr,Limit,TS). |
2905 | | |
2906 | | transform_raw_list(Var,Res) :- var(Var),!, |
2907 | | add_internal_error('Var raw expression list:',transform_raw_list(Var,Res)), |
2908 | | Res= [b(identifier('$$VARIABLE_LIST$$'),any,[raw])]. |
2909 | | transform_raw_list(Args,TArgs) :- maplist(transform_raw,Args,TArgs). |
2910 | | |
2911 | | |
2912 | | transform_raw(Var,Res) :- %print(raw(Var)),nl, |
2913 | | var(Var), !, add_internal_error('Var raw expression:',transform_raw(Var,Res)), |
2914 | | Res= b(identifier('$$VARIABLE$$'),any,[raw]). |
2915 | | transform_raw(precondition(_,Pre,Body),Res) :- !, Res= b(precondition(TP,TB),subst,[raw]), |
2916 | | transform_raw(Pre,TP), |
2917 | | transform_raw(Body,TB). |
2918 | | transform_raw(typeof(_,E,_Type),Res) :- !, transform_raw(E,Res). % remove typeof operator; TODO: transform |
2919 | | transform_raw(identifier(_,M),Res) :- !, Res= b(identifier(M),any,[raw]). |
2920 | | transform_raw(integer(_,M),Res) :- !, Res= b(integer(M),integer,[raw]). |
2921 | | % rules from btype_rewrite2: |
2922 | | transform_raw(integer_set(_),Res) :- !, generate_typed_int_set('INTEGER',Res). |
2923 | | transform_raw(natural_set(_),Res) :- !, generate_typed_int_set('NATURAL',Res). |
2924 | | transform_raw(natural1_set(_),Res) :- !, generate_typed_int_set('NATURAL1',Res). |
2925 | | transform_raw(nat_set(_),Res) :- !, generate_typed_int_set('NAT',Res). |
2926 | | transform_raw(nat1_set(_),Res) :- !, generate_typed_int_set('NAT1',Res). |
2927 | | transform_raw(int_set(_),Res) :- !, generate_typed_int_set('INT',Res). |
2928 | | transform_raw(let_expression(_,_Ids,Eq,Body),Res) :- !, |
2929 | | transform_raw(conjunct(_,Eq,Body),Res). % TO DO: fix and generate let_expression(Ids,ListofExprs,Body) |
2930 | | transform_raw(let_predicate(_,_Ids,Eq,Body),Res) :- !, |
2931 | | transform_raw(conjunct(_,Eq,Body),Res). % ditto |
2932 | | transform_raw(forall(_,Ids,Body),Res) :- !, |
2933 | | (Body=implication(_,LHS,RHS) -> true ; LHS=truth,RHS=Body), |
2934 | | transform_raw(forall(_,Ids,LHS,RHS),Res). |
2935 | | transform_raw(record_field(_,Rec,identifier(_,Field)),Res) :- !, Res = b(record_field(TRec,Field),any,[]), |
2936 | | transform_raw(Rec,TRec). |
2937 | | transform_raw(rec_entry(_,identifier(_,Field),Rec),Res) :- !, Res = field(Field,TRec), |
2938 | | transform_raw(Rec,TRec). |
2939 | | transform_raw(conjunct(_,List),Res) :- !, |
2940 | | transform_raw_list_to_conjunct(List,Res). % sometimes conjunct/1 with list is used (e.g., .eventb files) |
2941 | | transform_raw(couple(_,L),Res) :- !, transform_raw_list_to_couple(L,Res). % couples are represented by lists |
2942 | | transform_raw(extended_expr(Pos,Op,L,_TypeParas),Res) :- !, |
2943 | | (L=[] -> transform_raw(identifier(none,Op),Res) % no arguments |
2944 | | ; transform_raw(function(Pos,identifier(none,Op),L),Res)). |
2945 | | transform_raw(extended_pred(Pos,Op,L,_TypeParas),Res) :- !, |
2946 | | transform_raw(function(Pos,identifier(none,Op),L),Res). % not of correct type pred, but seems to work |
2947 | | transform_raw(external_function_call_auto(Pos,Name,Para),Res) :- !, |
2948 | | transform_raw(external_function_call(Pos,Name,Para),Res). % we assume expr rather than pred and hope for the best |
2949 | | transform_raw(function(_,F,L),Res) :- !, transform_raw(F,TF), |
2950 | | Res = b(function(TF,Args),any,[]), |
2951 | | transform_raw_list_to_couple(L,Args). % args are represented by lists |
2952 | | transform_raw(Atom,Res) :- atomic(Atom),!,Res=Atom. |
2953 | | transform_raw([H|T],Res) :- !, maplist(transform_raw,[H|T],Res). |
2954 | | transform_raw(Symbolic,Res) :- symbolic_raw(Symbolic,Body),!, |
2955 | | transform_raw(Body,Res). |
2956 | | transform_raw(OtherOp,b(Res,Type,[])) :- OtherOp =..[F,_Pos|Rest], |
2957 | | maplist(transform_raw,Rest,TRest), |
2958 | | (get_type(F,FT) -> Type=FT ; Type=any), |
2959 | | Res =.. [F|TRest]. |
2960 | | transform_raw_list_to_couple([R],Res) :- !, transform_raw(R,Res). |
2961 | | transform_raw_list_to_couple([R1|T],Res) :- !, Res=b(couple(TR1,TT),any,[]), |
2962 | | transform_raw(R1,TR1),transform_raw_list_to_couple(T,TT). |
2963 | | transform_raw_list_to_conjunct([R],Res) :- !, transform_raw(R,Res). |
2964 | | transform_raw_list_to_conjunct([R1|T],Res) :- !, Res=b(conjunct(TR1,TT),pred,[]), |
2965 | | transform_raw(R1,TR1),transform_raw_list_to_conjunct(T,TT). |
2966 | | generate_typed_int_set(Name,b(integer_set(Name),set(integer),[])). |
2967 | | get_type(conjunct,pred). |
2968 | | get_type(disjunct,pred). |
2969 | | get_type(implication,pred). |
2970 | | get_type(equivalence,pred). |
2971 | | get_type(member,pred). |
2972 | | get_type(equal,pred). |
2973 | | get_type(not_equal,pred). |
2974 | | get_type(not_member,pred). |
2975 | | get_type(subset,pred). |
2976 | | get_type(not_subset,pred). |
2977 | | |
2978 | | symbolic_raw(symbolic_composition(A,B,C),composition(A,B,C)). |
2979 | | symbolic_raw(symbolic_comprehension_set(A,B,C),comprehension_set(A,B,C)). |
2980 | | symbolic_raw(symbolic_event_b_comprehension_set(A,B,C,D),eventb_comprehension_set(A,B,C,D)). |
2981 | | symbolic_raw(symbolic_lambda(A,B,C,D),lambda(A,B,C,D)). |
2982 | | symbolic_raw(symbolic_quantified_union(A,B,C,D),quantified_union(A,B,C,D)). |
2983 | | |
2984 | | % ------------- |
2985 | | |
2986 | | |
2987 | | % pretty-print the operations of a machine |
2988 | | translate_ops([]) --> !. |
2989 | | translate_ops([Op|Rest]) --> |
2990 | | translate_op(Op), |
2991 | | ({Rest=[]} -> {true}; insertstr(';'),indent), |
2992 | | translate_ops(Rest). |
2993 | | translate_op(Op) --> |
2994 | | { get_texpr_expr(Op,operation(Id,Res,Params,Body)) }, |
2995 | | translate_operation(Id,Res,Params,Body). |
2996 | | translate_operation(Id,Res,Params,Body) --> |
2997 | | indent,translate_op_results(Res), |
2998 | | pp_expr_indent(Id), |
2999 | | translate_op_params(Params), |
3000 | | insertstr(' = '), |
3001 | | indention_level(I1,I2),{I2 is I1+2,type_infos_in_subst(Params,Body,Body2)}, |
3002 | | translate_subst_begin_end(Body2), |
3003 | | pp_description_pragma_of(Body2), |
3004 | | indention_level(_,I1). |
3005 | | translate_op_results([]) --> !. |
3006 | | translate_op_results(Ids) --> pp_expr_indent_l(Ids), insertstr(' <-- '). |
3007 | | translate_op_params([]) --> !. |
3008 | | translate_op_params(Ids) --> insertstr('('),pp_expr_indent_l(Ids), insertstr(')'). |
3009 | | |
3010 | | translate_subst_begin_end(TSubst) --> |
3011 | | {get_texpr_expr(TSubst,Subst),subst_needs_begin_end(Subst), |
3012 | | create_texpr(block(TSubst),subst,[],Block)},!, |
3013 | | translate_subst(Block). |
3014 | | translate_subst_begin_end(Subst) --> |
3015 | | translate_subst(Subst). |
3016 | | |
3017 | | subst_needs_begin_end(assign(_,_)). |
3018 | | subst_needs_begin_end(assign_single_id(_,_)). |
3019 | | subst_needs_begin_end(parallel(_)). |
3020 | | subst_needs_begin_end(sequence(_)). |
3021 | | subst_needs_begin_end(operation_call(_,_,_)). |
3022 | | |
3023 | | type_infos_in_subst([],Subst,Subst) :- !. |
3024 | | type_infos_in_subst(Ids,SubstIn,SubstOut) :- |
3025 | | get_preference(translate_print_typing_infos,true),!, |
3026 | | type_infos_in_subst2(Ids,SubstIn,SubstOut). |
3027 | | type_infos_in_subst(_Ids,Subst,Subst). |
3028 | | type_infos_in_subst2(Ids,SubstIn,SubstOut) :- |
3029 | | get_texpr_expr(SubstIn,precondition(P1,S)),!, |
3030 | | get_texpr_info(SubstIn,Info), |
3031 | | create_texpr(precondition(P2,S),pred,Info,SubstOut), |
3032 | | add_typing_predicates(Ids,P1,P2). |
3033 | | type_infos_in_subst2(Ids,SubstIn,SubstOut) :- |
3034 | | create_texpr(precondition(P,SubstIn),pred,[],SubstOut), |
3035 | | generate_typing_predicates(Ids,Typing), |
3036 | | conjunct_predicates(Typing,P). |
3037 | | |
3038 | | |
3039 | | |
3040 | | |
3041 | | |
3042 | | % pretty-print the internal section about included and used machines |
3043 | | translate_used([]) --> !. |
3044 | | translate_used([Used|Rest]) --> |
3045 | | translate_used2(Used), |
3046 | | translate_used(Rest). |
3047 | | translate_used2(includeduse(Name,Id,NewTExpr)) --> |
3048 | | indent,pp_expr_indent(NewTExpr), |
3049 | | insertstr(' --> '), insertstr(Name), insertstr(':'), insertstr(Id). |
3050 | | |
3051 | | % pretty-print the internal information about freetypes |
3052 | | translate_freetypes([]) --> !. |
3053 | | translate_freetypes([Freetype|Frest]) --> |
3054 | | translate_freetype(Freetype), |
3055 | | translate_freetypes(Frest). |
3056 | | translate_freetype(freetype(Name,Cases)) --> |
3057 | | {pretty_freetype(Name,PName)}, |
3058 | | indent(PName),insertstr('= '), |
3059 | | indention_level(I1,I2),{I2 is I1+2}, |
3060 | | translate_freetype_cases(Cases), |
3061 | | indention_level(_,I1). |
3062 | | translate_freetype_cases([]) --> !. |
3063 | | translate_freetype_cases([case(Name,Type)|Rest]) --> {nonvar(Type),Type=constant(_)}, |
3064 | | !,indent(Name),insert_comma(Rest), |
3065 | | translate_freetype_cases(Rest). |
3066 | | translate_freetype_cases([case(Name,Type)|Rest]) --> |
3067 | | {pretty_type(Type,PT)}, |
3068 | | indent(Name), |
3069 | | insertstr('('),insertstr(PT),insertstr(')'), |
3070 | | insert_comma(Rest), |
3071 | | translate_freetype_cases(Rest). |
3072 | | |
3073 | | insert_comma([]) --> []. |
3074 | | insert_comma([_|_]) --> insertstr(','). |
3075 | | |
3076 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3077 | | % substitutions |
3078 | | |
3079 | | translate_subst_or_bexpr(Stmt,String) :- get_texpr_type(Stmt,subst),!, |
3080 | | translate_substitution(Stmt,String). |
3081 | | translate_subst_or_bexpr(ExprOrPred,String) :- |
3082 | | translate_bexpression(ExprOrPred,String). |
3083 | | |
3084 | | translate_subst_or_bexpr_with_limit(Stmt,Limit,String) :- |
3085 | | translate_subst_or_bexpr_with_limit(Stmt,Limit,report_errors,String). |
3086 | | translate_subst_or_bexpr_with_limit(Stmt,_Limit,ReportErrors,String) :- get_texpr_type(Stmt,subst),!, |
3087 | | translate_substitution(Stmt,String,ReportErrors). % TO DO: use limit |
3088 | | translate_subst_or_bexpr_with_limit(ExprOrPred,Limit,ReportErrors,String) :- |
3089 | | translate_bexpression_with_limit(ExprOrPred,Limit,ReportErrors,String). |
3090 | | |
3091 | | print_subst(Stmt) :- translate_substitution(Stmt,T), print(T). |
3092 | | translate_substitution(Stmt,String) :- translate_substitution(Stmt,String,report_errors). |
3093 | | translate_substitution(Stmt,String,_) :- |
3094 | | translate_subst_with_indention(Stmt,0,Codes,[]), |
3095 | | (Codes = [10|C] -> true ; Codes=[13|C] -> true ; Codes=C), % peel off leading newline |
3096 | | atom_codes_with_limit(String, C),!. |
3097 | | translate_substitution(Stmt,String,report_errors) :- |
3098 | | add_error(translate_substitution,'Could not translate substitution: ',Stmt), |
3099 | | String='???'. |
3100 | | |
3101 | | translate_subst_with_indention(TS,Indention,I,O) :- |
3102 | | translate_subst(TS,(Indention,I),(_,O)). |
3103 | | translate_subst_with_indention_and_label(TS,Indention,I,O) :- |
3104 | | translate_subst_with_label(TS,(Indention,I),(_,O)). |
3105 | | |
3106 | | translate_subst(TS) --> |
3107 | | ( {get_texpr_expr(TS,S)} -> |
3108 | | translate_subst2(S) |
3109 | | ; translate_subst2(TS)). |
3110 | | |
3111 | | translate_subst_with_label(TS) --> |
3112 | | ( {get_texpr_expr(TS,S)} -> |
3113 | | indent_rodin_label(TS), % pretty print substitution labels |
3114 | | translate_subst2(S) |
3115 | | ; translate_subst2(TS)). |
3116 | | |
3117 | | % will print (first) rodin or pragma label indendent |
3118 | | :- public indent_rodin_label/3. |
3119 | | indent_rodin_label(_TExpr) --> {get_preference(translate_suppress_rodin_positions_flag,true),!}. |
3120 | | indent_rodin_label(_TExpr) --> {get_preference(bugly_pp_scrambling,true),!}. |
3121 | | indent_rodin_label(TExpr) --> {get_texpr_labels(TExpr,Names)},!, % note: this will only get the first label |
3122 | | indent('/* @'),pp_ids_indent(Names),insertstr('*/ '). % this Camille syntax cannot be read back in by B parser |
3123 | | indent_rodin_label(_TExpr) --> []. |
3124 | | |
3125 | | pp_ids_indent([]) --> !, []. |
3126 | | pp_ids_indent([ID]) --> !,pp_expr_indent(identifier(ID)). |
3127 | | pp_ids_indent([ID|T]) --> !,pp_expr_indent(identifier(ID)), insertstr(' '),pp_ids_indent(T). |
3128 | | pp_ids_indent(X) --> {add_error(pp_ids_indent,'Not a list of atoms: ',pp_ids_indent(X))}. |
3129 | | |
3130 | | translate_subst2(Var) --> {var(Var)}, !, "_", {add_warning(translate_subst,'Variable subst:',Var)}. |
3131 | | translate_subst2(skip) --> |
3132 | | indent(skip). |
3133 | | translate_subst2(operation(Id,Res,Params,Body)) --> translate_operation(Id,Res,Params,Body). % not really a substition that can appear normally |
3134 | | translate_subst2(precondition(P,S)) --> |
3135 | | indent('PRE '), pred_over_lines(2,'@grd',P), indent('THEN'), insert_subst(S), indent('END'). |
3136 | | translate_subst2(assertion(P,S)) --> |
3137 | | indent('ASSERT '), pp_expr_indent(P), indent('THEN'), insert_subst(S), indent('END'). |
3138 | | translate_subst2(witness_then(P,S)) --> |
3139 | | indent('WITNESS '), pp_expr_indent(P), indent('THEN'), insert_subst(S), indent('END'). |
3140 | | translate_subst2(block(S)) --> |
3141 | | indent('BEGIN'), insert_subst(S), indent('END'). |
3142 | | translate_subst2(assign([L],[R])) --> !, |
3143 | | indent,pp_expr_indent(L),insertstr(' := '),pp_expr_indent(R). |
3144 | | translate_subst2(assign(L,R)) --> |
3145 | | {(member(b(E,_,_),R), can_indent_expr(E) |
3146 | | -> maplist(create_assign,L,R,ParAssigns))},!, % split into parallel assignments so that we can indent |
3147 | | translate_subst2(parallel(ParAssigns)). |
3148 | | translate_subst2(assign(L,R)) --> |
3149 | | indent,pp_expr_indent_l(L),insertstr(' := '),pp_expr_indent_l(R). |
3150 | | translate_subst2(assign_single_id(L,R)) --> |
3151 | | translate_subst2(assign([L],[R])). |
3152 | | translate_subst2(becomes_element_of(L,R)) --> |
3153 | | indent,pp_expr_indent_l(L),insertstr(' :: '),pp_expr_indent(R). |
3154 | | translate_subst2(becomes_such(L,R)) --> |
3155 | | indent,pp_expr_indent_l(L),insertstr(' : '), insertstr('('), |
3156 | | { add_optional_typing_predicates(L,R,R1) }, |
3157 | | pp_expr_indent(R1), insertstr(')'). |
3158 | | translate_subst2(evb2_becomes_such(L,R)) --> translate_subst2(becomes_such(L,R)). |
3159 | | translate_subst2(if([Elsif|Rest])) --> |
3160 | | { get_if_elsif(Elsif,P,S) }, |
3161 | | indent('IF '), pp_expr_indent(P), insertstr(' THEN'), |
3162 | | insert_subst(S), |
3163 | | translate_ifs(Rest). |
3164 | | translate_subst2(if_elsif(P,S)) --> % not a legal top-level construct; but can be called in b_portray_hook |
3165 | | indent('IF '), pp_expr_indent(P), insertstr(' THEN'), |
3166 | | insert_subst(S), |
3167 | | indent('END'). |
3168 | | translate_subst2(choice(Ss)) --> indent(' CHOICE'), |
3169 | | split_over_lines(Ss,'OR'), |
3170 | | indent('END'). % indentation seems too far |
3171 | | translate_subst2(parallel(Ss)) --> |
3172 | | split_over_lines(Ss,'||'). |
3173 | | translate_subst2(init_statement(S)) --> insert_subst(S). |
3174 | | translate_subst2(sequence(Ss)) --> |
3175 | | split_over_lines(Ss,';'). |
3176 | | translate_subst2(operation_call(Id,Rs,As)) --> |
3177 | | indent,translate_op_results(Rs), |
3178 | | pp_expr_indent(Id), |
3179 | | translate_op_params(As). |
3180 | | translate_subst2(identifier(op(Id))) --> % shouldn't normally appear |
3181 | | indent,pp_expr_indent(identifier(Id)). |
3182 | | translate_subst2(external_subst_call(Symbol,Args)) --> |
3183 | | indent, |
3184 | | pp_expr_indent(identifier(Symbol)), |
3185 | | translate_op_params(Args). |
3186 | | translate_subst2(any(Ids,Pred,Subst)) --> |
3187 | | indent('ANY '), pp_expr_indent_l(Ids), |
3188 | | indent('WHERE '), |
3189 | | {add_optional_typing_predicates(Ids,Pred,Pred2)}, |
3190 | | pred_over_lines(2,'@grd',Pred2), indent('THEN'), |
3191 | | insert_subst(Subst), |
3192 | | indent('END'). |
3193 | | translate_subst2(select(Whens)) --> |
3194 | | translate_whens(Whens,'SELECT '), |
3195 | | indent('END'). |
3196 | | translate_subst2(select_when(Cond,Then)) --> % not a legal top-level construct; but can be called in b_portray_hook |
3197 | | indent('WHEN'), |
3198 | | pp_expr_indent(Cond), |
3199 | | indent('THEN'), |
3200 | | insert_subst(Then), |
3201 | | indent('END'). |
3202 | | translate_subst2(select(Whens,Else)) --> |
3203 | | translate_whens(Whens,'SELECT '), |
3204 | | indent('ELSE'), insert_subst(Else), |
3205 | | indent('END'). |
3206 | | translate_subst2(var(Ids,S)) --> |
3207 | | indent('VAR '), |
3208 | | pp_expr_indent_l(Ids), |
3209 | | indent('IN'),insert_subst(S), |
3210 | | indent('END'). |
3211 | | translate_subst2(let(Ids,P,S)) --> |
3212 | | indent('LET '), |
3213 | | pp_expr_indent_l(Ids), |
3214 | | insertstr(' BE '), pp_expr_indent(P), |
3215 | | indent('IN'), insert_subst(S), |
3216 | | indent('END'). |
3217 | | translate_subst2(lazy_let_subst(TID,P,S)) --> |
3218 | | indent('LET '), |
3219 | | pp_expr_indent_l([TID]), |
3220 | | insertstr(' BE '), pp_expr_indent(P), % could be expr or pred |
3221 | | indent('IN'), insert_subst(S), |
3222 | | indent('END'). |
3223 | | translate_subst2(case(Expression,Cases,ELSE)) --> |
3224 | | % CASE E OF EITHER m THEN G OR n THEN H ... ELSE I END END |
3225 | | indent('CASE '), |
3226 | | pp_expr_indent(Expression), insertstr(' OF'), |
3227 | | indent('EITHER '), translate_cases(Cases), |
3228 | | indent('ELSE '), insert_subst(ELSE), % we could drop this if ELSE is skip ? |
3229 | | indent('END END'). |
3230 | | translate_subst2(while(Pred,Subst,Inv,Var)) --> |
3231 | | indent('WHILE '), pp_expr_indent(Pred), |
3232 | | indent('DO'),insert_subst(Subst), |
3233 | | indent('INVARIANT '),pp_expr_indent(Inv), |
3234 | | indent('VARIANT '),pp_expr_indent(Var), |
3235 | | indent('END'). |
3236 | | translate_subst2(while1(Pred,Subst,Inv,Var)) --> |
3237 | | indent('WHILE /* 1 */ '), pp_expr_indent(Pred), |
3238 | | indent('DO'),insert_subst(Subst), |
3239 | | indent('INVARIANT '),pp_expr_indent(Inv), |
3240 | | indent('VARIANT '),pp_expr_indent(Var), |
3241 | | indent('END'). |
3242 | | translate_subst2(rlevent(Id,Section,Status,Parameters,Guard,Theorems,Actions,VWitnesses,PWitnesses,_Unmod,Refines)) --> |
3243 | | indent, |
3244 | | insert_status(Status), |
3245 | | insertstr('EVENT '), |
3246 | | ({Id = 'INITIALISATION'} |
3247 | | -> [] % avoid BLexer error in ProB2-UI, BLexerException: Invalid combination of symbols: 'INITIALISATION' and '='. |
3248 | | ; insertstr(Id), insertstr(' = ')), |
3249 | | insertstr('/'), insertstr('* of machine '), |
3250 | | insertstr(Section),insertstr(' */'), |
3251 | | insert_variant(Status), |
3252 | | ( {Parameters=[], get_texpr_expr(Guard,truth)} -> |
3253 | | {NoGuard=true} % indent('BEGIN ') |
3254 | | ; {Parameters=[]} -> |
3255 | | indent('WHEN '), |
3256 | | pred_over_lines(2,'@grd',Guard) |
3257 | | ; |
3258 | | indent('ANY '),pp_expr_indent_l(Parameters), |
3259 | | indent('WHERE '), |
3260 | | pred_over_lines(2,'@grd',Guard) |
3261 | | ), |
3262 | | ( {VWitnesses=[],PWitnesses=[]} -> |
3263 | | [] |
3264 | | ; |
3265 | | {append(VWitnesses,PWitnesses,Witnesses)}, |
3266 | | indent('WITH '),pp_witness_l(Witnesses) |
3267 | | ), |
3268 | | {( Actions=[] -> |
3269 | | create_texpr(skip,subst,[],Subst) |
3270 | | ; |
3271 | | create_texpr(parallel(Actions),subst,[],Subst) |
3272 | | )}, |
3273 | | ( {Theorems=[]} -> {true} |
3274 | | ; |
3275 | | indent('THEOREMS '), |
3276 | | preds_over_lines(2,'@thm',Theorems) |
3277 | | ), |
3278 | | ({NoGuard==true} |
3279 | | -> indent('BEGIN ') % avoid BLexer errors in ProB2-UI Syntax highlighting |
3280 | | ; indent('THEN ') |
3281 | | ), |
3282 | | insert_subst(Subst), |
3283 | | pp_refines_l(Refines,Id), |
3284 | | indent('END'). |
3285 | | |
3286 | | % translate cases of a CASE statement |
3287 | | translate_cases([]) --> !,[]. |
3288 | | translate_cases([CaseOr|T]) --> |
3289 | | {get_texpr_expr(CaseOr,case_or(Exprs,Subst))},!, |
3290 | | pp_expr_indent_l(Exprs), |
3291 | | insertstr(' THEN '), |
3292 | | insert_subst(Subst), |
3293 | | ({T==[]} -> {true} |
3294 | | ; indent('OR '), translate_cases(T)). |
3295 | | translate_cases(L) --> |
3296 | | {add_internal_error('Cannot translate CASE list: ',translate_cases(L,_,_))}. |
3297 | | |
3298 | | insert_status(TStatus) --> |
3299 | | {get_texpr_expr(TStatus,Status), |
3300 | | status_string(Status,String)}, |
3301 | | insertstr(String). |
3302 | | status_string(ordinary,''). |
3303 | | status_string(anticipated(_),'ANTICIPATED '). |
3304 | | status_string(convergent(_),'CONVERGENT '). |
3305 | | |
3306 | | insert_variant(TStatus) --> |
3307 | | {get_texpr_expr(TStatus,Status)}, |
3308 | | insert_variant2(Status). |
3309 | | insert_variant2(ordinary) --> !. |
3310 | | insert_variant2(anticipated(Variant)) --> insert_variant3(Variant). |
3311 | | insert_variant2(convergent(Variant)) --> insert_variant3(Variant). |
3312 | | insert_variant3(Variant) --> |
3313 | | indent('USING VARIANT '),pp_expr_indent(Variant). |
3314 | | |
3315 | | pp_refines_l([],_) --> []. |
3316 | | pp_refines_l([Ref|Rest],Id) --> |
3317 | | pp_refines(Ref,Id),pp_refines_l(Rest,Id). |
3318 | | pp_refines(Refined,_Id) --> |
3319 | | % indent(Id), insertstr(' REFINES '), |
3320 | | indent('REFINES '), |
3321 | | insert_subst(Refined). |
3322 | | |
3323 | | pp_witness_l([]) --> []. |
3324 | | pp_witness_l([Witness|WRest]) --> |
3325 | | pp_witness(Witness),pp_witness_l(WRest). |
3326 | | pp_witness(Expr) --> |
3327 | | indention_level(I1,I2), |
3328 | | {get_texpr_expr(Expr,witness(Id,Pred)), |
3329 | | I2 is I1+2}, |
3330 | | indent, pp_expr_indent(Id), insertstr(': '), |
3331 | | pp_expr_indent(Pred), |
3332 | | indention_level(_,I1). |
3333 | | |
3334 | | |
3335 | | translate_whens([],_) --> !. |
3336 | | translate_whens([When|Rest],T) --> |
3337 | | {get_texpr_expr(When,select_when(P,S))},!, |
3338 | | indent(T), pred_over_lines(2,'@grd',P), |
3339 | | indent('THEN '), |
3340 | | insert_subst(S), |
3341 | | translate_whens(Rest,'WHEN '). |
3342 | | translate_whens(L,_) --> |
3343 | | {add_internal_error('Cannot translate WHEN: ',translate_whens(L,_,_,_))}. |
3344 | | |
3345 | | |
3346 | | |
3347 | | create_assign(LHS,RHS,b(assign([LHS],[RHS]),subst,[])). |
3348 | | |
3349 | | split_over_lines([],_) --> !. |
3350 | | split_over_lines([S|Rest],Symbol) --> !, |
3351 | | indention_level(I1,I2),{atom_codes(Symbol,X),length(X,N),I2 is I1+N+1}, |
3352 | | translate_subst_check(S), |
3353 | | split_over_lines2(Rest,Symbol,I1,I2). |
3354 | | split_over_lines(S,Symbol) --> {add_error(split_over_lines,'Illegal argument: ',Symbol:S)}. |
3355 | | |
3356 | | split_over_lines2([],_,_,_) --> !. |
3357 | | split_over_lines2([S|Rest],Symbol,I1,I2) --> |
3358 | | indention_level(_,I1), indent(Symbol), |
3359 | | indention_level(_,I2), translate_subst(S), |
3360 | | split_over_lines2(Rest,Symbol,I1,I2). |
3361 | | |
3362 | | % print a predicate over several lines, at most one conjunct per line |
3363 | | % N is the increment that should be added to the indentation |
3364 | | %pred_over_lines(N,Pred) --> pred_over_lines(N,'@pred',Pred). |
3365 | | pred_over_lines(N,Lbl,Pred) --> |
3366 | | {conjunction_to_list(Pred,List)}, |
3367 | | preds_over_lines(N,Lbl,List). |
3368 | | section_pred_over_lines(N,Title,Pred) --> |
3369 | | ({get_eventb_default_label(Title,Lbl)} -> [] ; {Lbl='@pred'}), |
3370 | | pred_over_lines(N,Lbl,Pred). |
3371 | | get_eventb_default_label(properties,'@axm'). |
3372 | | get_eventb_default_label(assertions,'@thm'). |
3373 | | |
3374 | | % print a list of predicates over several lines, at most one conjunct per line |
3375 | | preds_over_lines(N,Lbl,Preds) --> preds_over_lines(N,Lbl,'& ',Preds). |
3376 | | % preds_over_lines(IndentationIncrease,EventBDefaultLabel,ClassicalBSeperator,ListOfPredicates) |
3377 | | preds_over_lines(N,Lbl,Sep,Preds) --> |
3378 | | indention_level(I1,I2),{I2 is I1+N}, |
3379 | | preds_over_lines1(Preds,Lbl,1,Sep), |
3380 | | indention_level(_,I1). |
3381 | | preds_over_lines1([],Lbl,Nr,Sep) --> !, |
3382 | | preds_over_lines1([b(truth,pred,[])],Lbl,Nr,Sep). |
3383 | | preds_over_lines1([H|T],Lbl,Nr,Sep) --> |
3384 | | indent(' '), pp_label(Lbl,Nr), |
3385 | | %({T==[]} -> pp_expr_indent(H) ; pp_expr_m_indent(H,40)), |
3386 | | ({T==[]} -> pp_pred_nested(H,conjunct,0) ; pp_pred_nested(H,conjunct,40)), |
3387 | | pp_description_pragma_of(H), |
3388 | | {N1 is Nr+1}, |
3389 | | preds_over_lines2(T,Lbl,N1,Sep). |
3390 | | preds_over_lines2([],_,_,_Sep) --> !. |
3391 | | preds_over_lines2([E|Rest],Lbl,Nr,Sep) --> |
3392 | | ({force_eventb_rodin_mode} -> indent(' '), pp_label(Lbl,Nr) ; indent(Sep)), |
3393 | | pp_pred_nested(E,conjunct,40), |
3394 | | pp_description_pragma_of(E), |
3395 | | {N1 is Nr+1}, |
3396 | | preds_over_lines2(Rest,Lbl,N1,Sep). |
3397 | | |
3398 | | % print event-b label for Rodin/Camille: |
3399 | | pp_label(Lbl,Nr) --> |
3400 | | ({force_eventb_rodin_mode} |
3401 | | -> {atom_codes(Lbl,C1), number_codes(Nr,NC), append(C1,NC,AC), atom_codes(A,AC)}, |
3402 | | pp_atom_indent(A), pp_atom_indent(' ') |
3403 | | ; []). |
3404 | | |
3405 | | % a version of nested_print_bexpr / nbp that does not directly print to stream conjunct |
3406 | | pp_pred_nested(TExpr,CurrentType,_) --> {TExpr = b(E,pred,_)}, |
3407 | | {get_binary_connective(E,NewType,Ascii,LHS,RHS), binary_infix(NewType,Ascii,Prio,left)}, |
3408 | | !, |
3409 | | pp_rodin_label_indent(TExpr), % print any label |
3410 | | inc_lvl(CurrentType,NewType), |
3411 | | pp_pred_nested(LHS,NewType,Prio), |
3412 | | {translate_in_mode(NewType,Ascii,Symbol)}, |
3413 | | indent(' '),pp_atom_indent(Symbol), |
3414 | | indent(' '), |
3415 | | {(is_associative(NewType) -> NewTypeR=NewType % no need for parentheses if same operator on right |
3416 | | ; NewTypeR=right(NewType))}, |
3417 | | pp_pred_nested(RHS,NewTypeR,Prio), |
3418 | | dec_lvl(CurrentType,NewType). |
3419 | | pp_pred_nested(TExpr,_,_) --> {is_nontrivial_negation(TExpr,NExpr,InnerType,Prio)}, |
3420 | | !, |
3421 | | pp_rodin_label_indent(TExpr), % print any label |
3422 | | {translate_in_mode(negation,'not',Symbol)}, |
3423 | | pp_atom_indent(Symbol), |
3424 | | inc_lvl(other,negation), % always need parentheses for negation |
3425 | | pp_pred_nested(NExpr,InnerType,Prio), |
3426 | | dec_lvl(other,negation). |
3427 | | pp_pred_nested(TExpr,_,_) --> {TExpr = b(exists(Ids,RHS),pred,_)}, |
3428 | | !, |
3429 | | pp_rodin_label_indent(TExpr), % print any label |
3430 | | {translate_in_mode(exists,'#',FSymbol)}, |
3431 | | %indent(' '), |
3432 | | pp_atom_indent(FSymbol), |
3433 | | pp_expr_ids_in_mode_indent(Ids),pp_atom_indent('.'), |
3434 | | inc_lvl(other,conjunct), % always need parentheses here |
3435 | | {add_normal_typing_predicates(Ids,RHS,RHST), Prio=40}, % Prio of conjunction |
3436 | | pp_pred_nested(RHST,conjunct,Prio), |
3437 | | dec_lvl(other,conjunct). |
3438 | | pp_pred_nested(TExpr,_,_) --> {TExpr = b(forall(Ids,LHS,RHS),pred,_)}, |
3439 | | !, |
3440 | | pp_rodin_label_indent(TExpr), % print any label |
3441 | | {translate_in_mode(forall,'!',FSymbol)}, |
3442 | | %indent(' '), |
3443 | | pp_atom_indent(FSymbol), |
3444 | | pp_expr_ids_in_mode_indent(Ids),pp_atom_indent('.'), |
3445 | | inc_lvl(other,implication), % always need parentheses here |
3446 | | {add_normal_typing_predicates(Ids,LHS,LHST), Prio=30}, % Prio of implication |
3447 | | pp_pred_nested(LHST,implication,Prio), |
3448 | | {translate_in_mode(implication,'=>',Symbol)}, |
3449 | | indent(' '),pp_atom_indent(Symbol), |
3450 | | indent(' '), |
3451 | | pp_pred_nested(RHS,right(implication),Prio), |
3452 | | dec_lvl(other,implication). |
3453 | | pp_pred_nested(TExpr,_,_) --> |
3454 | | {\+ eventb_translation_mode, |
3455 | | TExpr = b(let_predicate(Ids,Exprs,Body),pred,_) |
3456 | | }, %Ids=[_]}, % TODO: enable printing with more than one id; see below |
3457 | | !, |
3458 | | pp_let_nested(Ids,Exprs,Body). |
3459 | | pp_pred_nested(b(BOP,pred,_),_CurrentType,CurMinPrio) --> |
3460 | | {indent_binary_predicate(BOP,LHS,RHS,OpStr), |
3461 | | get_texpr_id(LHS,_),can_indent_texpr(RHS)},!, |
3462 | | pp_expr_m_indent(LHS,CurMinPrio), |
3463 | | insertstr(OpStr), |
3464 | | increase_indentation_level(2), |
3465 | | indent(''), |
3466 | | pp_expr_indent(RHS), % only supports %, {}, bool which do not need parentheses |
3467 | | decrease_indentation_level(2). |
3468 | | pp_pred_nested(Expr,_CurrentType,CurMinPrio) --> {can_indent_texpr(Expr)},!, |
3469 | | pp_expr_m_indent(Expr,CurMinPrio). |
3470 | | pp_pred_nested(Expr,_CurrentType,CurMinPrio) --> pp_expr_m_indent(Expr,CurMinPrio). |
3471 | | |
3472 | | indent_binary_predicate(equal(LHS,RHS),LHS,RHS,' = '). |
3473 | | indent_binary_predicate(member(LHS,RHS),LHS,RHS,' : '). |
3474 | | |
3475 | | pp_let_nested(Ids,Exprs,Body) --> |
3476 | | indent('LET '), |
3477 | | pp_expr_indent_l(Ids), |
3478 | | insertstr(' BE '), |
3479 | | {maplist(create_equality,Ids,Exprs,Equalities)}, |
3480 | | preds_over_lines(2,'@let_eq',Equalities), |
3481 | | indent(' IN '), |
3482 | | increase_indentation_level(2), |
3483 | | pp_pred_nested(Body,let_predicate,40), |
3484 | | decrease_indentation_level(2), |
3485 | | indent(' END'). |
3486 | | pp_let_expr_nested(Ids,Exprs,Body) --> |
3487 | | insertstr('LET '), |
3488 | | pp_expr_indent_l(Ids), |
3489 | | insertstr(' BE '), |
3490 | | {maplist(create_equality,Ids,Exprs,Equalities)}, |
3491 | | preds_over_lines(2,'@let_eq',Equalities), |
3492 | | indent('IN '), |
3493 | | increase_indentation_level(2), |
3494 | | pp_expr_indent(Body), |
3495 | | decrease_indentation_level(2), |
3496 | | indent('END'). |
3497 | | |
3498 | | is_nontrivial_negation(b(negation(NExpr),pred,_),NExpr,NewType,Prio) :- |
3499 | | get_texpr_expr(NExpr,E), |
3500 | | (E=negation(_) -> NewType=other,Prio=0 |
3501 | | ; get_binary_connective(E,NewType,Ascii,_,_), |
3502 | | binary_infix(NewType,Ascii,Prio,_Assoc)). |
3503 | | |
3504 | | pp_rodin_label_indent(b(_,_,Infos),(I,S),(I,T)) :- pp_rodin_label(Infos,S,T). |
3505 | | % note: below we will print unnecessary parentheses in case of Atelier-B mode; but for readability it maye be better to add them |
3506 | | inc_lvl(Old,New) --> {New=Old}, !,[]. |
3507 | | inc_lvl(_,_) --> pp_atom_indent('('), % not strictly necessary if higher_prio |
3508 | | increase_indentation_level, indent(' '). |
3509 | | dec_lvl(Old,New) --> {New=Old}, !,[]. |
3510 | | dec_lvl(_,_) --> decrease_indentation_level, indent(' '),pp_atom_indent(')'). |
3511 | | |
3512 | | is_associative(conjunct). |
3513 | | is_associative(disjunct). |
3514 | | |
3515 | | %higher_prio(conjunct,implication). |
3516 | | %higher_prio(disjunct,implication). |
3517 | | % priority of equivalence changes in Rodin vs Atelier-B, maybe better add parentheses |
3518 | | |
3519 | | translate_ifs([]) --> !, |
3520 | | indent('END'). |
3521 | | translate_ifs([Elsif]) --> |
3522 | | {get_if_elsif(Elsif,P,S), |
3523 | | optional_type(P,truth)},!, |
3524 | | indent('ELSE'), insert_subst(S), indent('END'). |
3525 | | translate_ifs([Elsif|Rest]) --> |
3526 | | {get_if_elsif(Elsif,P,S)},!, |
3527 | | indent('ELSIF '), pp_expr_indent(P), insertstr(' THEN'), |
3528 | | insert_subst(S), |
3529 | | translate_ifs(Rest). |
3530 | | translate_ifs(ElseList) --> |
3531 | | {functor(ElseList,F,A),add_error(translate_ifs,'Could not translate IF-THEN-ELSE: ',F/A-ElseList),fail}. |
3532 | | |
3533 | | get_if_elsif(Elsif,P,S) :- |
3534 | | (optional_type(Elsif,if_elsif(P,S)) -> true |
3535 | | ; add_internal_error('Is not an if_elsif:',get_if_elsif(Elsif,P,S)), fail). |
3536 | | |
3537 | | insert_subst(S) --> |
3538 | | indention_level(I,I2),{I2 is I+2}, |
3539 | | translate_subst_check(S), |
3540 | | indention_level(_,I). |
3541 | | |
3542 | | translate_subst_check(S) --> translate_subst(S),!. |
3543 | | translate_subst_check(S) --> |
3544 | | {b_functor(S,F,A),add_error(translate_subst,'Could not translate substitution: ',F/A-S),fail}. |
3545 | | |
3546 | | b_functor(b(E,_,_),F,A) :- !,functor(E,F,A). |
3547 | | b_functor(E,F,A) :- functor(E,F,A). |
3548 | | |
3549 | | pp_description_pragma_of(enumerated_set_def(_,_)) --> !, "". |
3550 | | pp_description_pragma_of(Expr) --> |
3551 | | ({get_texpr_description(Expr,Desc)} |
3552 | | -> insert_atom(' /*@desc '), insert_atom(Desc), insert_atom(' */') |
3553 | | ; {true}). |
3554 | | indent_expr(Expr) --> |
3555 | | indent, pp_expr_indent(Expr), |
3556 | | pp_description_pragma_of(Expr). |
3557 | | %indent_expr_l([]) --> !. |
3558 | | %indent_expr_l([Expr|Rest]) --> |
3559 | | % indent_expr(Expr), indent_expr_l(Rest). |
3560 | | indent_expr_l_sep([],_) --> !. |
3561 | | indent_expr_l_sep([Expr|Rest],Sep) --> |
3562 | | indent_expr(Expr), |
3563 | | {(Rest=[] -> RealSep='' ; RealSep=Sep)}, |
3564 | | insert_atom(RealSep), % the threaded argument is a pair, not directly a string ! |
3565 | | indent_expr_l_sep(Rest,Sep). |
3566 | | %indention_level(L) --> indention_level(L,L). |
3567 | | increase_indentation_level --> indention_level(L,New), {New is L+1}. |
3568 | | increase_indentation_level(N) --> indention_level(L,New), {New is L+N}. |
3569 | | decrease_indentation_level --> indention_level(L,New), {New is L-1}. |
3570 | | decrease_indentation_level(N) --> indention_level(L,New), {New is L-N}. |
3571 | | indention_level(Old,New,(Old,S),(New,S)). |
3572 | | indention_codes(Old,New,(Indent,Old),(Indent,New)). |
3573 | | indent --> indent(''). |
3574 | | indent(M,(I,S),(I,T)) :- indent2(I,M,S,T). |
3575 | | indent2(Level,Msg) --> |
3576 | | "\n",do_indention(Level),ppatom(Msg). |
3577 | | |
3578 | | insert_atom(Sep,(I,S),(I,T)) :- ppatom(Sep,S,T). |
3579 | | |
3580 | | insertstr(M,(I,S),(I,T)) :- ppterm(M,S,T). |
3581 | | insertcodes(M,(I,S),(I,T)) :- ppcodes(M,S,T). |
3582 | | |
3583 | | do_indention(0,T,R) :- !, R=T. |
3584 | | do_indention(N,[32|I],O) :- |
3585 | | N>0,N2 is N-1, do_indention(N2,I,O). |
3586 | | |
3587 | | optional_type(Typed,Expr) :- get_texpr_expr(Typed,E),!,Expr=E. |
3588 | | optional_type(Expr,Expr). |
3589 | | |
3590 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3591 | | % expressions and predicates |
3592 | | |
3593 | | % pretty-type an expression in an indent-environment |
3594 | | % currently, the indent level is just thrown away |
3595 | | % TODO: pp_expr_indent dom( comprehension_set ) / union ( ...) |
3596 | | pp_expr_indent(b(comprehension_set(Ids,Body),_,_)) --> |
3597 | | {\+ eventb_translation_mode, % TODO: also print in Event-B mode: |
3598 | | detect_lambda_comprehension(Ids,Body, FrontIDs,LambdaBody,ToExpr)}, |
3599 | | {add_normal_typing_predicates(FrontIDs,LambdaBody,TLambdaBody)}, |
3600 | | !, |
3601 | | insertstr('%('), % to do: use lambda_symbol and improve layout below |
3602 | | pp_expr_indent_l(FrontIDs), |
3603 | | insertstr(') . ('), |
3604 | | pred_over_lines(2,'@body',TLambdaBody), |
3605 | | indent(' | '), increase_indentation_level(2), |
3606 | | indent(''), pp_expr_indent(ToExpr), decrease_indentation_level(2), |
3607 | | indent(')'). |
3608 | | pp_expr_indent(b(comprehension_set(Ids,Body),_,Info),(I,S),(I,T)) :- |
3609 | | pp_comprehension_set5(Ids,Body,Info,_,special(_Kind),S,T), |
3610 | | % throw away indent and check if a special pp rule is applicable |
3611 | | !. |
3612 | | pp_expr_indent(b(comprehension_set(Ids,Body),_,_)) --> |
3613 | | !, |
3614 | | insertstr('{'), pp_expr_indent_l(Ids), |
3615 | | insertstr(' | '), |
3616 | | pred_over_lines(2,'@body',Body), |
3617 | | indent('}'). |
3618 | | pp_expr_indent(b(convert_bool(Body),_,_)) --> |
3619 | | !, |
3620 | | insertstr('bool('), |
3621 | | pred_over_lines(2,'@bool',Body), |
3622 | | indent(')'). |
3623 | | pp_expr_indent(b(if_then_else(Test,Then,Else),_,_)) --> |
3624 | | !, |
3625 | | insertstr('IF'), |
3626 | | pred_over_lines(2,'@test',Test), |
3627 | | indent('THEN'),increase_indentation_level(2), |
3628 | | indent(''),pp_expr_indent(Then),decrease_indentation_level(2), |
3629 | | indent('ELSE'),increase_indentation_level(2), |
3630 | | indent(''),pp_expr_indent(Else),decrease_indentation_level(2), |
3631 | | indent('END'). |
3632 | | pp_expr_indent(b(let_expression(Ids,Exprs,Body),_,_)) --> |
3633 | | !, |
3634 | | pp_let_expr_nested(Ids,Exprs,Body). |
3635 | | % TODO: support a few more like dom/ran(comprehension_set) SIGMA, PI, \/ (union), ... |
3636 | | pp_expr_indent(Expr,(I,S),(I,T)) :- |
3637 | | %get_texpr_expr(Expr,F), functor(F,FF,NN), format(user_output,'Cannot indent: ~w/~w~n',[FF,NN]), |
3638 | | pp_expr(Expr,_,_LimitReached,S,T). % throw away indent |
3639 | | |
3640 | | can_indent_texpr(b(E,_,_)) :- can_indent_expr(E). |
3641 | | can_indent_expr(comprehension_set(_,_)). |
3642 | | can_indent_expr(convert_bool(_)). |
3643 | | can_indent_expr(if_then_else(_,_,_)). |
3644 | | can_indent_expr(let_expression(_,_,_)). |
3645 | | |
3646 | | pp_expr_indent_l([E]) --> !, pp_expr_indent(E). |
3647 | | pp_expr_indent_l(Exprs,(I,S),(I,T)) :- |
3648 | | pp_expr_l(Exprs,_LR,S,T). % throw away indent |
3649 | | pp_expr_m_indent(Expr,MinPrio,(I,S),(I,T)) :- |
3650 | | pp_expr_m(Expr,MinPrio,_LimitReached,S,T). |
3651 | | pp_atom_indent(A,(I,S),(I,T)) :- ppatom(A,S,T). |
3652 | | pp_expr_ids_in_mode_indent(Ids,(I,S),(I,T)) :- pp_expr_ids_in_mode(Ids,_,S,T). |
3653 | | |
3654 | | |
3655 | | |
3656 | | |
3657 | | is_boolean_value(b(B,boolean,_),BV) :- boolean_aux(B,BV). |
3658 | | boolean_aux(boolean_true,pred_true). |
3659 | | boolean_aux(boolean_false,pred_false). |
3660 | | boolean_aux(value(V),BV) :- nonvar(V),!,BV=V. |
3661 | | |
3662 | | |
3663 | | constants_in_mode(F,S) :- |
3664 | | constants(F,S1), translate_in_mode(F,S1,S). |
3665 | | |
3666 | | constants(pred_true,'TRUE'). |
3667 | | constants(pred_false,'FALSE'). |
3668 | | constants(boolean_true,'TRUE'). |
3669 | | constants(boolean_false,'FALSE'). |
3670 | | constants(max_int,'MAXINT'). |
3671 | | constants(min_int,'MININT'). |
3672 | | constants(empty_set,'{}'). |
3673 | | constants(bool_set,'BOOL'). |
3674 | | constants(float_set,'FLOAT'). |
3675 | | constants(real_set,'REAL'). |
3676 | | constants(string_set,'STRING'). |
3677 | | constants(empty_sequence,'[]'). |
3678 | | constants(event_b_identity,'id'). |
3679 | | |
3680 | | constants(truth,Res) :- eventb_translation_mode,!,Res=true. |
3681 | | constants(truth,Res) :- animation_minor_mode(tla),!,Res='TRUE'. |
3682 | | constants(truth,Res) :- atelierb_mode(_),!,Res='(TRUE:BOOL)'. % __truth; we could also do TRUE=TRUE |
3683 | | constants(truth,'btrue'). |
3684 | | constants(falsity,Res) :- eventb_translation_mode,!,Res=false. |
3685 | | constants(falsity,Res) :- animation_minor_mode(tla),!,Res='FALSE'. |
3686 | | constants(falsity,Res) :- atelierb_mode(_),!,Res='(TRUE=FALSE)'. |
3687 | | constants(falsity,'bfalse'). % __falsity |
3688 | | constants(unknown_truth_value(Msg),Res) :- % special internal constant |
3689 | | ajoin(['?(',Msg,')'],Res). |
3690 | | |
3691 | | function_like_in_mode(F,S) :- |
3692 | | function_like(F,S1), |
3693 | | translate_in_mode(F,S1,S). |
3694 | | |
3695 | | function_like(convert_bool,bool). |
3696 | | function_like(convert_real,real). % cannot be used on its own: dom(real) is not accepted by Atelier-B |
3697 | | function_like(convert_int_floor,floor). % ditto |
3698 | | function_like(convert_int_ceiling,ceiling). % ditto |
3699 | | function_like(successor,succ). % can also be used on its own; e.g., dom(succ)=INTEGER is ok |
3700 | | function_like(predecessor,pred). % ditto |
3701 | | function_like(max,max). |
3702 | | function_like(max_real,max). |
3703 | | function_like(min,min). |
3704 | | function_like(min_real,min). |
3705 | | function_like(card,card). |
3706 | | function_like(pow_subset,'POW'). |
3707 | | function_like(pow1_subset,'POW1'). |
3708 | | function_like(fin_subset,'FIN'). |
3709 | | function_like(fin1_subset,'FIN1'). |
3710 | | function_like(identity,id). |
3711 | | function_like(first_projection,prj1). |
3712 | | function_like(first_of_pair,'prj1'). % used to be __first_of_pair, will be dealt with separately to generate parsable representation |
3713 | | function_like(second_projection,prj2). |
3714 | | function_like(second_of_pair,'prj2'). % used to be __second_of_pair, will be dealt with separately to generate parsable representation |
3715 | | function_like(iteration,iterate). |
3716 | | function_like(event_b_first_projection_v2,prj1). |
3717 | | function_like(event_b_second_projection_v2,prj2). |
3718 | | function_like(reflexive_closure,closure). |
3719 | | function_like(closure,closure1). |
3720 | | function_like(domain,dom). |
3721 | | function_like(range,ran). |
3722 | | function_like(seq,seq). |
3723 | | function_like(seq1,seq1). |
3724 | | function_like(iseq,iseq). |
3725 | | function_like(iseq1,iseq1). |
3726 | | function_like(perm,perm). |
3727 | | function_like(size,size). |
3728 | | function_like(first,first). |
3729 | | function_like(last,last). |
3730 | | function_like(front,front). |
3731 | | function_like(tail,tail). |
3732 | | function_like(rev,rev). |
3733 | | function_like(general_concat,conc). |
3734 | | function_like(general_union,union). |
3735 | | function_like(general_intersection,inter). |
3736 | | function_like(trans_function,fnc). |
3737 | | function_like(trans_relation,rel). |
3738 | | function_like(tree,tree). |
3739 | | function_like(btree,btree). |
3740 | | function_like(const,const). |
3741 | | function_like(top,top). |
3742 | | function_like(sons,sons). |
3743 | | function_like(prefix,prefix). |
3744 | | function_like(postfix,postfix). |
3745 | | function_like(sizet,sizet). |
3746 | | function_like(mirror,mirror). |
3747 | | function_like(rank,rank). |
3748 | | function_like(father,father). |
3749 | | function_like(son,son). |
3750 | | function_like(subtree,subtree). |
3751 | | function_like(arity,arity). |
3752 | | function_like(bin,bin). |
3753 | | function_like(left,left). |
3754 | | function_like(right,right). |
3755 | | function_like(infix,infix). |
3756 | | |
3757 | | function_like(rec,rec). |
3758 | | function_like(struct,struct). |
3759 | | |
3760 | | function_like(negation,not). |
3761 | | function_like(bag_items,items). |
3762 | | |
3763 | | function_like(finite,finite). % from Event-B, TO DO: if \+ eventb_translation_mode then print as S:FIN(S) |
3764 | | function_like(witness,'@witness'). % from Event-B |
3765 | | |
3766 | | function_like(floored_div,'FDIV') :- \+ animation_minor_mode(tla). % using external function |
3767 | | |
3768 | | unary_prefix(unary_minus,-,210). |
3769 | | unary_prefix(unary_minus_real,-,210). |
3770 | | unary_prefix(mu,'MU',210) :- animation_minor_mode(z). |
3771 | | |
3772 | | unary_prefix_parentheses(compaction,'compaction'). |
3773 | | unary_prefix_parentheses(bag_items,'bag_items'). |
3774 | | unary_prefix_parentheses(mu,'MU') :- \+ animation_minor_mode(z). % write with () for external function |
3775 | | |
3776 | | unary_postfix(reverse,'~',230). % relational inverse |
3777 | | |
3778 | | |
3779 | | always_surround_by_parentheses(parallel_product). |
3780 | | always_surround_by_parentheses(composition). |
3781 | | |
3782 | | binary_infix_symbol(b(T,_,_),Symbol) :- functor(T,F,2), binary_infix_in_mode(F,Symbol,_,_). |
3783 | | |
3784 | | % EXPR * EXPR --> EXPR |
3785 | | binary_infix(composition,';',20,left). |
3786 | | binary_infix(overwrite,'<+',160,left). |
3787 | | binary_infix(direct_product,'><',160,left). % Rodin requires parentheses |
3788 | | binary_infix(parallel_product,'||',20,left). |
3789 | | binary_infix(concat,'^',160,left). |
3790 | | binary_infix(relations,'<->',125,left). |
3791 | | binary_infix(partial_function,'+->',125,left). |
3792 | | binary_infix(total_function,'-->',125,left). |
3793 | | binary_infix(partial_injection,'>+>',125,left). |
3794 | | binary_infix(total_injection,'>->',125,left). |
3795 | | binary_infix(partial_surjection,'+->>',125,left). |
3796 | | binary_infix(total_surjection,Symbol,125,left) :- |
3797 | | (eventb_translation_mode -> Symbol = '->>'; Symbol = '-->>'). |
3798 | | binary_infix(total_bijection,'>->>',125,left). |
3799 | | binary_infix(partial_bijection,'>+>>',125,left). |
3800 | | binary_infix(total_relation,'<<->',125,left). % only in Event-B |
3801 | | binary_infix(surjection_relation,'<->>',125,left). % only in Event-B |
3802 | | binary_infix(total_surjection_relation,'<<->>',125,left). % only in Event-B |
3803 | | binary_infix(insert_front,'->',160,left). |
3804 | | binary_infix(insert_tail,'<-',160,left). |
3805 | | binary_infix(domain_restriction,'<|',160,left). |
3806 | | binary_infix(domain_subtraction,'<<|',160,left). |
3807 | | binary_infix(range_restriction,'|>',160,left). |
3808 | | binary_infix(range_subtraction,'|>>',160,left). |
3809 | | binary_infix(intersection,'/\\',160,left). |
3810 | | binary_infix(union,'\\/',160,left). |
3811 | | binary_infix(restrict_front,'/|\\',160,left). |
3812 | | binary_infix(restrict_tail,'\\|/',160,left). |
3813 | | binary_infix(couple,'|->',160,left). |
3814 | | binary_infix(interval,'..',170,left). |
3815 | | binary_infix(add,+,180,left). |
3816 | | binary_infix(add_real,+,180,left). |
3817 | | binary_infix(minus,-,180,left). |
3818 | | binary_infix(minus_real,-,180,left). |
3819 | | binary_infix(set_subtraction,'\\',180,left) :- eventb_translation_mode,!. % symbol is not allowed by Atelier-B |
3820 | | binary_infix(set_subtraction,-,180,left). |
3821 | | binary_infix(minus_or_set_subtract,-,180,left). |
3822 | | binary_infix(multiplication,*,190,left). |
3823 | | binary_infix(multiplication_real,*,190,left). |
3824 | | binary_infix(cartesian_product,**,190,left) :- eventb_translation_mode,!. |
3825 | | binary_infix(cartesian_product,*,190,left). |
3826 | | binary_infix(mult_or_cart,*,190,left). % in case type checker not yet run |
3827 | | binary_infix(div,/,190,left). |
3828 | | binary_infix(div_real,/,190,left). |
3829 | | binary_infix(floored_div,div,190,left) :- animation_minor_mode(tla). |
3830 | | binary_infix(modulo,mod,190,left). |
3831 | | binary_infix(power_of,**,200,right). |
3832 | | binary_infix(power_of_real,**,200,right). |
3833 | | 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 |
3834 | | |
3835 | | binary_infix(ring,'\x2218\',160,left). % our B Parser gives ring same priority as direct_product or overwrite |
3836 | | |
3837 | | % PRED * PRED --> PRED |
3838 | | binary_infix(implication,'=>',30,left). |
3839 | | binary_infix(conjunct,'&',40,left). |
3840 | | binary_infix(disjunct,or,40,left). |
3841 | | binary_infix(equivalence,'<=>',Prio,left) :- % in Rodin this has the same priority as implication |
3842 | | (eventb_translation_mode -> Prio=30 ; Prio=60). |
3843 | | |
3844 | | |
3845 | | % EXPR * EXPR --> PRED |
3846 | | binary_infix(equal,=,60,left). |
3847 | | binary_infix(not_equal,'/=',160,left). |
3848 | | binary_infix(less_equal,'<=',160,left). |
3849 | | binary_infix(less,'<',160,left). |
3850 | | binary_infix(less_equal_real,'<=',160,left). |
3851 | | binary_infix(less_real,'<',160,left). |
3852 | | binary_infix(greater_equal,'>=',160,left). |
3853 | | binary_infix(greater,'>',160,left). |
3854 | | binary_infix(member,':',60,left). |
3855 | | binary_infix(not_member,'/:',160,left). |
3856 | | binary_infix(subset,'<:',110,left). |
3857 | | binary_infix(subset_strict,'<<:',110,left). |
3858 | | binary_infix(not_subset,'/<:',110,left). |
3859 | | binary_infix(not_subset_strict,'/<<:',110,left). |
3860 | | |
3861 | | binary_infix(values_entry,'=',60,left). |
3862 | | |
3863 | | % atelierb_mode(pp): translation for AtelierB's PP/ML prover |
3864 | | % atelierb_mode(native): translation to native B supported by AtelierB |
3865 | | :- dynamic latex_mode/0, unicode_mode/0, atelierb_mode/1, force_eventb_rodin_mode/0. |
3866 | | |
3867 | | %latex_mode. |
3868 | | %unicode_mode. |
3869 | | %force_eventb_rodin_mode. % Force Event-B output even if not in eventb minor mode |
3870 | | |
3871 | | eventb_translation_mode :- animation_minor_mode(eventb),!. |
3872 | | eventb_translation_mode :- force_eventb_rodin_mode. |
3873 | | |
3874 | | set_force_eventb_mode :- assertz(force_eventb_rodin_mode). |
3875 | | unset_force_eventb_mode :- |
3876 | | (retract(force_eventb_rodin_mode) -> true ; add_internal_error('Was not in forced Event-B mode: ',force_eventb_rodin_mode)). |
3877 | | |
3878 | | set_unicode_mode :- assertz(unicode_mode). |
3879 | | set_latex_mode :- assertz(latex_mode). |
3880 | | unset_unicode_mode :- |
3881 | | (retract(unicode_mode) -> true ; add_internal_error('Was not in Unicode mode: ',unset_unicode_mode)). |
3882 | | unset_latex_mode :- |
3883 | | (retract(latex_mode) -> true |
3884 | | ; add_internal_error('Was not in Latex mode: ',unset_latex_mode)). |
3885 | | |
3886 | | set_atelierb_mode(Mode) :- asserta(atelierb_mode(Mode)). |
3887 | | unset_atelierb_mode :- |
3888 | | (retract(atelierb_mode(_)) -> true ; add_internal_error('Was not in Atelier-B mode: ',unset_atelierb_mode)). |
3889 | | |
3890 | | get_translation_mode(M) :- unicode_mode, !, M=unicode. |
3891 | | get_translation_mode(M) :- latex_mode, !, M=latex. |
3892 | | get_translation_mode(M) :- atelierb_mode(native), !, M=atelierb. |
3893 | | get_translation_mode(M) :- atelierb_mode(pp), !, M=atelierb_pp. |
3894 | | get_translation_mode(ascii). |
3895 | | |
3896 | | % TO DO: provide better stack-based setting/unsetting of modes or use options parameter |
3897 | | set_translation_mode(ascii) :- !, retractall(unicode_mode), retractall(latex_mode), retractall(atelierb_mode(_)). |
3898 | | set_translation_mode(unicode) :- !, set_unicode_mode. |
3899 | | set_translation_mode(latex) :- !, set_latex_mode. |
3900 | | set_translation_mode(atelierb) :- !, set_atelierb_mode(native). |
3901 | | set_translation_mode(atelierb_pp) :- !, set_atelierb_mode(pp). % translation for PP/ML prover |
3902 | | set_translation_mode(Mode) :- add_internal_error('Illegal mode:',set_translation_mode(Mode)). |
3903 | | |
3904 | | unset_translation_mode(ascii) :- !. |
3905 | | unset_translation_mode(unicode) :- !,unset_unicode_mode. |
3906 | | unset_translation_mode(latex) :- !,unset_latex_mode. |
3907 | | unset_translation_mode(atelierb) :- !,unset_atelierb_mode. |
3908 | | unset_translation_mode(atelierb_pp) :- !,unset_atelierb_mode. |
3909 | | unset_translation_mode(Mode) :- add_internal_error('Illegal mode:',unset_translation_mode(Mode)). |
3910 | | |
3911 | | with_translation_mode(Mode, Call) :- |
3912 | | get_translation_mode(OldMode), |
3913 | | (OldMode == Mode -> Call ; |
3914 | | set_translation_mode(ascii), % Clear all existing translation mode settings first |
3915 | | set_translation_mode(Mode), |
3916 | | call_cleanup(Call, set_translation_mode(OldMode)) |
3917 | | % FIXME This might not restore all translation modes fully! |
3918 | | % For example, if both unicode_mode and latex_mode are set, |
3919 | | % then with_translation_mode(ascii, ...) will only restore unicode_mode. |
3920 | | % Not sure if this might cause problems for some code. |
3921 | | ). |
3922 | | |
3923 | | % The language mode is currently linked to the animation minor mode, |
3924 | | % so be careful when changing it! |
3925 | | % TODO Allow overriding the language for translate without affecting the animation mode |
3926 | | |
3927 | | get_language_mode(csp_and(Lang)) :- |
3928 | | csp_with_bz_mode, |
3929 | | !, |
3930 | | (animation_minor_mode(Lang) -> true ; Lang = b). |
3931 | | get_language_mode(Lang) :- animation_minor_mode(Lang), !. |
3932 | | get_language_mode(Lang) :- animation_mode(Lang). |
3933 | | |
3934 | | set_language_mode(csp_and(Lang)) :- |
3935 | | !, |
3936 | | set_animation_mode(csp_and_b), |
3937 | | (Lang == b -> true ; set_animation_minor_mode(Lang)). |
3938 | | set_language_mode(csp) :- !, set_animation_mode(csp). |
3939 | | set_language_mode(xtl) :- !, set_animation_mode(xtl). |
3940 | | set_language_mode(b) :- !, set_animation_mode(b). |
3941 | | set_language_mode(Lang) :- |
3942 | | set_animation_mode(b), |
3943 | | set_animation_minor_mode(Lang). |
3944 | | |
3945 | | with_language_mode(Lang, Call) :- |
3946 | | get_language_mode(OldLang), |
3947 | | (OldLang == Lang -> Call ; |
3948 | | set_language_mode(Lang), |
3949 | | call_cleanup(Call, set_language_mode(OldLang)) |
3950 | | % FIXME This might not restore all animation modes fully! |
3951 | | % It's apparently possible to have multiple animation minor modes, |
3952 | | % which get/set_language_mode doesn't handle. |
3953 | | % (Are multiple animation minor modes actually used anywhere?) |
3954 | | ). |
3955 | | |
3956 | | exists_symbol --> {latex_mode},!, "\\exists ". |
3957 | | exists_symbol --> {unicode_mode},!, pp_colour_code(magenta),[8707],pp_colour_code(reset). |
3958 | | exists_symbol --> pp_colour_code(blue),"#",pp_colour_code(reset). |
3959 | | forall_symbol --> {latex_mode},!, "\\forall ". |
3960 | | forall_symbol --> {unicode_mode},!, pp_colour_code(magenta),[8704],pp_colour_code(reset). |
3961 | | forall_symbol --> pp_colour_code(blue),"!",pp_colour_code(reset). |
3962 | | dot_symbol --> {latex_mode},!, "\\cdot ". |
3963 | | dot_symbol --> {unicode_mode},!, [183]. %"·". % dot also used in Rodin |
3964 | | dot_symbol --> ".". |
3965 | | dot_bullet_symbol --> {latex_mode},!, "\\cdot ". |
3966 | | dot_bullet_symbol --> [183]. %"·". % dot also used in Rodin |
3967 | | set_brackets(X,Y) :- latex_mode,!,X='\\{', Y='\\}'. |
3968 | | set_brackets('{','}'). |
3969 | | left_set_bracket --> {latex_mode},!, "\\{ ". |
3970 | | left_set_bracket --> "{". |
3971 | | right_set_bracket --> {latex_mode},!, "\\} ". |
3972 | | right_set_bracket --> "}". |
3973 | | maplet_symbol --> {latex_mode},!, "\\mapsto ". |
3974 | | maplet_symbol --> {unicode_mode},!, [8614]. |
3975 | | maplet_symbol --> "|->". % also provide option to use colours? pp_colour_code(blue) ,... |
3976 | | |
3977 | | lambda_symbol --> {unicode_mode},!, [955]. % '\x3BB\' |
3978 | | lambda_symbol --> {latex_mode},!, "\\lambda ". |
3979 | | lambda_symbol --> pp_colour_code(blue),"%",pp_colour_code(reset). |
3980 | | |
3981 | | and_symbol --> {unicode_mode},!, [8743]. % ''\x2227\'' |
3982 | | and_symbol --> {latex_mode},!, "\\wedge ". |
3983 | | and_symbol --> "&". |
3984 | | |
3985 | | hash_card_symbol --> {latex_mode},!, "\\# ". |
3986 | | hash_card_symbol --> "#". |
3987 | | ldots --> {latex_mode},!, "\\ldots ". |
3988 | | ldots --> "...". |
3989 | | |
3990 | | empty_set_symbol --> {get_preference(translate_print_all_sequences,true)},!, pp_empty_sequence. |
3991 | | empty_set_symbol --> {unicode_mode},!, [8709]. |
3992 | | empty_set_symbol --> {latex_mode},!, "\\emptyset ". |
3993 | | empty_set_symbol --> "{}". |
3994 | | |
3995 | | underscore_symbol --> {latex_mode},!, "\\_". |
3996 | | underscore_symbol --> "_". |
3997 | | |
3998 | | string_start_symbol --> {latex_mode},!, "\\textnormal{``". |
3999 | | string_start_symbol --> pp_colour_code(blue), """". |
4000 | | string_end_symbol --> {latex_mode},!, "''}". |
4001 | | string_end_symbol --> pp_colour_code(reset), """". |
4002 | | |
4003 | | |
4004 | | unary_postfix_in_mode(Op,Trans2,Prio) :- |
4005 | | unary_postfix(Op,Trans,Prio), % print(op(Op,Trans)),nl, |
4006 | | translate_in_mode(Op,Trans,Trans2). |
4007 | | |
4008 | | binary_infix_in_mode(Op,Trans2,Prio,Assoc) :- |
4009 | | binary_infix(Op,Trans,Prio,Assoc), % print(op(Op,Trans)),nl, |
4010 | | translate_in_mode(Op,Trans,Trans2). |
4011 | | |
4012 | | latex_integer_set_translation('NATURAL', '\\mathbb N '). % \nat in bsymb.sty |
4013 | | latex_integer_set_translation('NATURAL1', '\\mathbb N_1 '). % \natn |
4014 | | latex_integer_set_translation('INTEGER', '\\mathbb Z '). % \intg |
4015 | | latex_integer_set_translation('REAL', '\\mathbb R '). % \intg |
4016 | | |
4017 | | latex_translation(empty_set, '\\emptyset '). |
4018 | | latex_translation(implication, '\\mathbin\\Rightarrow '). |
4019 | | latex_translation(conjunct,'\\wedge '). |
4020 | | latex_translation(disjunct,'\\vee '). |
4021 | | latex_translation(equivalence,'\\mathbin\\Leftrightarrow '). |
4022 | | latex_translation(negation,'\\neg '). |
4023 | | latex_translation(not_equal,'\\neq '). |
4024 | | latex_translation(less_equal,'\\leq '). |
4025 | | latex_translation(less_equal_real,'\\leq '). |
4026 | | latex_translation(greater_equal,'\\geq '). |
4027 | | latex_translation(member,'\\in '). |
4028 | | latex_translation(not_member,'\\not\\in '). |
4029 | | latex_translation(subset,'\\subseteq '). |
4030 | | latex_translation(subset_strict,'\\subset '). |
4031 | | latex_translation(not_subset,'\\not\\subseteq '). |
4032 | | latex_translation(not_subset_strict,'\\not\\subset '). |
4033 | | latex_translation(union,'\\cup '). |
4034 | | latex_translation(intersection,'\\cap '). |
4035 | | latex_translation(couple,'\\mapsto '). |
4036 | | latex_translation(cartesian_product,'\\times'). |
4037 | | latex_translation(rec,'\\mathit{rec}'). |
4038 | | latex_translation(struct,'\\mathit{struct}'). |
4039 | | latex_translation(convert_bool,'\\mathit{bool}'). |
4040 | | latex_translation(max,'\\mathit{max}'). |
4041 | | latex_translation(max_real,'\\mathit{max}'). |
4042 | | latex_translation(min,'\\mathit{min}'). |
4043 | | latex_translation(min_real,'\\mathit{min}'). |
4044 | | latex_translation(modulo,'\\mod '). |
4045 | | latex_translation(card,'\\mathit{card}'). |
4046 | | latex_translation(successor,'\\mathit{succ}'). |
4047 | | latex_translation(predecessor,'\\mathit{pred}'). |
4048 | | latex_translation(domain,'\\mathit{dom}'). |
4049 | | latex_translation(range,'\\mathit{ran}'). |
4050 | | latex_translation(size,'\\mathit{size}'). |
4051 | | latex_translation(first,'\\mathit{first}'). |
4052 | | latex_translation(last,'\\mathit{last}'). |
4053 | | latex_translation(front,'\\mathit{front}'). |
4054 | | latex_translation(tail,'\\mathit{tail}'). |
4055 | | latex_translation(rev,'\\mathit{rev}'). |
4056 | | latex_translation(seq,'\\mathit{seq}'). |
4057 | | latex_translation(seq1,'\\mathit{seq}_{1}'). |
4058 | | latex_translation(perm,'\\mathit{perm}'). |
4059 | | latex_translation(fin_subset,'\\mathit{FIN}'). |
4060 | | latex_translation(fin1_subset,'\\mathit{FIN}_{1}'). |
4061 | | latex_translation(first_projection,'\\mathit{prj}_{1}'). |
4062 | | latex_translation(second_projection,'\\mathit{prj}_{2}'). |
4063 | | latex_translation(pow_subset,'\\mathbb P\\hbox{}'). % POW \pow would require bsymb.sty |
4064 | | latex_translation(pow1_subset,'\\mathbb P_1'). % POW1 \pown would require bsymb.sty |
4065 | | latex_translation(concat,'\\stackrel{\\frown}{~}'). % was '\\hat{~}'). |
4066 | | latex_translation(relations,'\\mathbin\\leftrightarrow'). % <->, \rel requires bsymb.sty |
4067 | | latex_translation(total_relation,'\\mathbin{\\leftarrow\\mkern-14mu\\leftrightarrow}'). % <<-> \trel requires bsymb.sty |
4068 | | latex_translation(total_surjection_relation,'\\mathbin{\\leftrightarrow\\mkern-14mu\\leftrightarrow}'). % <<->> \strel requires bsymb.sty |
4069 | | latex_translation(surjection_relation,'\\mathbin{\\leftrightarrow\\mkern-14mu\\rightarrow}'). % <->> \srel requires bsymb.sty |
4070 | | latex_translation(partial_function,'\\mathbin{\\mkern6mu\\mapstochar\\mkern-6mu\\rightarrow}'). % +-> \pfun requires bsymb.sty, but \mapstochar is not supported by Mathjax |
4071 | | latex_translation(partial_injection,'\\mathbin{\\mkern9mu\\mapstochar\\mkern-9mu\\rightarrowtail}'). % >+> \pinj requires bsymb.sty |
4072 | | latex_translation(partial_surjection,'\\mathbin{\\mkern6mu\\mapstochar\\mkern-6mu\\twoheadrightarrow}'). % >+> \psur requires bsymb.sty |
4073 | | latex_translation(total_function,'\\mathbin\\rightarrow'). % --> \tfun would require bsymb.sty |
4074 | | latex_translation(total_surjection,'\\mathbin\\twoheadrightarrow'). % -->> \tsur requires bsymb.sty |
4075 | | latex_translation(total_injection,'\\mathbin\\rightarrowtail'). % >-> \tinj requires bsymb.sty |
4076 | | latex_translation(total_bijection,'\\mathbin{\\rightarrowtail\\mkern-18mu\\twoheadrightarrow}'). % >->> \tbij requires bsymb.sty |
4077 | | latex_translation(domain_restriction,'\\mathbin\\lhd'). % <| domres requires bsymb.sty |
4078 | | latex_translation(range_restriction,'\\mathbin\\rhd'). % |> ranres requires bsymb.sty |
4079 | | latex_translation(domain_subtraction,'\\mathbin{\\lhd\\mkern-14mu-}'). % <<| domsub requires bsymb.sty |
4080 | | latex_translation(range_subtraction,'\\mathbin{\\rhd\\mkern-14mu-}'). % |>> ransub requires bsymb.sty |
4081 | | latex_translation(overwrite,'\\mathbin{\\lhd\\mkern-9mu-}'). % <+ \ovl requires bsymb.sty |
4082 | | latex_translation(ring,'\\circ '). % not tested |
4083 | | latex_translation(general_sum,'\\Sigma '). |
4084 | | latex_translation(general_product,'\\Pi '). |
4085 | | latex_translation(lambda,'\\lambda '). |
4086 | | latex_translation(quantified_union,'\\bigcup\\nolimits'). % \Union requires bsymb.sty |
4087 | | latex_translation(quantified_intersection,'\\bigcap\\nolimits'). % \Inter requires bsymb.sty |
4088 | | %latex_translation(truth,'\\top'). |
4089 | | %latex_translation(falsity,'\\bot'). |
4090 | | latex_translation(truth,'{\\color{olive} \\top}'). % requires \usepackage{xcolor} in Latex |
4091 | | latex_translation(falsity,'{\\color{red} \\bot}'). |
4092 | | latex_translation(boolean_true,'{\\color{olive} \\mathit{TRUE}}'). |
4093 | | latex_translation(boolean_false,'{\\color{red} \\mathit{FALSE}}'). |
4094 | | latex_translation(pred_true,'{\\color{olive} \\mathit{TRUE}}'). |
4095 | | latex_translation(pred_false,'{\\color{red} \\mathit{FALSE}}'). |
4096 | | latex_translation(reverse,'^{-1}'). |
4097 | | |
4098 | | ascii_to_unicode(Ascii,Unicode) :- |
4099 | | translate_prolog_constructor(BAst,Ascii), % will not backtrack |
4100 | | unicode_translation(BAst,Unicode). |
4101 | | |
4102 | | |
4103 | | % can be used to translate Latex shortcuts to B Unicode operators for editors |
4104 | | latex_to_unicode(LatexShortcut,Unicode) :- |
4105 | | latex_to_b_ast(LatexShortcut,BAst), |
4106 | | unicode_translation(BAst,Unicode). |
4107 | | latex_to_unicode(LatexShortcut,Unicode) :- % allow to use B AST names as well |
4108 | | unicode_translation(LatexShortcut,Unicode). |
4109 | | latex_to_unicode(LatexShortcut,Unicode) :- |
4110 | | greek_symbol(LatexShortcut,Unicode). |
4111 | | |
4112 | | get_latex_keywords(List) :- |
4113 | | findall(Id,latex_to_unicode(Id,_),Ids), |
4114 | | sort(Ids,List). |
4115 | | |
4116 | | get_latex_keywords_with_backslash(BList) :- |
4117 | | get_latex_keywords(List), |
4118 | | maplist(atom_concat('\\'),List,BList). |
4119 | | |
4120 | | latex_to_b_ast(and,conjunct). |
4121 | | latex_to_b_ast(bcomp,ring). % bsymb: backwards composition |
4122 | | latex_to_b_ast(bigcap,quantified_intersection). |
4123 | | latex_to_b_ast(bigcup,quantified_union). |
4124 | | latex_to_b_ast(cap,intersection). |
4125 | | latex_to_b_ast(cart,cartesian_product). |
4126 | | latex_to_b_ast(cprod,cartesian_product). |
4127 | | latex_to_b_ast(cdot,dot_symbol). |
4128 | | latex_to_b_ast(cup,union). |
4129 | | latex_to_b_ast(dprod,direct_product). |
4130 | | latex_to_b_ast(dres,domain_restriction). |
4131 | | latex_to_b_ast(dsub,domain_subtraction). |
4132 | | latex_to_b_ast(emptyset,empty_set). |
4133 | | latex_to_b_ast(exp,power_of). |
4134 | | %latex_to_b_ast(fcomp,composition). % bsymb: forwards composition |
4135 | | latex_to_b_ast(geq,greater_equal). |
4136 | | latex_to_b_ast(implies,implication). |
4137 | | latex_to_b_ast(in,member). |
4138 | | latex_to_b_ast(int,'INTEGER'). |
4139 | | latex_to_b_ast(intg,'INTEGER'). % from bsymb |
4140 | | latex_to_b_ast(lambda,lambda). |
4141 | | latex_to_b_ast(land,conjunct). |
4142 | | latex_to_b_ast(leq,less_equal). |
4143 | | latex_to_b_ast(leqv,equivalence). |
4144 | | latex_to_b_ast(lhd,domain_restriction). |
4145 | | latex_to_b_ast(limp,implication). |
4146 | | latex_to_b_ast(lor,disjunct). |
4147 | | latex_to_b_ast(lnot,negation). |
4148 | | latex_to_b_ast(mapsto,couple). |
4149 | | latex_to_b_ast(nat,'NATURAL'). |
4150 | | latex_to_b_ast(natn,'NATURAL1'). |
4151 | | latex_to_b_ast(neg,negation). |
4152 | | latex_to_b_ast(neq,not_equal). |
4153 | | latex_to_b_ast(nin,not_member). |
4154 | | latex_to_b_ast(not,negation). |
4155 | | latex_to_b_ast(nsubseteq,not_subset). |
4156 | | latex_to_b_ast(nsubset,not_subset_strict). |
4157 | | latex_to_b_ast(or,disjunct). |
4158 | | %latex_to_b_ast(ovl,overwrite). |
4159 | | latex_to_b_ast(pfun,partial_function). |
4160 | | latex_to_b_ast(pinj,partial_injection). |
4161 | | latex_to_b_ast(psur,partial_surjection). |
4162 | | latex_to_b_ast(pow,pow_subset). |
4163 | | latex_to_b_ast(pown,pow1_subset). |
4164 | | latex_to_b_ast(pprod,parallel_product). |
4165 | | latex_to_b_ast(qdot,dot_symbol). |
4166 | | latex_to_b_ast(real,'REAL'). |
4167 | | latex_to_b_ast(rel,relations). |
4168 | | latex_to_b_ast(rhd,range_restriction). |
4169 | | latex_to_b_ast(rres,range_restriction). |
4170 | | latex_to_b_ast(rsub,range_subtraction). |
4171 | | latex_to_b_ast(srel,surjection_relation). |
4172 | | latex_to_b_ast(subseteq,subset). |
4173 | | latex_to_b_ast(subset,subset_strict). |
4174 | | latex_to_b_ast(tbij,total_bijection). |
4175 | | latex_to_b_ast(tfun,total_function). |
4176 | | latex_to_b_ast(tinj,total_injection). |
4177 | | latex_to_b_ast(trel,total_relation). |
4178 | | latex_to_b_ast(tsrel,total_surjection_relation). |
4179 | | latex_to_b_ast(tsur,total_surjection). |
4180 | | latex_to_b_ast(upto,interval). |
4181 | | latex_to_b_ast(vee,disjunct). |
4182 | | latex_to_b_ast(wedge,conjunct). |
4183 | | latex_to_b_ast('INT','INTEGER'). |
4184 | | latex_to_b_ast('NAT','NATURAL'). |
4185 | | latex_to_b_ast('N','NATURAL'). |
4186 | | latex_to_b_ast('Pi',general_product). |
4187 | | latex_to_b_ast('POW',pow_subset). |
4188 | | latex_to_b_ast('REAL','REAL'). |
4189 | | latex_to_b_ast('Rightarrow',implication). |
4190 | | latex_to_b_ast('Sigma',general_sum). |
4191 | | latex_to_b_ast('Leftrightarrow',equivalence). |
4192 | | latex_to_b_ast('Inter',quantified_intersection). |
4193 | | latex_to_b_ast('Union',quantified_union). |
4194 | | latex_to_b_ast('Z','INTEGER'). |
4195 | | |
4196 | | unicode_translation(implication, '\x21D2\'). |
4197 | | unicode_translation(conjunct,'\x2227\'). |
4198 | | unicode_translation(disjunct,'\x2228\'). |
4199 | | unicode_translation(negation,'\xAC\'). |
4200 | | unicode_translation(equivalence,'\x21D4\'). |
4201 | | unicode_translation(not_equal,'\x2260\'). |
4202 | | unicode_translation(less_equal,'\x2264\'). |
4203 | | unicode_translation(less_equal_real,'\x2264\'). |
4204 | | unicode_translation(greater_equal,'\x2265\'). |
4205 | | unicode_translation(member,'\x2208\'). |
4206 | | unicode_translation(not_member,'\x2209\'). |
4207 | | unicode_translation(subset,'\x2286\'). |
4208 | | unicode_translation(subset_strict,'\x2282\'). |
4209 | | unicode_translation(not_subset,'\x2288\'). |
4210 | | unicode_translation(not_subset_strict,'\x2284\'). |
4211 | | unicode_translation(supseteq,'\x2287\'). % ProB parser supports unicode symbol by reversing arguments |
4212 | | unicode_translation(supset_strict,'\x2283\'). % ditto |
4213 | | unicode_translation(not_supseteq,'\x2289\'). % ditto |
4214 | | unicode_translation(not_supset_strict,'\x2285\'). % ditto |
4215 | | unicode_translation(union,'\x222A\'). |
4216 | | unicode_translation(intersection,'\x2229\'). |
4217 | | unicode_translation(cartesian_product,'\xD7\'). % also 0x2217 in Camille or 0x2A2F (vector or cross product) in IDP |
4218 | | unicode_translation(couple,'\x21A6\'). |
4219 | | unicode_translation(div,'\xF7\'). |
4220 | | unicode_translation(dot_symbol,'\xB7\'). % not a B AST operator, cf dot_symbol 183 |
4221 | | unicode_translation(floored_div,'\xF7\') :- |
4222 | | animation_minor_mode(tla). % should we provide another Unicode character here for B? |
4223 | | unicode_translation(power_of,'\x02C4\'). % version of ^, does not exist in Rodin ?!, upwards arrow x2191 used below for restrict front |
4224 | | unicode_translation(power_of_real,'\x02C4\'). |
4225 | | unicode_translation(interval,'\x2025\'). |
4226 | | unicode_translation(domain_restriction,'\x25C1\'). |
4227 | | unicode_translation(domain_subtraction,'\x2A64\'). |
4228 | | unicode_translation(range_restriction,'\x25B7\'). |
4229 | | unicode_translation(range_subtraction,'\x2A65\'). |
4230 | | unicode_translation(relations,'\x2194\'). |
4231 | | unicode_translation(partial_function,'\x21F8\'). |
4232 | | unicode_translation(total_function,'\x2192\'). |
4233 | | unicode_translation(partial_injection,'\x2914\'). |
4234 | | unicode_translation(partial_surjection,'\x2900\'). |
4235 | | unicode_translation(total_injection,'\x21A3\'). |
4236 | | unicode_translation(total_surjection,'\x21A0\'). |
4237 | | unicode_translation(total_bijection,'\x2916\'). |
4238 | | unicode_translation('INTEGER','\x2124\'). |
4239 | | unicode_translation('NATURAL','\x2115\'). |
4240 | | unicode_translation('NATURAL1','\x2115\\x2081\'). % \x2115\ is subscript 1 |
4241 | | unicode_translation('REAL','\x211D\'). % 8477 in decimal |
4242 | | unicode_translation(real_set,'\x211D\'). |
4243 | | %unicode_translation(bool_set,'\x1D539\'). % conversion used by IDP, but creates SPIO_E_ENCODING_INVALID problem |
4244 | | unicode_translation(pow_subset,'\x2119\'). |
4245 | | unicode_translation(pow1_subset,'\x2119\\x2081\'). % \x2115\ is subscript 1 |
4246 | | unicode_translation(lambda,'\x3BB\'). |
4247 | | unicode_translation(general_product,'\x220F\'). |
4248 | | unicode_translation(general_sum,'\x2211\'). |
4249 | | unicode_translation(quantified_union,'\x22C3\'). % 8899 in decimal |
4250 | | unicode_translation(quantified_intersection,'\x22C2\'). % 8898 in decimal |
4251 | | unicode_translation(empty_set,'\x2205\'). |
4252 | | unicode_translation(truth,'\x22A4\'). % 8868 in decimal |
4253 | | unicode_translation(falsity,'\x22A5\'). % 8869 in decimal |
4254 | | unicode_translation(direct_product,'\x2297\'). |
4255 | | unicode_translation(parallel_product,'\x2225\'). |
4256 | | unicode_translation(reverse,'\x207B\\xB9\') :- \+ force_eventb_rodin_mode. % the one ¹ is ASCII 185 |
4257 | | % this symbol is not accepted by Rodin |
4258 | | % unicode_translation(infinity,'\x221E\'). % 8734 in decimal |
4259 | | unicode_translation(concat,'\x2312\'). % Arc character |
4260 | | unicode_translation(insert_front,'\x21FE\'). |
4261 | | unicode_translation(insert_tail,'\x21FD\'). |
4262 | | unicode_translation(restrict_front,'\x2191\'). % up arrow |
4263 | | unicode_translation(restrict_tail,'\x2192\'). |
4264 | | unicode_translation(forall, '\x2200\'). % usually forall_symbol used |
4265 | | unicode_translation(exists, '\x2203\'). % usually exists_symbol used |
4266 | | unicode_translation(eqeq,'\x225c\'). |
4267 | | |
4268 | | %unicode_translation(overwrite,'\xE103\'). % from kernel_lang_20.pdf |
4269 | | unicode_translation(ring,'\x2218\'). % from Event-B |
4270 | | unicode_translation(typeof,'\x2982\'). % Event-B oftype operator |
4271 | | |
4272 | | atelierb_pp_translation(set_minus,'_moinsE'). |
4273 | | atelierb_pp_translation(cartesian_product,'_multE'). |
4274 | | atelierb_pp_translation('INTEGER','INTEGER'). |
4275 | | %atelierb_pp_translation('INT','(MININT..MAXINT)'). % does not seem necessary |
4276 | | atelierb_pp_translation('NATURAL','NATURAL'). |
4277 | | %atelierb_pp_translation('NAT','(0..MAXINT)'). % does not seem necessary |
4278 | | %atelierb_pp_translation('NAT1','(1..MAXINT)'). % does not seem necessary |
4279 | | atelierb_pp_translation(truth,btrue). |
4280 | | atelierb_pp_translation(falsity,bfalse). |
4281 | | atelierb_pp_translation(boolean_true,'TRUE'). |
4282 | | atelierb_pp_translation(boolean_false,'FALSE'). |
4283 | | atelierb_pp_translation(empty_sequence,'{}'). |
4284 | | |
4285 | | quantified_in_mode(F,S) :- |
4286 | | quantified(F,S1), translate_in_mode(F,S1,S). |
4287 | | |
4288 | | translate_in_mode(F,S1,Result) :- |
4289 | | ( unicode_mode, unicode_translation(F,S) -> true |
4290 | | ; latex_mode, latex_translation(F,S) -> true |
4291 | | ; atelierb_mode(Mode), Mode == pp, atelierb_pp_translation(F,S) -> true |
4292 | | ; colour_translation(F,S1,S) -> true |
4293 | | ; S1=S), |
4294 | | (colour_translation(F,S,Res) -> Result=Res ; Result=S). |
4295 | | |
4296 | | :- use_module(tools_printing,[get_terminal_colour_code/2, no_color/0]). |
4297 | | use_colour_codes :- \+ no_color, |
4298 | | get_preference(pp_with_terminal_colour,true). |
4299 | | colour_translation(F,S1,Result) :- use_colour_codes, |
4300 | | colour_construct(F,Colour),!, |
4301 | | get_terminal_colour_code(Colour,R1), |
4302 | | get_terminal_colour_code(reset,R2), |
4303 | | ajoin([R1,S1,R2],Result). |
4304 | | colour_construct(pred_true,green). |
4305 | | colour_construct(pred_false,red). |
4306 | | colour_construct(boolean_true,green). |
4307 | | colour_construct(boolean_false,red). |
4308 | | colour_construct(truth,green). |
4309 | | colour_construct(falsity,red). |
4310 | | colour_construct(_,blue). |
4311 | | |
4312 | | % pretty print a colour code if colours are enabled: |
4313 | | pp_colour_code(Colour) --> {use_colour_codes,get_terminal_colour_code(Colour,C), atom_codes(C,CC)},!,CC. |
4314 | | pp_colour_code(_) --> []. |
4315 | | |
4316 | | |
4317 | | quantified(general_sum,'SIGMA'). |
4318 | | quantified(general_product,'PI'). |
4319 | | quantified(quantified_union,'UNION'). |
4320 | | quantified(quantified_intersection,'INTER'). |
4321 | | quantified(lambda,X) :- atom_codes(X,[37]). |
4322 | | quantified(forall,'!'). |
4323 | | quantified(exists,'#'). |
4324 | | |
4325 | | |
4326 | | translate_prolog_constructor(C,R) :- unary_prefix(C,R,_),!. |
4327 | | translate_prolog_constructor(C,R) :- unary_postfix(C,R,_),!. |
4328 | | translate_prolog_constructor(C,R) :- binary_infix_in_mode(C,R,_,_),!. |
4329 | | translate_prolog_constructor(C,R) :- function_like_in_mode(C,R),!. |
4330 | | translate_prolog_constructor(C,R) :- constants_in_mode(C,R),!. |
4331 | | translate_prolog_constructor(C,R) :- quantified_in_mode(C,R),!. |
4332 | | |
4333 | | % translate the Prolog constuctor of an AST node into a form for printing to the user |
4334 | | translate_prolog_constructor_in_mode(Constructor,Result) :- |
4335 | | unicode_mode, |
4336 | | unicode_translation(Constructor,Unicode),!, Result=Unicode. |
4337 | | translate_prolog_constructor_in_mode(Constructor,Result) :- |
4338 | | latex_mode, |
4339 | | latex_translation(Constructor,Latex),!, Result=Latex. |
4340 | | translate_prolog_constructor_in_mode(C,R) :- translate_prolog_constructor(C,R). |
4341 | | |
4342 | | translate_subst_or_bexpr_in_mode(Mode,TExpr,String) :- |
4343 | | with_translation_mode(Mode, translate_subst_or_bexpr(TExpr,String)). |
4344 | | |
4345 | | |
4346 | | translate_bexpression_to_unicode(TExpr,String) :- |
4347 | | with_translation_mode(unicode, translate_bexpression(TExpr,String)). |
4348 | | |
4349 | | translate_bexpression(TExpr,String) :- |
4350 | | (pp_expr(TExpr,String) -> true |
4351 | | ; add_error(translate_bexpression,'Could not translate bexpression: ',TExpr),String='???'). |
4352 | | |
4353 | | translate_bexpression_to_codes(TExpr,Codes) :- |
4354 | | reset_pp, |
4355 | | pp_expr(TExpr,_,_LimitReached,Codes,[]). |
4356 | | |
4357 | | pp_expr(TExpr,String) :- |
4358 | | translate_bexpression_to_codes(TExpr,Codes), |
4359 | | atom_codes_with_limit(String, Codes). |
4360 | | |
4361 | | translate_bexpression_with_limit(T,S) :- translate_bexpression_with_limit(T,200,report_errors,S). |
4362 | | translate_bexpression_with_limit(TExpr,Limit,String) :- |
4363 | | translate_bexpression_with_limit(TExpr,Limit,report_errors,String). |
4364 | | translate_bexpression_with_limit(TExpr,Limit,report_errors,String) :- compound(String),!, |
4365 | | add_internal_error('Result is instantiated to a compound term:', |
4366 | | translate_bexpression_with_limit(TExpr,Limit,report_errors,String)),fail. |
4367 | | translate_bexpression_with_limit(TExpr,Limit,ReportErrors,String) :- |
4368 | | (catch_call(pp_expr_with_limit(TExpr,Limit,String)) -> true |
4369 | | ; (ReportErrors=report_errors, |
4370 | | add_error(translate_bexpression,'Could not translate bexpression: ',TExpr),String='???')). |
4371 | | |
4372 | | pp_expr_with_limit(TExpr,Limit,String) :- |
4373 | | set_up_limit_reached(Codes,Limit,LimitReached), |
4374 | | reset_pp, |
4375 | | pp_expr(TExpr,_,LimitReached,Codes,[]), |
4376 | | atom_codes_with_limit(String, Limit, Codes). |
4377 | | |
4378 | | |
4379 | | |
4380 | | % pretty-type an expression, if the expression has a priority >MinPrio, parenthesis |
4381 | | % can be ommitted, if not the expression has to be put into parenthesis |
4382 | | pp_expr_m(TExpr,MinPrio,LimitReached,S,Srest) :- |
4383 | | add_outer_paren(Prio,MinPrio,S,Srest,X,Xrest), % use co-routine to instantiate S as soon as possible |
4384 | | pp_expr(TExpr,Prio,LimitReached,X,Xrest). |
4385 | | |
4386 | | :- block add_outer_paren(-,?,?,?,?,?). |
4387 | | add_outer_paren(Prio,MinPrio,S,Srest,X,Xrest) :- |
4388 | | ( Prio > MinPrio -> % was >=, but problem with & / or with same priority or with non associative operators ! |
4389 | | S=X, Srest=Xrest |
4390 | | ; |
4391 | | [Open] = "(", [Close] = ")", |
4392 | | S = [Open|X], Xrest = [Close|Srest]). |
4393 | | % warning: if prio not set we will have a pending co-routine and instantiation_error in atom_codes later |
4394 | | |
4395 | | :- use_module(translate_keywords,[classical_b_keyword/1, translate_keyword_id/2]). |
4396 | | translated_identifier('_zzzz_binary',R) :- !, |
4397 | | (latex_mode -> R='z''''' ; R='z__'). % TO DO: could cause clash with user IDs |
4398 | | translated_identifier('_zzzz_unary',R) :- !, |
4399 | | (latex_mode -> R='z''' ; R='z_'). % TO DO: ditto |
4400 | | translated_identifier('__RANGE_LAMBDA__',R) :- !, |
4401 | | (latex_mode -> R='\\rho\'' ; unicode_mode -> R= '\x03c1\' % RHO |
4402 | | ; R = 'RANGE_LAMBDA__'). %ditto, could clash with user IDs !! |
4403 | | % TO DO: do we need to treat _prj_arg1__, _prj_arg2__, _lambda_result_ here ? |
4404 | | translated_identifier(ID,Result) :- |
4405 | | latex_mode,!, |
4406 | | my_greek_latex_escape_atom(ID,Greek,Res), %print_message(translate_latex(ID,Greek,Res)), |
4407 | | (Greek=greek -> Result = Res ; ajoin(['\\mathit{',Res,'}'],Result)). |
4408 | | translated_identifier(X,X). |
4409 | | |
4410 | | pp_identifier(Atom) --> {id_requires_escaping(Atom), \+ eventb_translation_mode, \+ latex_mode}, !, |
4411 | | ({atelierb_mode(_)} |
4412 | | -> pp_identifier_for_atelierb(Atom) |
4413 | | ; pp_backquoted_identifier(Atom) |
4414 | | ). |
4415 | | pp_identifier(Atom) --> ppatom_opt_scramble(Atom). |
4416 | | |
4417 | | % print atom using backquotes, we use same escaping rules as in a string |
4418 | | % requires B parser version 2.9.30 or newer |
4419 | | pp_backquoted_identifier(Atom) --> {atom_codes(Atom,Codes)}, pp_backquoted_id_codes(Codes). |
4420 | | pp_backquoted_id_codes(Codes) --> {append(Prefix,[0'. | Suffix],Codes), Suffix=[_|_]}, |
4421 | | !, % we need to split the id and quote each part separately; otherwise the parser will complain |
4422 | | % see issue https://github.com/hhu-stups/prob-issues/issues/321 |
4423 | | % However, ids with dots are not accepted for constants and variables; so this does not solve all problems |
4424 | | "`", pp_codes_opt_scramble(Prefix), "`.", % TODO: we could check if id_requires_escaping |
4425 | | pp_backquoted_id_codes(Suffix). |
4426 | | pp_backquoted_id_codes(Codes) --> "`", pp_codes_opt_scramble(Codes), "`". |
4427 | | |
4428 | | :- use_module(tools_strings,[is_simple_classical_b_identifier/1]). |
4429 | | id_requires_escaping(ID) :- classical_b_keyword(ID). |
4430 | | id_requires_escaping(ID) :- \+ is_simple_classical_b_identifier(ID). |
4431 | | |
4432 | | pp_identifier_for_atelierb(Atom) --> |
4433 | | {atom_codes(Atom,Codes), |
4434 | | strip_illegal_id_codes(Codes,Change,Codes2), |
4435 | | Change==true},!, |
4436 | | {atom_codes(A2,Codes2)}, |
4437 | | ppatom_opt_scramble(A2). |
4438 | | pp_identifier_for_atelierb(Atom) --> ppatom_opt_scramble(Atom). |
4439 | | |
4440 | | % remove illegal codes in an identifier (probably EventB or Z) |
4441 | | strip_illegal_id_codes([0'_ | T ],Change,[946 | TR]) :- !, Change=true, strip_illegal_id_codes(T,_,TR). |
4442 | | strip_illegal_id_codes(Codes,Change,Res) :- strip_illegal_id_codes2(Codes,Change,Res). |
4443 | | |
4444 | | strip_illegal_id_codes2([],_,[]). |
4445 | | strip_illegal_id_codes2([H|T],Change,Res) :- strip_code(H,Res,TR),!, Change=true, strip_illegal_id_codes2(T,_,TR). |
4446 | | strip_illegal_id_codes2([H|T],Change,[H|TR]) :- strip_illegal_id_codes2(T,Change,TR). |
4447 | | |
4448 | | strip_code(46,[0'_, 0'_ |T],T). % replace dot . by two underscores |
4449 | | strip_code(36,[946|T],T) :- T \= [48]. % replace dollar $ by beta unless it is $0 at the end |
4450 | | strip_code(92,[950|T],T). % replace dollar by zeta; probably from Zed |
4451 | | % TODO: add more symbols and ensure that the new codes do not exist |
4452 | | |
4453 | | |
4454 | | |
4455 | | :- use_module(tools,[latex_escape_atom/2]). |
4456 | | |
4457 | | greek_or_math_symbol(Symbol) :- greek_symbol(Symbol,_). |
4458 | | % other Latex math symbols |
4459 | | greek_or_math_symbol('varepsilon'). |
4460 | | greek_or_math_symbol('varphi'). |
4461 | | greek_or_math_symbol('varpi'). |
4462 | | greek_or_math_symbol('varrho'). |
4463 | | greek_or_math_symbol('varsigma'). |
4464 | | greek_or_math_symbol('vartheta'). |
4465 | | greek_or_math_symbol('vdash'). |
4466 | | greek_or_math_symbol('models'). |
4467 | | |
4468 | | greek_symbol('Alpha','\x0391\'). |
4469 | | greek_symbol('Beta','\x0392\'). |
4470 | | greek_symbol('Chi','\x03A7\'). |
4471 | | greek_symbol('Delta','\x0394\'). |
4472 | | greek_symbol('Epsilon','\x0395\'). |
4473 | | greek_symbol('Eta','\x0397\'). |
4474 | | greek_symbol('Gamma','\x0393\'). |
4475 | | greek_symbol('Iota','\x0399\'). |
4476 | | greek_symbol('Kappa','\x039A\'). |
4477 | | greek_symbol('Lambda','\x039B\'). |
4478 | | greek_symbol('Mu','\x039C\'). |
4479 | | greek_symbol('Nu','\x039D\'). |
4480 | | greek_symbol('Phi','\x03A6\'). |
4481 | | greek_symbol('Pi','\x03A0\'). |
4482 | | greek_symbol('Psi','\x03A8\'). |
4483 | | greek_symbol('Rho','\x03A1\'). |
4484 | | greek_symbol('Omega','\x03A9\'). |
4485 | | greek_symbol('Omicron','\x039F\'). |
4486 | | greek_symbol('Sigma','\x03A3\'). |
4487 | | greek_symbol('Theta','\x0398\'). |
4488 | | greek_symbol('Upsilon','\x03A5\'). |
4489 | | greek_symbol('Xi','\x039E\'). |
4490 | | greek_symbol('alpha','\x03B1\'). |
4491 | | greek_symbol('beta','\x03B2\'). |
4492 | | greek_symbol('delta','\x03B4\'). |
4493 | | greek_symbol('chi','\x03C7\'). |
4494 | | greek_symbol('epsilon','\x03B5\'). |
4495 | | greek_symbol('eta','\x03B7\'). |
4496 | | greek_symbol('gamma','\x03B3\'). |
4497 | | greek_symbol('iota','\x03B9\'). |
4498 | | greek_symbol('kappa','\x03BA\'). |
4499 | | greek_symbol('lambda','\x03BB\'). |
4500 | | greek_symbol('mu','\x03BC\'). |
4501 | | greek_symbol('nu','\x03BD\'). |
4502 | | greek_symbol('omega','\x03C9\'). |
4503 | | greek_symbol('omicron','\x03BF\'). |
4504 | | greek_symbol('pi','\x03C0\'). |
4505 | | greek_symbol('phi','\x03C6\'). |
4506 | | greek_symbol('psi','\x03C8\'). |
4507 | | greek_symbol('rho','\x03C1\'). |
4508 | | greek_symbol('sigma','\x03C3\'). |
4509 | | greek_symbol('tau','\x03C4\'). |
4510 | | greek_symbol('theta','\x03B8\'). |
4511 | | greek_symbol('upsilon','\x03C5\'). |
4512 | | greek_symbol('xi','\x03BE\'). |
4513 | | greek_symbol('zeta','\x03B6\'). |
4514 | | |
4515 | | |
4516 | | my_greek_latex_escape_atom(A,greek,Res) :- |
4517 | | greek_or_math_symbol(A),get_preference(latex_pp_greek_ids,true),!, |
4518 | | atom_concat('\\',A,Res). |
4519 | | my_greek_latex_escape_atom(A,no_greek,EA) :- latex_escape_atom(A,EA). |
4520 | | |
4521 | | % ppatom + scramble if BUGYLY is TRUE |
4522 | | ppatom_opt_scramble(Name) --> {get_preference(bugly_pp_scrambling,true)}, |
4523 | | % {\+ bmachine:b_top_level_operation(Name)}, % comment in to not change name of B operations |
4524 | | !, |
4525 | | {bugly_scramble_id(Name,ScrName)}, |
4526 | | ppatom(ScrName). |
4527 | | ppatom_opt_scramble(Name) --> |
4528 | | {primes_to_unicode(Name, UnicodeName)}, |
4529 | | pp_atom_opt_latex(UnicodeName). |
4530 | | |
4531 | | % Convert ASCII primes (apostrophes) in identifiers to Unicode primes |
4532 | | % so they can be parsed by the classical B parser. |
4533 | | primes_to_unicode(Name, UnicodeName) :- |
4534 | | atom_codes(Name, Codes), |
4535 | | phrase(primes_to_unicode(Codes), UCodes), |
4536 | | atom_codes(UnicodeName, UCodes). |
4537 | | primes_to_unicode([0'\'|T]) --> !, |
4538 | | "\x2032\", |
4539 | | primes_to_unicode(T). |
4540 | | primes_to_unicode([C|T]) --> !, |
4541 | | [C], |
4542 | | primes_to_unicode(T). |
4543 | | primes_to_unicode([]) --> "". |
4544 | | |
4545 | | :- use_module(tools,[b_string_escape_codes/2]). |
4546 | | :- use_module(tools_strings,[convert_atom_to_number/2]). |
4547 | | % a version of ppatom which encodes/quotes symbols inside strings such as quotes " |
4548 | | ppstring_opt_scramble(Name) --> {var(Name)},!,ppatom(Name). |
4549 | | ppstring_opt_scramble(Name) --> {compound(Name)},!, |
4550 | | {add_internal_error('Not an atom: ',ppstring_opt_scramble(Name,_,_))}, |
4551 | | "<<" ,ppterm(Name), ">>". |
4552 | | ppstring_opt_scramble(Name) --> {get_preference(bugly_pp_scrambling,true)},!, |
4553 | | pp_bugly_composed_string(Name). |
4554 | | ppstring_opt_scramble(Name) --> {atom_codes(Name,Codes),b_string_escape_codes(Codes,EscCodes)}, |
4555 | | pp_codes_opt_latex(EscCodes). |
4556 | | |
4557 | | % a version of ppstring_opt_scramble with codes list |
4558 | | pp_codes_opt_scramble(Codes) --> {get_preference(bugly_pp_scrambling,true)},!, |
4559 | | pp_bugly_composed_string_codes(Codes,[]). |
4560 | | pp_codes_opt_scramble(Codes) --> {b_string_escape_codes(Codes,EscCodes)}, |
4561 | | pp_codes_opt_latex(EscCodes). |
4562 | | |
4563 | | pp_bugly_composed_string(Name) --> {atom_codes(Name,Codes)}, |
4564 | | !, % we can decompose the string; scramble each string separately; TODO: provide option to define separators |
4565 | | % idea is that if we have a string with spaces or other special separators we preserve the separators |
4566 | | pp_bugly_composed_string_codes(Codes,[]). |
4567 | | |
4568 | | pp_bugly_composed_string_codes([],Acc) --> {atom_codes(Atom,Acc)}, pp_bugly_string(Atom). |
4569 | | pp_bugly_composed_string_codes(List,Acc) --> {decompose_string(List,Seps,T)},!, |
4570 | | {reverse(Acc,Rev),atom_codes(Atom,Rev)}, pp_bugly_string(Atom), |
4571 | | ppcodes(Seps), |
4572 | | pp_bugly_composed_string_codes(T,[]). |
4573 | | pp_bugly_composed_string_codes([H|T],Acc) --> pp_bugly_composed_string_codes(T,[H|Acc]). |
4574 | | |
4575 | | decompose_string([Sep|T],[Sep],T) :- bugly_separator(Sep). |
4576 | | % comment in and adapt for domain specific separators: |
4577 | | %decompose_string(List,Seps,T) :- member(Seps,["LEU","DEF","BAL"]), append(Seps,T,List). |
4578 | | %bugly_separator(10). |
4579 | | %bugly_separator(13). |
4580 | | bugly_separator(32). |
4581 | | bugly_separator(0'-). |
4582 | | bugly_separator(0'_). |
4583 | | bugly_separator(0',). |
4584 | | bugly_separator(0'.). |
4585 | | bugly_separator(0';). |
4586 | | bugly_separator(0':). |
4587 | | bugly_separator(0'#). |
4588 | | bugly_separator(0'[). |
4589 | | bugly_separator(0']). |
4590 | | bugly_separator(0'(). |
4591 | | bugly_separator(0')). |
4592 | | |
4593 | | % scramble and pretty print individual strings or components of strings |
4594 | | pp_bugly_string('') --> !, []. |
4595 | | pp_bugly_string(Name) --> |
4596 | | {convert_atom_to_number(Name,_)},!, % do not scramble numbers; we could check if LibraryStrings is available |
4597 | | pp_atom_opt_latex(Name). |
4598 | | pp_bugly_string(Name) --> |
4599 | | {bugly_scramble_id(Name,ScrName)}, |
4600 | | ppatom(ScrName). |
4601 | | |
4602 | | % ------------ |
4603 | | |
4604 | | pp_atom_opt_latex(Name) --> {latex_mode},!, |
4605 | | {my_greek_latex_escape_atom(Name,_,EscName)}, |
4606 | | % should we add \mathrm{.} or \mathit{.}? |
4607 | | ppatom(EscName). |
4608 | | pp_atom_opt_latex(Name) --> ppatom(Name). |
4609 | | |
4610 | | % a version of pp_atom_opt_latex working with codes |
4611 | | pp_codes_opt_latex(Codes) --> {latex_mode},!, |
4612 | | {atom_codes(Name,Codes),my_greek_latex_escape_atom(Name,_,EscName)}, |
4613 | | ppatom(EscName). |
4614 | | pp_codes_opt_latex(Codes) --> ppcodes(Codes). |
4615 | | |
4616 | | pp_atom_opt_latex_mathit(Name) --> {latex_mode},!, |
4617 | | {latex_escape_atom(Name,EscName)}, |
4618 | | "\\mathit{",ppatom(EscName),"}". |
4619 | | pp_atom_opt_latex_mathit(Name) --> ppatom(Name). |
4620 | | |
4621 | | pp_atom_opt_mathit(EscName) --> {latex_mode},!, |
4622 | | % we assume already escaped |
4623 | | "\\mathit{",ppatom(EscName),"}". |
4624 | | pp_atom_opt_mathit(Name) --> ppatom(Name). |
4625 | | |
4626 | | pp_space --> {latex_mode},!, "\\ ". |
4627 | | pp_space --> " ". |
4628 | | |
4629 | | opt_scramble_id(ID,Res) :- get_preference(bugly_pp_scrambling,true),!, |
4630 | | bugly_scramble_id(ID,Res). |
4631 | | opt_scramble_id(ID,ID). |
4632 | | |
4633 | | :- use_module(probsrc(gensym),[gensym/2]). |
4634 | | :- dynamic bugly_scramble_id_cache/2. |
4635 | | bugly_scramble_id(ID,Res) :- var(ID),!, add_internal_error('Illegal call: ',bugly_scramble_id(ID,Res)), ID=Res. |
4636 | | bugly_scramble_id(ID,Res) :- bugly_scramble_id_cache(ID,ScrambledID),!, |
4637 | | Res=ScrambledID. |
4638 | | bugly_scramble_id(ID,Res) :- %print(gen_id(ID,Res)),nl, |
4639 | | genbuglynr(Nr), |
4640 | | gen_bugly_id(Nr,ScrambledID), |
4641 | | assertz(bugly_scramble_id_cache(ID,ScrambledID)), |
4642 | | %format(user_output,'BUGLY scramble ~w --> ~w~n',[ID,ScrambledID]), |
4643 | | Res = ScrambledID. |
4644 | | |
4645 | | gen_bugly_id_codes(Nr,[Char|TC]) :- Char is 97+ Nr mod 26, |
4646 | | (Nr> 25 -> N1 is Nr // 26, gen_bugly_id_codes(N1,TC) ; TC=[]). |
4647 | | gen_bugly_id(Nr,ScrambledID) :- gen_bugly_id_codes(Nr,Codes), atom_codes(ScrambledID,[97,97|Codes]). |
4648 | | %gen_bugly_id(Nr,ScrambledID) :- ajoin(['aa',Nr],ScrambledID). % old version using aaNr |
4649 | | |
4650 | | :- dynamic bugly_count/1. |
4651 | | bugly_count(0). |
4652 | | genbuglynr(Nr) :- |
4653 | | retract(bugly_count(Nr)), N1 is Nr + 1, |
4654 | | assertz(bugly_count(N1)). |
4655 | | |
4656 | | |
4657 | | is_lambda_result_id(b(identifier(ID),_,_INFO),Suffix) :- % _INFO=[lambda_result], sometiems _INFO=[] |
4658 | | is_lambda_result_name(ID,Suffix). |
4659 | | is_lambda_result_name(LAMBDA_RESULT,Suffix) :- atomic(LAMBDA_RESULT), |
4660 | | atom_codes(LAMBDA_RESULT,[95,108,97,109,98,100,97,95,114,101,115,117,108,116,95|Suffix]). % _lambda_result_ |
4661 | | |
4662 | | pp_expr(TE,P) --> %{print('OBSOLETE'),nl,nl}, |
4663 | | pp_expr(TE,P,_LimitReached). |
4664 | | |
4665 | | pp_expr(TExpr,Prio,_) --> {var(TExpr)},!,"_",{Prio=500}. |
4666 | | pp_expr(_,Prio,LimitReached) --> {LimitReached==limit_reached},!,"...",{Prio=500}. |
4667 | | pp_expr(b(Expr,Type,Info),Prio,LimitReached) --> !, |
4668 | | pp_expr0(Expr,Type,Info,Prio,LimitReached). |
4669 | | pp_expr(Expr,Prio,LimitReached) --> |
4670 | | pp_expr1(Expr,any,[],Prio,LimitReached). |
4671 | | |
4672 | | pp_expr0(identifier(ID),_Type,_Info,Prio,_LimitReached) --> {is_lambda_result_name(ID,Suffix)},!, {Prio=500}, |
4673 | | {append("LAMBDA_RESULT___",Suffix,ASCII), atom_codes(R,ASCII)}, ppatom(R). |
4674 | | pp_expr0(Expr,_Type,Info,Prio,_LimitReached) --> |
4675 | | {eventb_translation_mode}, |
4676 | | pp_theory_operator(Expr,Info,Prio),!. |
4677 | | pp_expr0(Expr,Type,Info,Prio,LimitReached) --> |
4678 | | {check_info(Expr,Type,Info)}, |
4679 | | pp_rodin_label(Info), |
4680 | | (pp_expr1(Expr,Type,Info,Prio,LimitReached) -> {true} |
4681 | | ; {add_error(translate,'Could not translate:',Expr,Expr),fail} |
4682 | | ). |
4683 | | |
4684 | | check_info(Expr,_,Info) :- var(Info), add_error(translate,'Illegal variable info field for expression: ', Expr),fail. |
4685 | | check_info(_,_,_). |
4686 | | |
4687 | | pp_theory_operator(general_sum(_,Membercheck,_),_Info,500) --> |
4688 | | {get_texpr_expr(Membercheck,member(_,Arg))}, |
4689 | | ppatom('SUM('),pp_expr(Arg,_),ppatom(')'). |
4690 | | pp_theory_operator(general_product(_,Membercheck,_),_Info,500) --> |
4691 | | {get_texpr_expr(Membercheck,member(_Couple,Arg))}, |
4692 | | ppatom('PRODUCT('),pp_expr(Arg,_),ppatom(')'). |
4693 | | pp_theory_operator(function(_,Arg),Info,500) --> |
4694 | | {memberchk_in_info(theory_operator(O,N),Info),decouplise_expr(N,Arg,Args)}, |
4695 | | ppatom(O),"(",pp_expr_l_sep(Args,",",_LR),")". |
4696 | | pp_theory_operator(member(Arg,_),Info,500) --> |
4697 | | {memberchk_in_info(theory_operator(O,N),Info),decouplise_expr(N,Arg,Args)}, |
4698 | | ppatom(O),"(",pp_expr_l_sep(Args,",",_LR),")". |
4699 | | |
4700 | | decouplise_expr(1,E,R) :- !,R=[E]. |
4701 | | decouplise_expr(N,E,R) :- |
4702 | | get_texpr_expr(E,couple(A,B)),!, |
4703 | | N2 is N-1, |
4704 | | decouplise_expr(N2,A,R1),append(R1,[B],R). |
4705 | | decouplise_expr(N,E,[E]) :- |
4706 | | print_message(call_failed(decouplise_expr(N,E,_))),nl. |
4707 | | |
4708 | | % will pretty print (first) rodin or pragma label |
4709 | | pp_rodin_label(_Infos) --> {preference(translate_suppress_rodin_positions_flag,true),!}. |
4710 | | pp_rodin_label(_Infos) --> {preference(bugly_pp_scrambling,true),!}. |
4711 | | pp_rodin_label(Infos) --> {var(Infos)},!, "/* ILLEGAL VARIABLE INFO FIELD */". |
4712 | | pp_rodin_label(Infos) --> {get_info_labels(Infos,Label)},!, |
4713 | | pp_start_label_pragma, |
4714 | | ppatoms_opt_latex(Label), |
4715 | | pp_end_label_pragma. |
4716 | | pp_rodin_label(Infos) --> {preference(pp_wd_infos,true)},!, pp_wd_info(Infos). |
4717 | | pp_rodin_label(_Infos) --> []. |
4718 | | |
4719 | | % print infos about well-definedness attached to AST node: |
4720 | | pp_wd_info(Infos) --> {member(discharged_wd_po,Infos)},!, "/*D", |
4721 | | ({member(contains_wd_condition,Infos)} -> "-WD*/ " ; "*/ "). |
4722 | | pp_wd_info(Infos) --> {member(contains_wd_condition,Infos)},!, "/*WD*/ ". |
4723 | | pp_wd_info(_Infos) --> []. |
4724 | | |
4725 | | pp_start_label_pragma --> |
4726 | | {(atelierb_mode(Mode), Mode == pp |
4727 | | ; get_preference(translate_print_typing_infos,true))}, % proxy for parseable; |
4728 | | % set by translate_bvalue_to_parseable_classicalb; important for parsertests with labels |
4729 | | !, |
4730 | | "/*@label ". |
4731 | | pp_start_label_pragma --> "/* @". % shorter version, for viewing in UI |
4732 | | pp_end_label_pragma --> " */ ". |
4733 | | |
4734 | | ppatoms([]) --> !, []. |
4735 | | ppatoms([ID|T]) --> !,ppatom(ID), " ", ppatoms(T). |
4736 | | ppatoms(X) --> {add_error(ppatoms,'Not a list of atoms: ',ppatoms(X))}. |
4737 | | |
4738 | | ppatoms_opt_latex([]) --> !, []. |
4739 | | ppatoms_opt_latex([ID]) --> !,pp_atom_opt_latex(ID). |
4740 | | ppatoms_opt_latex([ID|T]) --> !,pp_atom_opt_latex(ID), " ", ppatoms_opt_latex(T). |
4741 | | ppatoms_opt_latex(X) --> {add_error(ppatoms_opt_latex,'Not a list of atoms: ',ppatoms_opt_latex(X))}. |
4742 | | |
4743 | | %:- use_module(bsyntaxtree,[is_set_type/2]). |
4744 | | :- load_files(library(system), [when(compile_time), imports([environ/2])]). |
4745 | | pp_expr1(Expr,_,_,Prio,_) --> {var(Expr)},!,"_",{Prio=500}. |
4746 | | pp_expr1(event_b_comprehension_set(Ids,E,P),Type,_Info,Prio,LimitReached) --> |
4747 | | {b_ast_cleanup:rewrite_event_b_comprehension_set(Ids,E,P,Type, NewExpression)},!, |
4748 | | pp_expr(NewExpression,Prio,LimitReached). |
4749 | | pp_expr1(union(b(event_b_identity,Type,_), b(closure(Rel),Type,_)),_,Info,500,LimitReached) --> |
4750 | | /* closure(Rel) = id \/ closure1(Rel) */ |
4751 | | {member_in_info(was(reflexive_closure),Info)},!, |
4752 | | "closure(",pp_expr(Rel,_,LimitReached),")". |
4753 | | pp_expr1(comprehension_set([_],_),_,Info,500,_LimitReached) --> |
4754 | | {memberchk_in_info(freetype(P),Info),!},ppatom(P). |
4755 | | % used instead of constants(Expr,Symbol) case below: |
4756 | | pp_expr1(greater_equal(A,Y),Type,Info,Prio,LimitReached) --> % x:NATURAL was rewritten to x>=0, see test 499, 498 |
4757 | | {memberchk_in_info(was(member(A,B)),Info), get_integer(Y,_)}, |
4758 | | pp_expr1(member(A,B),Type,Info,Prio,LimitReached). |
4759 | | pp_expr1(comprehension_set([TID],b(B,_,_)),Type,Info,Prio,LimitReached) --> |
4760 | | {memberchk_in_info(was(integer_set(S)),Info)}, |
4761 | | {S='INTEGER' -> B=truth |
4762 | | ; get_texpr_id(TID,ID), |
4763 | | B=greater_equal(TID2,Y), get_integer(Y,I), |
4764 | | get_texpr_id(TID2,ID), |
4765 | | (I=0 -> S='NATURAL' ; I=1,S='NATURAL1')}, % TO DO: check bounds |
4766 | | !, |
4767 | | pp_expr1(integer_set(S),Type,Info,Prio,LimitReached). |
4768 | | pp_expr1(interval(b(A,_,_),B),Type,Info,Prio,LimitReached) --> |
4769 | | {memberchk_in_info(was(integer_set(S)),Info)}, |
4770 | | {B=b(max_int,integer,_)}, % TO DO ? allow value(int(Mx)) |
4771 | | {A=min_int -> S='INT' ; A=integer(0) -> S='NAT' ; A=integer(1),S='NAT1'}, |
4772 | | !, |
4773 | | pp_expr1(integer_set(S),Type,Info,Prio,LimitReached). |
4774 | | pp_expr1(falsity,_,Info,Prio,LimitReached) --> {memberchk_in_info(was(Pred),Info)},!, |
4775 | | ({(unicode_mode ; latex_mode)} |
4776 | | -> {translate_in_mode(falsity,'falsity',Symbol)}, |
4777 | | ppatom(Symbol), |
4778 | | ({get_preference(pp_propositional_logic_mode,true)} -> {true} |
4779 | | ; " ", enter_comment, " ", pp_expr2(Pred,Prio,LimitReached), " ", exit_comment) |
4780 | | ; enter_comment, " falsity ",exit_comment, " ", |
4781 | | pp_expr2(Pred,Prio,LimitReached)). % Pred is not wrapped |
4782 | | pp_expr1(truth,_,Info,Prio,LimitReached) --> {memberchk_in_info(was(Pred),Info)},!, |
4783 | | ({(unicode_mode ; latex_mode)} |
4784 | | -> {translate_in_mode(truth,'truth',Symbol)}, |
4785 | | ppatom(Symbol), |
4786 | | ({get_preference(pp_propositional_logic_mode,true)} -> {true} |
4787 | | ; " ",enter_comment, " ", pp_expr2(Pred,Prio,LimitReached), " ", exit_comment) |
4788 | | ; enter_comment, " truth ", exit_comment, " ", |
4789 | | pp_expr2(Pred,Prio,LimitReached)). % Pred is not wrapped |
4790 | | % TO DO: do this for other expressions as well; but then we have to ensure that ast_cleanup generates complete was(_) infos |
4791 | | % :- load_files(library(system), [when(compile_time), imports([environ/2])]). % directive moved above to avoid Spider warning |
4792 | | pp_expr1(event_b_identity,Type,_Info,500,_LimitReached) --> |
4793 | | {\+ eventb_translation_mode}, %{atelierb_mode(Mode), Mode == pp}, |
4794 | | {is_set_type(Type,couple(ElType,ElType))}, |
4795 | | !, |
4796 | | "id(", {pretty_normalized_type(ElType,S)},ppatom(S), ")". |
4797 | | pp_expr1(typeset,SType,_Info,500,_LimitReached) --> % normally removed by ast_cleanup |
4798 | | {is_set_type(SType,Type)}, |
4799 | | !, |
4800 | | ({normalized_type_requires_outer_paren(Type)} -> "(" ; ""), |
4801 | | {pretty_normalized_type(Type,S)},ppatom(S), |
4802 | | ({normalized_type_requires_outer_paren(Type)} -> ")" ; ""). |
4803 | | :- if(environ(prob_safe_mode,true)). |
4804 | | pp_expr1(exists(Parameters,_),_,Info,_Prio,_LimitReached) --> |
4805 | | {\+ member_in_info(used_ids(_),Info), |
4806 | | add_error(translate,'Missing used_ids Info for exists: ',Parameters:Info),fail}. |
4807 | | %pp_expr1(exists(Ids,P1),_,Info,250) --> !, { member_in_info(used_ids(Used),Info)}, |
4808 | | % exists_symbol,pp_expr_ids_in_mode(Ids,LimitReached), |
4809 | | % {add_normal_typing_predicates(Ids,P1,P)}, |
4810 | | % " /* Used = ", ppterm(Used), " */ ", |
4811 | | % ".",pp_expr_m(P,221). |
4812 | | :- endif. |
4813 | | pp_expr1(Expr,Type,Info,Prio,LimitReached) --> {member_in_info(sharing(ID,Count,_,_),Info),number(Count),Count>1},!, |
4814 | | "( ",enter_comment," CSE ",ppnumber(ID), ":#", ppnumber(Count), |
4815 | | ({member_in_info(negated_cse,Info)} -> " (neg) " ; " "), |
4816 | | ({member_in_info(contains_wd_condition,Info)} -> " (wd) " ; " "), |
4817 | | exit_comment, " ", |
4818 | | {delete(Info,sharing(_,_,_,_),Info2)}, |
4819 | | pp_expr1(Expr,Type,Info2,Prio,LimitReached), ")". |
4820 | | %pp_expr1(Expr,_,Info,Prio) --> {member_in_info(contains_wd_condition,Info)},!, |
4821 | | % "( /* (wd) */ ", pp_expr2(Expr,Prio), ")". |
4822 | | % pp_expr1(Expr,subst,_Info,Prio) --> !, translate_subst2(Expr,Prio). % TO DO: also allow substitutions here |
4823 | | pp_expr1(value(V),Type,_,Prio,LimitReached) --> !, |
4824 | | {(nonvar(V),V=closure(_,_,_) -> Prio=300 ; Prio=500)}, pp_value_with_type(V,Type,LimitReached). |
4825 | | pp_expr1(comprehension_set(Ids,P1),_,Info,500,LimitReached) --> !, |
4826 | | pp_comprehension_set(Ids,P1,Info,LimitReached). |
4827 | | %pp_expr1(Expr,_,Info,Prio,LimitReached) --> {pp_is_important_info_field(Expr,Info,_)}, |
4828 | | % !, pp_important_infos(Expr,Info), pp_expr2(Expr,Prio,LimitReached). |
4829 | | pp_expr1(first_of_pair(X),_,Info,500,LimitReached) --> {was_eventb_destructor(Info,X,Op,Arg)},!, |
4830 | | ppatom(Op), "(",pp_expr(Arg,_,LimitReached), ")". |
4831 | | pp_expr1(second_of_pair(X),_,Info,500,LimitReached) --> {was_eventb_destructor(Info,X,Op,Arg)},!, |
4832 | | ppatom(Op), "(",pp_expr(Arg,_,LimitReached), ")". |
4833 | | %pp_expr1(let_expression(_Ids,Exprs,_P),_Type,Info,500,LimitReached) --> |
4834 | | % % pretty print direct definition operator calls, which get translated using create_z_let |
4835 | | % % However: the lets can get removed; in which case the translated direct definition will be pretty printed |
4836 | | % % also: what if the body of the let has been modified ?? |
4837 | | % {member(was(extended_expr(DirectDefOp)),Info), |
4838 | | % bmachine_eventb:stored_operator_direct_definition(DirectDefOp,_Proj,_Theory,Parameters,_Def,_WD,_TypeParas,_Kind), |
4839 | | % %length(Exprs,Arity),,length(Parameters,Arity1), write(found_dd(DirectDefOp,Arity1,Arity2,Proj,Theory)),nl, |
4840 | | % same_length(Parameters,ActualParas), %same_length(TypeParameters,TP), |
4841 | | % append(ActualParas,_TP,Exprs) |
4842 | | % }, |
4843 | | % !, |
4844 | | % ppatom(DirectDefOp), |
4845 | | % pp_expr_wrap_l('(',ActualParas,')',LimitReached). |
4846 | | pp_expr1(Expr,_,_Info,Prio,LimitReached) --> pp_expr2(Expr,Prio,LimitReached). |
4847 | | |
4848 | | was_eventb_destructor(Info,X,Op,Arg) :- eventb_translation_mode, |
4849 | | member(was(extended_expr(Op)),Info),peel_projections(X,Arg). |
4850 | | is_projection(first_of_pair(A),A). |
4851 | | is_projection(second_of_pair(A),A). |
4852 | | % peel projections constructed for Event-B destructor operator |
4853 | | peel_projections(b(A,_,_),R) :- |
4854 | | (is_projection(A,RA) -> peel_projections(RA,R) |
4855 | | ; A = freetype_destructor(_,_,R)). |
4856 | | |
4857 | | |
4858 | | :- public pp_important_infos/4. % debugging utility |
4859 | | pp_important_infos(Expr,Info) --> |
4860 | | {findall(PPI,pp_is_important_info_field(Expr,Info,PPI),PPInfos), PPInfos \= []}, |
4861 | | " ", enter_comment, ppterm(PPInfos), exit_comment, " ". |
4862 | | pp_is_important_info_field(_,Infos,'DO_NOT_ENUMERATE'(X)) :- member(prob_annotation('DO_NOT_ENUMERATE'(X)),Infos). |
4863 | | pp_is_important_info_field(exists(_,_),Infos,'LIFT') :- member(allow_to_lift_exists,Infos). |
4864 | | pp_is_important_info_field(exists(_,_),Infos,used_ids(Used)) :- member(used_ids(Used),Infos). |
4865 | | pp_is_important_info_field(exists(_,_),Infos,'(wd)') :- member(contains_wd_condition,Infos). |
4866 | | |
4867 | | |
4868 | | pp_expr2(Expr,_,_LimitReached) --> {var(Expr)},!,"_". |
4869 | | pp_expr2(_,_,LimitReached) --> {LimitReached==limit_reached},!,"...". |
4870 | | pp_expr2(atom_string(V),500,_) --> !,pp_atom_opt_latex_mathit(V). % hardwired_atom |
4871 | | pp_expr2(global_set(V),500,_) --> !, pp_identifier(V). |
4872 | | pp_expr2(freetype_set(V),500,_) --> !,{pretty_freetype(V,P)},ppatom_opt_scramble(P). |
4873 | | pp_expr2(lazy_lookup_expr(I),500,_) --> !, pp_identifier(I). |
4874 | | pp_expr2(lazy_lookup_pred(I),500,_) --> !, pp_identifier(I). |
4875 | | pp_expr2(identifier(I),500,_) --> !, |
4876 | | {( I=op(Id) -> true; I=Id)}, |
4877 | | ( {atomic(Id)} -> ({translated_identifier(Id,TId)}, |
4878 | | ({latex_mode} -> ppatom(TId) ; pp_identifier(TId))) |
4879 | | ; |
4880 | | "'",ppterm(Id), "'"). |
4881 | | pp_expr2(integer(N),500,_) --> !, ppnumber(N). |
4882 | | pp_expr2(real(N),500,_) --> !, ppatom(N). |
4883 | | pp_expr2(integer_set(S),500,_) --> !, |
4884 | | {integer_set_mapping(S,T)},ppatom(T). |
4885 | | pp_expr2(string(S),500,_) --> !, string_start_symbol, ppstring_opt_scramble(S), string_end_symbol. |
4886 | | pp_expr2(set_extension(Ext),500,LimitReached) --> !, {set_brackets(L,R)}, |
4887 | | pp_expr_wrap_l(L,Ext,R,LimitReached). |
4888 | | pp_expr2(sequence_extension(Ext),500,LimitReached) --> !, |
4889 | | pp_begin_sequence, |
4890 | | ({get_preference(translate_print_cs_style_sequences,true)} -> pp_expr_l_sep(Ext,"",LimitReached) |
4891 | | ; pp_expr_l_sep(Ext,",",LimitReached)), |
4892 | | pp_end_sequence. |
4893 | | pp_expr2(assign(LHS,RHS),10,LimitReached) --> !, |
4894 | | pp_expr_wrap_l(',',LHS,'',LimitReached), ":=", pp_expr_wrap_l(',',RHS,'',LimitReached). |
4895 | | pp_expr2(assign_single_id(LHS,RHS),10,LimitReached) --> !, pp_expr2(assign([LHS],[RHS]),10,LimitReached). |
4896 | | pp_expr2(parallel(RHS),10,LimitReached) --> !, |
4897 | | pp_expr_wrap_l('||',RHS,'',LimitReached). |
4898 | | pp_expr2(sequence(RHS),10,LimitReached) --> !, |
4899 | | pp_expr_wrap_l(';',RHS,'',LimitReached). |
4900 | | 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 |
4901 | | pp_event_b_comprehension_set(Ids,E,P1,LimitReached). |
4902 | | pp_expr2(recursive_let(Id,S),500,LimitReached) --> !, |
4903 | | ({eventb_translation_mode} -> "" % otherwise we get strange characters in Rodin |
4904 | | ; enter_comment," recursive ID ", pp_expr(Id,_,LimitReached), " ", exit_comment), |
4905 | | pp_expr(S,_,LimitReached). |
4906 | | pp_expr2(image(A,B),300,LimitReached) --> !, |
4907 | | 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 |
4908 | | pp_expr_m(B,0,LimitReached),"]". % was 500, now set to 0: we never need an outer pair of () !? |
4909 | | pp_expr2(function(A,B),300,LimitReached) --> !, |
4910 | | 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 |
4911 | | pp_function_left_bracket, |
4912 | | pp_expr_m(B,0,LimitReached), % was 500, now set to 0: we never need an outer pair of () !? |
4913 | | pp_function_right_bracket. |
4914 | | pp_expr2(definition(A,B),300,LimitReached) --> !, % definition call; usually inlined,... |
4915 | | ppatom(A), |
4916 | | pp_function_left_bracket, |
4917 | | pp_expr_l_sep(B,",",LimitReached), |
4918 | | pp_function_right_bracket. |
4919 | | pp_expr2(operation_call_in_expr(A,B),300,LimitReached) --> !, |
4920 | | pp_expr_m(A,249,LimitReached), |
4921 | | pp_function_left_bracket, |
4922 | | pp_expr_l_sep(B,",",LimitReached), |
4923 | | pp_function_right_bracket. |
4924 | | pp_expr2(enumerated_set_def(GS,ListEls),200,LimitReached) --> !, % for pretty printing enumerate set defs |
4925 | | {reverse(ListEls,RLE)}, /* they have been inserted in inverse order */ |
4926 | | pp_identifier(GS), "=", pp_expr_wrap_l('{',RLE,'}',LimitReached). |
4927 | | pp_expr2(forall(Ids,D1,P),Prio,LimitReached) --> !, |
4928 | | ({eventb_translation_mode} -> {Prio=60} ; {Prio=250}), % in Rodin forall/exists cannot be mixed with &, or, <=>, ... |
4929 | | forall_symbol,pp_expr_ids_in_mode(Ids,LimitReached), |
4930 | | {add_normal_typing_predicates(Ids,D1,D)}, |
4931 | | dot_symbol,pp_expr_m(b(implication(D,P),pred,[]),221,LimitReached). |
4932 | | pp_expr2(exists(Ids,P1),Prio,LimitReached) --> !, |
4933 | | ({eventb_translation_mode} -> {Prio=60} ; {Prio=250}), % exists has Prio 250, but dot has 220 |
4934 | | exists_symbol,pp_expr_ids_in_mode(Ids,LimitReached), |
4935 | | {add_normal_typing_predicates(Ids,P1,P)}, |
4936 | | dot_symbol, |
4937 | | ({eventb_translation_mode} -> {MinPrio=29} ; {MinPrio=500}), |
4938 | | % 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 |
4939 | | % In Event-B ∃y·y>x ∧ (y=x+1 ∨ y=x+2) is valid and requires no outer parenthesis |
4940 | | pp_expr_m(P,MinPrio,LimitReached). |
4941 | | pp_expr2(record_field(R,I),250,LimitReached) --> !, |
4942 | | pp_expr_m(R,251,LimitReached),"'",pp_identifier(I). |
4943 | | pp_expr2(rec(Fields),500,LimitReached) --> !, |
4944 | | {function_like_in_mode(rec,Symbol)}, |
4945 | | ppatom(Symbol), "(",pp_expr_fields(Fields,LimitReached),")". |
4946 | | pp_expr2(struct(Rec),500,LimitReached) --> |
4947 | | {get_texpr_expr(Rec,rec(Fields)),Val=false ; get_texpr_expr(Rec,value(rec(Fields)))},!, |
4948 | | {function_like_in_mode(struct,Symbol)}, |
4949 | | ppatom(Symbol), "(", |
4950 | | ({Val==false} -> pp_expr_fields(Fields,LimitReached) |
4951 | | ; pp_value_l(Fields,',',LimitReached)), |
4952 | | ")". |
4953 | | pp_expr2(freetype_case(_FT,L,Expr),Prio,LimitReached) --> !, |
4954 | | %{Prio=500}, pp_freetype_term('__is_ft_case',FT,L,Expr,LimitReached). |
4955 | | % we now pretty-print it as Expr : ran(L) assuming there is a constant L generated for every case |
4956 | | {FTCons = b(identifier(L),any,[]), RanFTCons = b(range(FTCons),any,[])}, |
4957 | | pp_expr(b(member(Expr,RanFTCons),pred,[]),Prio,LimitReached). |
4958 | | pp_expr2(freetype_constructor(_FT,Case,Expr),Prio,LimitReached) --> !, |
4959 | | {FTCons = b(identifier(Case),any,[])}, |
4960 | | pp_expr(b(function(FTCons,Expr),any,[]),Prio,LimitReached). |
4961 | | % ppatom_opt_scramble(Case),ppatom('('),pp_expr(Expr,_,LimitReached),ppatom(')'). |
4962 | | pp_expr2(freetype_destructor(_FT,Case,Expr),Prio,LimitReached) --> !, |
4963 | | % pretty print it as: Case~(Expr) |
4964 | | {FTCons = b(identifier(Case),any,[]), Destr = b(reverse(FTCons),any,[])}, |
4965 | | pp_expr(b(function(Destr,Expr),any,[]),Prio,LimitReached). |
4966 | | % ({unicode_mode} |
4967 | | % -> {unicode_translation(reverse,PowMinus1Symbol)}, |
4968 | | % ppatom(Case),ppatom(PowMinus1Symbol), % Note: we do not print the freetype's name FT |
4969 | | % "(",pp_expr_m(Expr,0,LimitReached),")" |
4970 | | % ; pp_freetype_term('__ft~',FT,Case,Expr,LimitReached) % TODO: maybe find better print |
4971 | | % ). |
4972 | | pp_expr2(let_predicate(Ids,Exprs,P),1,LimitReached) --> !, |
4973 | | pp_expr_let_exists(Ids,Exprs,P,LimitReached). % instead of pp_expr_let |
4974 | | pp_expr2(let_expression(Ids,Exprs,P),1,LimitReached) --> !, |
4975 | | pp_expr_let(Ids,Exprs,P,LimitReached). |
4976 | | pp_expr2(let_expression_global(Ids,Exprs,P),1,LimitReached) --> !, " /", "* global *", "/ ", |
4977 | | pp_expr_let(Ids,Exprs,P,LimitReached). |
4978 | | pp_expr2(lazy_let_pred(Id,Expr,P),Pr,LimitReached) --> !, pp_expr2(lazy_let_expr(Id,Expr,P),Pr,LimitReached). |
4979 | | pp_expr2(lazy_let_subst(Id,Expr,P),Pr,LimitReached) --> !, pp_expr2(lazy_let_expr(Id,Expr,P),Pr,LimitReached). |
4980 | | pp_expr2(lazy_let_expr(Id,Expr,P),1,LimitReached) --> !, |
4981 | | pp_expr_let([Id],[Expr],P,LimitReached). |
4982 | | pp_expr2(norm_conjunct(Cond,[]),1,LimitReached) --> !, % norm_conjunct: flattened version generated by b_interpreter_check,... |
4983 | | "( ",pp_expr(Cond,_,LimitReached), ")". |
4984 | | pp_expr2(norm_conjunct(Cond,[H|T]),1,LimitReached) --> !, |
4985 | | "( ",pp_expr(Cond,_,LimitReached), ") ", and_symbol, " (", pp_expr2(norm_conjunct(H,T),_,LimitReached), ")". |
4986 | | pp_expr2(assertion_expression(Cond,Msg,Expr),1,LimitReached) --> !, |
4987 | | " ASSERT_EXPR (", |
4988 | | pp_expr_m(b(convert_bool(Cond),pred,[]),30,LimitReached), ",", |
4989 | | pp_expr_m(string(Msg),30,LimitReached), ",", |
4990 | | pp_expr_m(Expr,30,LimitReached), |
4991 | | " )". |
4992 | | %pp_expr2(assertion_expression(Cond,_Msg,Expr),1) --> !, |
4993 | | % "__ASSERT ",pp_expr_m(Cond,30), |
4994 | | % " IN ", pp_expr_m(Expr,30). |
4995 | | pp_expr2(partition(S,Elems),500,LimitReached) --> |
4996 | | {eventb_translation_mode ; |
4997 | | \+ atelierb_mode(_), length(Elems,Len), Len>50 % we need to print a quadratic number of disjoints |
4998 | | },!, |
4999 | | "partition(",pp_expr(S,_,LimitReached), |
5000 | | ({Elems=[]} -> ")" ; pp_expr_wrap_l(',',Elems,')',LimitReached)). |
5001 | | pp_expr2(partition(S,Elems),500,LimitReached) --> !, |
5002 | | "(",pp_expr(S,_,LimitReached), " = ", |
5003 | | ({Elems=[]} -> "{})" |
5004 | | ; pp_expr_l_sep(Elems,"\\/",LimitReached), pp_all_disjoint(Elems,LimitReached),")"). |
5005 | | pp_expr2(finite(S),Prio,LimitReached) --> {\+ eventb_translation_mode}, %{atelierb_mode(_)}, |
5006 | | !, |
5007 | | pp_expr2(member(S,b(fin_subset(S),set(any),[])),Prio,LimitReached). |
5008 | | pp_expr2(if_then_else(If,Then,Else),1,LimitReached) --> {animation_minor_mode(z)},!, |
5009 | | "\\IF ",pp_expr_m(If,30,LimitReached), |
5010 | | " \\THEN ",pp_expr_m(Then,30,LimitReached), |
5011 | | " \\ELSE ",pp_expr_m(Else,30,LimitReached). |
5012 | | %pp_expr2(if_then_else(If,Then,Else),1) --> {unicode_mode},!, |
5013 | | % "if ",pp_expr_m(If,30), " then ",pp_expr_m(Then,30), " else ",pp_expr_m(Else,30). |
5014 | | pp_expr2(if_then_else(If,Then,Else),Prio,LimitReached) --> {atelierb_mode(_)},!, |
5015 | | % print IF-THEN-ELSE using a translation that Atelier-B can understand: |
5016 | | {rewrite_if_then_else_expr_to_b(if_then_else(If,Then,Else), NExpr), |
5017 | | get_texpr_type(Then,Type), |
5018 | | NAst = b(NExpr,Type,[])}, |
5019 | | % construct {d,x| If => x=Then & not(if) => x=Else}(TRUE) |
5020 | | pp_expr(NAst,Prio,LimitReached). |
5021 | | pp_expr2(if_then_else(If,Then,Else),1,LimitReached) --> !, |
5022 | | pp_atom_opt_mathit('IF'),pp_space, % "IF ", |
5023 | | pp_expr_m(If,30,LimitReached), |
5024 | | pp_space, pp_atom_opt_mathit('THEN'),pp_space, %" THEN ", |
5025 | | pp_expr_m(Then,30,LimitReached), |
5026 | | pp_space, pp_atom_opt_mathit('ELSE'),pp_space, %" ELSE ", |
5027 | | pp_expr_m(Else,30,LimitReached), |
5028 | | pp_space, pp_atom_opt_mathit('END'). %" END" |
5029 | | pp_expr2(kodkod(Id,Identifiers),300,LimitReached) --> !, |
5030 | | "KODKOD_CALL(",ppnumber(Id),": ",pp_expr_ids(Identifiers,LimitReached),")". |
5031 | | pp_expr2(Expr,500,_) --> |
5032 | | {constants_in_mode(Expr,Symbol)},!,ppatom(Symbol). |
5033 | | pp_expr2(equal(A,B),Prio,LimitReached) --> |
5034 | | {get_preference(pp_propositional_logic_mode,true), % a mode for printing propositional logic formuli |
5035 | | is_boolean_value(B,BV), |
5036 | | get_texpr_id(A,_)},!, |
5037 | | ({BV=pred_true} -> pp_expr(A,Prio,LimitReached) |
5038 | | ; pp_expr2(negation(b(equal(A,b(boolean_true,boolean,[])),pred,[])),Prio,LimitReached)). |
5039 | | pp_expr2(Expr,Prio,LimitReached) --> |
5040 | | {functor(Expr,F,1), |
5041 | | unary_prefix(F,Symbol,Prio),!, |
5042 | | arg(1,Expr,Arg),APrio is Prio+1}, |
5043 | | ppatom(Symbol), " ", |
5044 | | pp_expr_m(Arg,APrio,LimitReached). |
5045 | | pp_expr2(Expr,500,LimitReached) --> |
5046 | | {functor(Expr,F,1), |
5047 | | unary_prefix_parentheses(F,Symbol),!, |
5048 | | arg(1,Expr,Arg)}, |
5049 | | pp_atom_opt_latex(Symbol), "(", pp_expr(Arg,_,LimitReached), ")". |
5050 | | pp_expr2(Expr,Prio,LimitReached) --> |
5051 | | {functor(Expr,F,1), |
5052 | | unary_postfix_in_mode(F,Symbol,Prio),!, |
5053 | | arg(1,Expr,Arg),APrio is Prio+1}, |
5054 | | pp_expr_m(Arg,APrio,LimitReached),ppatom(Symbol). |
5055 | | pp_expr2(power_of(Left,Right),Prio,LimitReached) --> {latex_mode},!, % special case, as we need to put {} around RHS |
5056 | | {Prio=200, LPrio is Prio+1, RPrio = Prio}, |
5057 | | pp_expr_m(Left,LPrio,LimitReached), |
5058 | | "^{", |
5059 | | pp_expr_m(Right,RPrio,LimitReached), |
5060 | | "}". |
5061 | | pp_expr2(power_of_real(Left,Right),Prio,LimitReached) --> !, |
5062 | | ({get_texpr_expr(Right,convert_real(RI))} |
5063 | | -> pp_expr2(power_of(Left,RI),Prio,LimitReached) % the Atelier-B power_of expects integer exponent |
5064 | | ; pp_external_call('RPOW',[Left,Right],expression,Prio,LimitReached) |
5065 | | ). |
5066 | | pp_expr2(Expr,OPrio,LimitReached) --> |
5067 | | {functor(Expr,F,2), |
5068 | | binary_infix_in_mode(F,Symbol,Prio,Ass),!, |
5069 | | arg(1,Expr,Left), |
5070 | | arg(2,Expr,Right), |
5071 | | ( Ass = left, binary_infix_symbol(Left,Symbol) -> LPrio is Prio-1, RPrio is Prio+1 |
5072 | | ; Ass = right, binary_infix_symbol(Right,Symbol) -> LPrio is Prio+1, RPrio is Prio-1 |
5073 | | ; LPrio is Prio+1, RPrio is Prio+1)}, |
5074 | | % Note: Prio+1 is actually not necessary, Prio would be sufficient, as pp_expr_m uses a strict comparison < |
5075 | | ({always_surround_by_parentheses(F)} -> "(",{OPrio=1000} ; {OPrio=Prio}), |
5076 | | pp_expr_m(Left,LPrio,LimitReached), |
5077 | | " ", ppatom(Symbol), " ", |
5078 | | pp_expr_m(Right,RPrio,LimitReached), |
5079 | | ({always_surround_by_parentheses(F)} -> ")" ; []). |
5080 | | pp_expr2(first_of_pair(X),500,LimitReached) --> {get_texpr_type(X,couple(From,To))},!, |
5081 | | "prj1(", % TO DO: Latex version |
5082 | | ({\+ atelierb_mode(_)} % eventb_translation_mode |
5083 | | -> "" % no need to print types in Event-B or with new parser; |
5084 | | % TODO: also with new parser no longer required; only print in Atelier-B mode |
5085 | | ; {pretty_normalized_type(From,FromT), |
5086 | | pretty_normalized_type(To,ToT)}, |
5087 | | pp_atom_opt_latex(FromT), ",", pp_atom_opt_latex(ToT), |
5088 | | ")(" |
5089 | | ), |
5090 | | pp_expr(X,_,LimitReached),")". |
5091 | | pp_expr2(second_of_pair(X),500,LimitReached) --> {get_texpr_type(X,couple(From,To))},!, |
5092 | | "prj2(", % TO DO: Latex version |
5093 | | ({\+ atelierb_mode(_)} -> "" % no need to print types in Event-B or with new parser |
5094 | | ; {pretty_normalized_type(From,FromT), |
5095 | | pretty_normalized_type(To,ToT)}, |
5096 | | pp_atom_opt_latex(FromT), ",", pp_atom_opt_latex(ToT), |
5097 | | ")(" |
5098 | | ), |
5099 | | pp_expr(X,_,LimitReached),")". |
5100 | | pp_expr2(Call,Prio,LimitReached) --> {external_call(Call,Kind,Symbol,Args)},!, |
5101 | | pp_external_call(Symbol,Args,Kind,Prio,LimitReached). |
5102 | | pp_expr2(card(A),500,LimitReached) --> {latex_mode, get_preference(latex_pp_greek_ids,true)},!, |
5103 | | "|",pp_expr_m(A,0,LimitReached),"|". |
5104 | | pp_expr2(Expr,500,LimitReached) --> |
5105 | | {functor(Expr,F,_), |
5106 | | function_like_in_mode(F,Symbol),!, |
5107 | | Expr =.. [F|Args]}, |
5108 | | ppatom(Symbol), |
5109 | | ({Args=[]} |
5110 | | -> "" % some operators like pred and succ do not expect arguments |
5111 | | ; pp_expr_wrap_l('(',Args,')',LimitReached)). |
5112 | | pp_expr2(Expr,250,LimitReached) --> |
5113 | | {functor(Expr,F,3), |
5114 | | quantified_in_mode(F,Symbol), |
5115 | | Expr =.. [F,Ids,P1,E], |
5116 | | !, |
5117 | | add_normal_typing_predicates(Ids,P1,P)}, |
5118 | | ppatom(Symbol),pp_expr_ids(Ids,LimitReached),".(", |
5119 | | pp_expr_m(P,11,LimitReached),pp_such_that_bar(E), |
5120 | | pp_expr_m(E,11,LimitReached),")". |
5121 | | pp_expr2(Expr,Prio,LimitReached) --> |
5122 | | {functor(Expr,F,N), |
5123 | | (debug_mode(on) |
5124 | | -> format('**** Unknown functor ~w/~w in pp_expr2~n expression: ~w~n',[F,N,Expr]) |
5125 | | ; format('**** Unknown functor ~w/~w in pp_expr2~n',[F,N]) |
5126 | | ), |
5127 | | %add_internal_error('Unknown Expression: ',pp_expr2(Expr,Prio)), |
5128 | | Prio=20}, |
5129 | | ppterm_with_limit_reached(Expr,LimitReached). |
5130 | | |
5131 | | :- use_module(external_function_declarations,[synonym_for_external_predicate/2]). |
5132 | | |
5133 | | pp_external_call('MEMOIZE_STORED_FUNCTION',[TID],_,500,LimitReached) --> |
5134 | | {get_integer(TID,ID),memoization:get_registered_function_name(ID,Name)},!, |
5135 | | pp_expr_m(atom_string(Name),20,LimitReached), |
5136 | | " /*@memo ", pp_expr_m(TID,20,LimitReached), "*/". |
5137 | | pp_external_call('STRING_LENGTH',[Arg],_,Prio,LimitReached) --> |
5138 | | {get_preference(allow_sequence_operators_on_strings,true)},!, |
5139 | | pp_expr2(size(Arg),Prio,LimitReached). |
5140 | | pp_external_call('STRING_APPEND',[Arg1,Arg2],_,Prio,LimitReached) --> |
5141 | | {get_preference(allow_sequence_operators_on_strings,true)},!, |
5142 | | pp_expr2(concat(Arg1,Arg2),Prio,LimitReached). |
5143 | | pp_external_call('STRING_CONC',[Arg1],_,Prio,LimitReached) --> |
5144 | | {get_preference(allow_sequence_operators_on_strings,true)},!, |
5145 | | pp_expr2(general_concat(Arg1),Prio,LimitReached). |
5146 | | % we could also pretty-print RMUL, ... |
5147 | | pp_external_call(PRED,Args,pred,Prio,LimitReached) --> |
5148 | | {get_preference(translate_ids_to_parseable_format,true), |
5149 | | synonym_for_external_predicate(PRED,FUNC)}, |
5150 | | !, % print external predicate as function, as parser can only parse the latter without access to DEFINITIONS |
5151 | | pp_expr2(equal(b(external_function_call(FUNC,Args),boolean,[]), |
5152 | | b(boolean_true,boolean,[])),Prio,LimitReached). |
5153 | | pp_external_call(Symbol,Args,_,Prio,LimitReached) --> |
5154 | | ({invisible_external_pred(Symbol)} |
5155 | | -> pp_expr2(truth,Prio,LimitReached), |
5156 | | " /* ",pp_expr_m(atom_string(Symbol),20,LimitReached),pp_expr_wrap_l('(',Args,') */',LimitReached) |
5157 | | ; {Prio=500},pp_expr_m(atom_string(Symbol),20,LimitReached), |
5158 | | pp_expr_wrap_l('(',Args,')',LimitReached) % pp_expr_wrap_l('/*EXT:*/(',Args,')') |
5159 | | ). |
5160 | | |
5161 | | invisible_external_pred('LEQ_SYM'). |
5162 | | invisible_external_pred('LEQ_SYM_BREAK'). % just for symmetry breaking foralls,... |
5163 | | external_call(external_function_call(Symbol,Args),expression,Symbol,Args). |
5164 | | external_call(external_pred_call(Symbol,Args),pred,Symbol,Args). |
5165 | | external_call(external_subst_call(Symbol,Args),subst,Symbol,Args). |
5166 | | |
5167 | | pp_all_disjoint([H1,H2],LimitReached) --> !, " ",and_symbol," ", pp_disjoint(H1,H2,LimitReached). |
5168 | | pp_all_disjoint([H1|T],LimitReached) --> pp_all_disjoint_aux(T,H1,LimitReached), pp_all_disjoint(T,LimitReached). |
5169 | | pp_all_disjoint([],_) --> "". |
5170 | | |
5171 | | pp_all_disjoint_aux([],_,_) --> "". |
5172 | | pp_all_disjoint_aux([H2|T],H1,LimitReached) --> " ",and_symbol," ", |
5173 | | pp_disjoint(H1,H2,LimitReached), pp_all_disjoint_aux(T,H1,LimitReached). |
5174 | | |
5175 | | pp_disjoint(H1,H2,LimitReached) --> pp_expr(H1,_), "/\\", pp_expr(H2,_,LimitReached), " = {}". |
5176 | | |
5177 | | |
5178 | | % given a list of predicates and an ID either extract ID:Set and return Set or return its type as string |
5179 | | select_membership([],TID,[],atom_string(TS)) :- % atom_string used as wrapper for pp_expr2 |
5180 | | get_texpr_type(TID,Type), pretty_type(Type,TS). |
5181 | | select_membership([Pred|Rest],TID,Rest,Set) :- |
5182 | | Pred = b(member(TID2,Set),pred,_), |
5183 | | same_id(TID2,TID,_),!. |
5184 | | select_membership([Pred|Rest],TID,Rest,Set) :- |
5185 | | Pred = b(equal(TID2,EqValue),pred,_), |
5186 | | same_id(TID2,TID,_),!, get_texpr_type(TID,Type), |
5187 | | Set = b(set_extension([EqValue]),set(Type),[]). |
5188 | | select_membership([Pred|T],TID,[Pred|Rest],Set) :- |
5189 | | select_membership(T,TID,Rest,Set). |
5190 | | |
5191 | | % pretty print prj1/prj2 |
5192 | | pp_prj12(Prj,Set1,Set2,LimitReached) --> |
5193 | | ppatom(Prj),"(",pp_expr(Set1,_,LimitReached),",",pp_expr(Set2,_),")". |
5194 | | |
5195 | | %:- use_module(bsyntaxtree,[is_a_disjunct/3, get_integer/2]). |
5196 | | |
5197 | | pp_comprehension_set(Ids,P1,Info,LimitReached) --> |
5198 | | pp_comprehension_set5(Ids,P1,Info,LimitReached,_). |
5199 | | |
5200 | | % the extra argument of pp_comprehension_set5 indicates whether a special(Rule) was applied or not |
5201 | | %pp_comprehension_set(IDs,Body,Info,LimitReached,_) --> {print(pp(IDs,Body,Info)),nl,fail}. |
5202 | | pp_comprehension_set5([TID1,TID2,TID3],Body,_Info,LimitReached,special(Proj)) --> |
5203 | | /* This comprehension set was a projection function (prj1/prj2) */ |
5204 | | % %(z_,z__).(z__ : NATURAL|z_) -> prj1(INTEGER,NATURAL) |
5205 | | {get_texpr_id(TID1,ID1), % sometimes _zzzz_unary or _prj_arg1__ |
5206 | | get_texpr_id(TID2,ID2), % sometimes _zzzz_binary or _prj_arg2__ |
5207 | | get_texpr_id(TID3,LambdaID), |
5208 | | get_lambda_equality(Body,LambdaID,RestBody,ResultExpr), |
5209 | | get_texpr_id(ResultExpr,ResultID), |
5210 | | (ResultID = ID1 -> Proj = prj1 ; ResultID = ID2, Proj = prj2), |
5211 | | flatten_conjunctions(RestBody,Rest1), |
5212 | | select_membership(Rest1,TID1,Rest2,Set1), |
5213 | | select_membership(Rest2,TID2,[],Set2)}, |
5214 | | !, |
5215 | | pp_prj12(Proj,Set1,Set2,LimitReached). |
5216 | | pp_comprehension_set5([ID1|T],Body,Info,LimitReached,special(disjunct)) --> {is_a_disjunct(Body,B1,B2), |
5217 | | get_last(T,ID1,_FrontIDs,LastID), |
5218 | | is_lambda_result_id(LastID,_Suffix)},!, % we seem to have the union of two lambda expressions |
5219 | | "(", pp_comprehension_set([ID1|T],B1,Info,LimitReached), |
5220 | | " \\/ ", pp_comprehension_set([ID1|T],B2,Info,LimitReached), ")". |
5221 | | pp_comprehension_set5([b(identifier('_pred_'),integer,_), |
5222 | | b(identifier(LAMBDARES),integer,_)],Body,_,_,special(pred)) --> % '_lambda_result_' |
5223 | | {Body = b(equal(LR,T),pred,_), |
5224 | | LR = b(identifier(LAMBDARES),integer,_), |
5225 | | T = b(minus(ARG,One),integer,_), |
5226 | | get_integer(One,1), |
5227 | | ARG = b(identifier('_pred_'),integer,_)}, |
5228 | | !, |
5229 | | "pred". |
5230 | | pp_comprehension_set5([b(identifier('_succ_'),integer,_), |
5231 | | b(identifier(LAMBDARES),integer,_)],Body,_,_,special(succ)) --> % '_lambda_result_' |
5232 | | {Body = b(equal(LR,T),pred,_), |
5233 | | LR = b(identifier(LAMBDARES),integer,_), |
5234 | | T = b(add(ARG,One),integer,_), |
5235 | | get_integer(One,1), |
5236 | | ARG = b(identifier('_succ_'),integer,_)}, |
5237 | | !, |
5238 | | "succ". |
5239 | | pp_comprehension_set5(Paras,Body,Info,LimitReached,special(lambda)) --> |
5240 | | {detect_lambda_comprehension(Paras,Body, FrontIDs,LambdaBody,ToExpr)}, |
5241 | | !, |
5242 | | {add_normal_typing_predicates(FrontIDs,LambdaBody,TLambdaBody)}, |
5243 | | ({eventb_translation_mode} -> "(" ; ""), % put brackets around the lambda in Rodin |
5244 | | pp_annotations(Info,Body), |
5245 | | lambda_symbol, % "%" |
5246 | | pp_lambda_identifiers(FrontIDs,LimitReached), |
5247 | | ".", |
5248 | | ({eventb_translation_mode} -> {IPrio=30} ; {IPrio=11}, "("), % In Rodin it is not ok to write (P|E) |
5249 | | pp_expr_m(TLambdaBody,IPrio,LimitReached), % Check 11 against prio of . and | |
5250 | | pp_such_that_bar(ToExpr), |
5251 | | pp_expr_m(ToExpr,IPrio,LimitReached), |
5252 | | ")". |
5253 | | pp_comprehension_set5(TIds,Body,Info,LimitReached,special(event_b_comprehension_set)) --> |
5254 | | % detect Event-B style set comprehensions and use bullet • or Event-B notation such as {x·x ∈ 1 ‥ 3|x * 10} |
5255 | | % gets translated to {`__comp_result__`|∃x·(x ∈ 1 ‥ 3 ∧ `__comp_result__` = x * 10)} |
5256 | | {is_eventb_comprehension_set(TIds,Body,Info,Ids,P1,EXPR)},!, |
5257 | | pp_annotations(Info,P1), |
5258 | | left_set_bracket, |
5259 | | pp_expr_l_pair_in_mode(Ids,LimitReached), |
5260 | | {add_normal_typing_predicates(Ids,P1,P)}, |
5261 | | dot_bullet_symbol, |
5262 | | pp_expr_m(P,11,LimitReached), |
5263 | | pp_such_that_bar(P), |
5264 | | pp_expr_m(EXPR,11,LimitReached), |
5265 | | right_set_bracket. |
5266 | | pp_comprehension_set5(Ids,P1,Info,LimitReached,normal) --> |
5267 | | pp_annotations(Info,P1), |
5268 | | left_set_bracket, |
5269 | | pp_expr_l_pair_in_mode(Ids,LimitReached), |
5270 | | {add_normal_typing_predicates(Ids,P1,P)}, |
5271 | | pp_such_that_bar(P), |
5272 | | pp_expr_m(P,11,LimitReached), |
5273 | | right_set_bracket. |
5274 | | |
5275 | | |
5276 | | detect_lambda_comprehension([ID1|T],Body, FrontIDs,LambdaBody,ToExpr) :- |
5277 | | get_last(T,ID1,FrontIDs,LastID), |
5278 | | FrontIDs=[_|_], % at least one identifier for the lambda |
5279 | | is_lambda_result_id(LastID,Suffix), |
5280 | | % nl, print(lambda(Body,T,ID1)),nl, |
5281 | | (is_an_equality(Body,From,ToExpr) -> LambdaBody = b(truth,pred,[]) |
5282 | | ; is_a_conjunct(Body,LambdaBody,Equality), |
5283 | | is_an_equality(Equality,From,ToExpr)), |
5284 | | is_lambda_result_id(From,Suffix). |
5285 | | |
5286 | | pp_annotations(V,_) --> {var(V), format('Illegal variable info field in pp_annotations: ~w~n',[V])},!, |
5287 | | "/* ILLEGAL VARIABLE INFO FIED */". |
5288 | | pp_annotations(INFO,_) --> {member(prob_annotation('SYMBOLIC'),INFO)},!, |
5289 | | "/*@symbolic*/ ". |
5290 | ? | pp_annotations(_,b(_,_,INFO)) --> {nonvar(INFO),member(prob_annotation('SYMBOLIC'),INFO)},!, |
5291 | | "/*@symbolic*/ ". |
5292 | | % TO DO: maybe also print other annotations like memoize, recursive ? |
5293 | | pp_annotations(_,_) --> "". |
5294 | | |
5295 | | pp_event_b_comprehension_set(Ids,E,P1,LimitReached) --> |
5296 | | left_set_bracket,pp_expr_l_pair_in_mode(Ids,LimitReached), |
5297 | | {add_normal_typing_predicates(Ids,P1,P)}, |
5298 | | pp_such_that_bar(P),pp_expr_m(P,11,LimitReached), |
5299 | | " . ", pp_expr_m(E,11,LimitReached),right_set_bracket. |
5300 | | |
5301 | | pp_lambda_identifiers([H1,H2|T],LimitReached) --> {\+ eventb_translation_mode},!, |
5302 | | "(",pp_expr_l([H1,H2|T],LimitReached),")". |
5303 | | pp_lambda_identifiers(L,LimitReached) --> pp_expr_l_pair_in_mode(L,LimitReached). |
5304 | | |
5305 | | pp_such_that_bar(_) --> {latex_mode},!, "\\mid ". |
5306 | | pp_such_that_bar(b(unary_minus(_),_,_)) --> !, " | ". % otherwise AtelierB complains about illegal token |- |
5307 | | pp_such_that_bar(b(unary_minus_real(_),_,_)) --> !, " | ". % otherwise AtelierB complains about illegal token |- |
5308 | | pp_such_that_bar(_Next) --> "|". |
5309 | | pp_such_that_bar --> {latex_mode},!, "\\mid ". |
5310 | | pp_such_that_bar --> "|". |
5311 | | |
5312 | | is_an_equality(b(equal(A,B),_,_),A,B). |
5313 | | |
5314 | | integer_set_mapping(A,B) :- integer_set_mapping(A,_,B). |
5315 | | integer_set_mapping(A,integer_set,B) :- unicode_mode, unicode_translation(A,B),!. |
5316 | | integer_set_mapping(A,integer_set,B) :- latex_mode, latex_integer_set_translation(A,B),!. |
5317 | | integer_set_mapping(A,integer_set,B) :- atelierb_mode(Mode), Mode == pp, atelierb_pp_translation(A,B),!. |
5318 | | integer_set_mapping(A,integer_set,B) :- |
5319 | | eventb_translation_mode, eventb_integer_mapping(A,B),!. |
5320 | | integer_set_mapping(ISet,user_set,Res) :- atomic(ISet),!,Res=ISet. |
5321 | | integer_set_mapping(_ISet,unknown_set,'integer_set(??)'). |
5322 | | |
5323 | | eventb_integer_mapping('INTEGER','INT'). |
5324 | | eventb_integer_mapping('NATURAL','NAT'). |
5325 | | eventb_integer_mapping('NATURAL1','NAT1'). |
5326 | | |
5327 | | real_set_mapping(A,B) :- unicode_mode, unicode_translation(A,B),!. |
5328 | | real_set_mapping(X,X). % TO DO: unicode_mode,... |
5329 | | |
5330 | | :- dynamic comment_level/1. |
5331 | | reset_pp :- retractall(comment_level(_)). |
5332 | | enter_comment --> {retract(comment_level(N))},!, "(*", {N1 is N+1, assertz(comment_level(N1))}. |
5333 | | enter_comment --> "/*", {assertz(comment_level(1))}. |
5334 | | exit_comment --> {retract(comment_level(N))},!, |
5335 | | ({N>1} -> "*)", {N1 is N-1, assertz(comment_level(N1))} ; "*/"). |
5336 | | exit_comment --> "*/", {add_internal_error('Unmatched closing comment:',exit_comment)}. |
5337 | | % TO DO: ensure reset_pp is called when starting to pretty print, in case timeout occurs in previous pretty prints |
5338 | | |
5339 | | %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)))),[])) |
5340 | | |
5341 | | get_last([],Last,[],Last). |
5342 | | get_last([H2|T],H1,[H1|LT],Last) :- get_last(T,H2,LT,Last). |
5343 | | |
5344 | | pp_expr_wrap_l(Pre,Expr,Post,LimitReached) --> |
5345 | | ppatom(Pre),pp_expr_l(Expr,LimitReached),ppatom(Post). |
5346 | | %pp_freetype_term(Term,FT,L,Expr,LimitReached) --> |
5347 | | % {pretty_freetype(FT,P)}, |
5348 | | % ppatom(Term),"(",ppatom_opt_scramble(P),",", |
5349 | | % ppatom(L),",",pp_expr_m(Expr,500,LimitReached),")". |
5350 | | |
5351 | | % print a list of expressions, seperated by commas |
5352 | | pp_expr_l_pair_in_mode(List,LimitReached) --> {eventb_translation_mode},!, |
5353 | | {maplet_symbol(MapletStr,[])}, |
5354 | | pp_expr_l_sep(List,MapletStr,LimitReached). |
5355 | | pp_expr_l_pair_in_mode(List,LimitReached) --> pp_expr_l_sep(List,",",LimitReached). |
5356 | | pp_expr_l(List,LimitReached) --> pp_expr_l_sep(List,",",LimitReached). |
5357 | | |
5358 | | pp_expr_l_sep([Expr],_,LimitReached) --> !, |
5359 | | pp_expr_m(Expr,0,LimitReached). |
5360 | | pp_expr_l_sep(List,Sep,LimitReached) --> pp_expr_l2(List,Sep,LimitReached). |
5361 | | pp_expr_l2([],_Sep,_) --> !. |
5362 | | pp_expr_l2([Expr|Rest],Sep,LimitReached) --> |
5363 | | {get_sep_prio(Sep,Prio)}, |
5364 | | pp_expr_m(Expr,Prio,LimitReached), |
5365 | | pp_expr_l3(Rest,Sep,LimitReached). |
5366 | | pp_expr_l3([],_Sep,_) --> !. |
5367 | | pp_expr_l3(Rest,Sep,LimitReached) --> |
5368 | | Sep,pp_expr_l2(Rest,Sep,LimitReached). |
5369 | | |
5370 | | get_sep_prio(",",Prio) :- !, Prio=116. % Prio of , is 115 |
5371 | | get_sep_prio("\\/",Prio) :- !, Prio=161. |
5372 | | get_sep_prio("/\\",Prio) :- !, Prio=161. |
5373 | | get_sep_prio("|->",Prio) :- !, Prio=161. |
5374 | | get_sep_prio([8614],Prio) :- !, Prio=161. |
5375 | | % |
5376 | | get_sep_prio(_,161). |
5377 | | |
5378 | | % print the fields of a record |
5379 | | pp_expr_fields([field(Name,Expr)],LimitReached) --> !, |
5380 | | pp_identifier(Name),":",pp_expr_m(Expr,120,LimitReached). |
5381 | | pp_expr_fields(Fields,LimitReached) --> |
5382 | | pp_expr_fields2(Fields,LimitReached). |
5383 | | pp_expr_fields2([],_) --> !. |
5384 | | pp_expr_fields2([field(Name,Expr)|Rest],LimitReached) --> |
5385 | | pp_identifier(Name),":", |
5386 | | pp_expr_m(Expr,116,LimitReached), |
5387 | | pp_expr_fields3(Rest,LimitReached). |
5388 | | pp_expr_fields3([],_) --> !. |
5389 | | pp_expr_fields3(Rest,LimitReached) --> |
5390 | | ",",pp_expr_fields2(Rest,LimitReached). |
5391 | | |
5392 | | % TO DO: test more fully; identifiers seem to be wrapped in brackets |
5393 | | pp_expr_let_exists(Ids,Exprs,P,LimitReached) --> |
5394 | | exists_symbol, |
5395 | | ({eventb_translation_mode} -> % otherwise we get strange characters in Rodin, no (.) allowed in Rodin |
5396 | | pp_expr_ids_in_mode(Ids,LimitReached), |
5397 | | ".(" |
5398 | | ; " /* LET */ (", |
5399 | | pp_expr_l_pair_in_mode(Ids,LimitReached), |
5400 | | ").(" |
5401 | | ), |
5402 | | pp_expr_let_pred_exprs(Ids,Exprs,LimitReached), |
5403 | | ({is_truth(P)} -> "" |
5404 | | ; " ",and_symbol," ", pp_expr_m(P,40,LimitReached)), |
5405 | | ")". |
5406 | | |
5407 | | pp_expr_let_pred_exprs([],[],_) --> !. |
5408 | | pp_expr_let_pred_exprs([Id|Irest],[Expr|Erest],LimitReached) --> |
5409 | | " ",pp_expr_let_id(Id,LimitReached), |
5410 | | "=",pp_expr_m(Expr,400,LimitReached), |
5411 | | ( {Irest=[]} -> [] ; " ", and_symbol), |
5412 | | pp_expr_let_pred_exprs(Irest,Erest,LimitReached). |
5413 | | |
5414 | | % print a LET expression |
5415 | | pp_expr_let(_Ids,Exprs,P,LimitReached) --> |
5416 | | {eventb_translation_mode, |
5417 | | P=b(_,_,I), member(was(extended_expr(Op)),I)},!, % let was created by direct_definition for a theory operator call |
5418 | | ppatom(Op), |
5419 | | pp_function_left_bracket, |
5420 | | pp_expr_l_sep(Exprs,",",LimitReached), |
5421 | | %pp_expr_let_pred_exprs(Ids,Exprs,LimitReached) % write entire predicate with parameter names |
5422 | | pp_function_right_bracket. |
5423 | | pp_expr_let(Ids,Exprs,P,LimitReached) --> |
5424 | | "LET ", pp_expr_ids_no_parentheses(Ids,LimitReached), |
5425 | | " BE ", pp_expr_let_pred_exprs(Ids,Exprs,LimitReached), |
5426 | | " IN ",pp_expr_m(P,5,LimitReached), |
5427 | | " END". |
5428 | | |
5429 | | pp_expr_let_id(ID,LimitReached) --> {atomic(ID),!, print(unwrapped_let_id(ID)),nl}, |
5430 | | pp_expr_m(identifier(ID),500,LimitReached). |
5431 | | pp_expr_let_id(ID,LimitReached) --> pp_expr_m(ID,499,LimitReached). |
5432 | | |
5433 | | % print a list of identifiers |
5434 | | pp_expr_ids_in_mode([],_) --> !. |
5435 | | pp_expr_ids_in_mode(Ids,LimitReached) --> {eventb_translation_mode ; Ids=[_]},!, |
5436 | | pp_expr_l(Ids,LimitReached). % no (.) allowed in Event-B; not necessary in B if only one id |
5437 | | pp_expr_ids_in_mode(Ids,LimitReached) --> "(",pp_expr_l(Ids,LimitReached),")". |
5438 | | |
5439 | | pp_expr_ids([],_) --> !. |
5440 | | pp_expr_ids(Ids,LimitReached) --> |
5441 | | % ( {Ids=[Id]} -> pp_expr_m(Id,221) |
5442 | | % ; |
5443 | | "(",pp_expr_l(Ids,LimitReached),")". |
5444 | | |
5445 | | pp_expr_ids_no_parentheses(Ids,LimitReached) --> pp_expr_l(Ids,LimitReached). |
5446 | | |
5447 | | |
5448 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
5449 | | % pretty print types for error messages |
5450 | | |
5451 | | %:- use_module(probsrc(typing_tools), [normalize_type/2]). |
5452 | | % replace seq(.) types before pretty printing: |
5453 | | pretty_normalized_type(Type,String) :- typing_tools:normalize_type(Type,NT),!, |
5454 | | pretty_type(NT,String). |
5455 | | pretty_normalized_type(Type,String) :- |
5456 | | add_internal_error('Cannot normalize type:',pretty_normalized_type(Type,String)), |
5457 | | pretty_type(Type,String). |
5458 | | |
5459 | | % for pp_expr: do we potentially have to add parentheses |
5460 | | normalized_type_requires_outer_paren(couple(_,_)). |
5461 | | % all other types are either identifiers or use prefix notation (POW(.), seq(.), struct(.)) |
5462 | | |
5463 | | pretty_type(Type,String) :- |
5464 | | pretty_type_l([Type],[String]). |
5465 | | |
5466 | | pretty_type_l(Types,Strings) :- |
5467 | | extract_vartype_names(Types,N), |
5468 | | pretty_type2_l(Types,N,Strings). |
5469 | | pretty_type2_l([],_,[]). |
5470 | | pretty_type2_l([T|TRest],Names,[S|SRest]) :- |
5471 | | pretty_type2(T,Names,noparen,S), |
5472 | | pretty_type2_l(TRest,Names,SRest). |
5473 | | |
5474 | | extract_vartype_names(Types,names(Variables,Names)) :- |
5475 | | term_variables(Types,Variables), |
5476 | | name_variables(Variables,1,Names). |
5477 | | |
5478 | | pretty_type2(X,names(Vars,Names),_,Name) :- var(X),!,exact_member_lookup(X,Name,Vars,Names). |
5479 | | pretty_type2(any,_,_,'?'). |
5480 | | pretty_type2(set(T),N,_,Text) :- nonvar(T),T=couple(A,B),!, |
5481 | | pretty_type2(A,N,paren,AT), pretty_type2(B,N,paren,BT), |
5482 | | binary_infix_in_mode(relations,Symbol,_,_), % <-> |
5483 | | ajoin(['(',AT,Symbol,BT,')'],Text). |
5484 | | pretty_type2(set(T),N,_,Text) :- |
5485 | | pretty_type2(T,N,noparen,TT), function_like_in_mode(pow_subset,POW), |
5486 | | ajoin([POW,'(',TT,')'],Text). |
5487 | | pretty_type2(seq(T),N,_,Text) :- |
5488 | | pretty_type2(T,N,noparen,TT), ajoin(['seq(',TT,')'],Text). |
5489 | | pretty_type2(couple(A,B),N,Paren,Text) :- |
5490 | | pretty_type2(A,N,paren,AT),pretty_type2(B,N,paren,BT), |
5491 | | binary_infix_in_mode(cartesian_product,Cart,_,_), |
5492 | | ajoin([AT,Cart,BT],Prod), |
5493 | | ( Paren == noparen -> |
5494 | | Text = Prod |
5495 | | ; |
5496 | | ajoin(['(',Prod,')'],Text)). |
5497 | | pretty_type2(string,_,_,'STRING'). |
5498 | | pretty_type2(integer,_,_,Atom) :- integer_set_mapping('INTEGER',Atom). |
5499 | | pretty_type2(real,_,_,Atom) :- real_set_mapping('REAL',Atom). |
5500 | | pretty_type2(boolean,_,_,'BOOL'). |
5501 | | pretty_type2(global(G_Id),_,_,A) :- opt_scramble_id(G_Id,G), ajoin([G],A). |
5502 | | pretty_type2(freetype(Id),N,_,A) :- pretty_freetype2(Id,N,A). |
5503 | | pretty_type2(pred,_,_,predicate). |
5504 | | pretty_type2(subst,_,_,substitution). |
5505 | | pretty_type2(constant(List),_,_,A) :- |
5506 | | (var(List) -> ['{??VAR??...}'] % should not happen |
5507 | | ; ajoin_with_sep(List,',',P), ajoin(['{',P,'}'],A)). |
5508 | | pretty_type2(record(Fields),N,_,Text) :- |
5509 | | pretty_type_fields(Fields,N,FText), |
5510 | | ajoin(['struct(',FText,')'],Text). |
5511 | | pretty_type2(op(Params,Results),N,_,Text) :- |
5512 | | pretty_type_l(Params,N,PText), |
5513 | | ( nonvar(Results),Results=[] -> |
5514 | | ajoin(['operation(',PText,')'],Text) |
5515 | | ; |
5516 | | pretty_type_l(Results,N,RText), |
5517 | | ajoin([RText,'<--operation(',PText,')'],Text) ). |
5518 | | pretty_type2(definition(DefType,_,_),_,_,DefType). |
5519 | | pretty_type2(witness,_,_,witness). |
5520 | | pretty_type2([],_,_,'[]') :- add_error(pretty_type,'Illegal list in type:','[]'). |
5521 | | pretty_type2([H|T],_,_,'[_]') :- add_error(pretty_type,'Illegal list in type:',[H|T]). |
5522 | | pretty_type2(b(E,T,I),_,_,'?') :- add_error(pretty_type,'Illegal b/3 term in type:',b(E,T,I)). |
5523 | | |
5524 | | pretty_type_l(L,_,'...') :- var(L),!. |
5525 | | pretty_type_l([],_,'') :- !. |
5526 | | pretty_type_l([E|Rest],N,Text) :- |
5527 | | pretty_type2(E,N,noparen,EText), |
5528 | | ( nonvar(Rest),Rest=[] -> |
5529 | | EText=Text |
5530 | | ; |
5531 | | pretty_type_l(Rest,N,RText), |
5532 | | ajoin([EText,',',RText],Text)). |
5533 | | |
5534 | | pretty_type_fields(L,_,'...') :- var(L),!. |
5535 | | pretty_type_fields([],_,'') :- !. |
5536 | | pretty_type_fields([field(Name,Type)|FRest],N,Text) :- !, |
5537 | | pretty_type2(Type,N,noparen,TText), |
5538 | | ptf_seperator(FRest,Sep), |
5539 | | pretty_type_fields(FRest,N,RestText), |
5540 | | opt_scramble_id(Name,ScrName), |
5541 | | ajoin([ScrName,':',TText,Sep,RestText],Text). |
5542 | | pretty_type_fields(Err,N,Text) :- |
5543 | | add_internal_error('Illegal field type: ',pretty_type_fields(Err,N,Text)), Text='??'. |
5544 | | ptf_seperator(L,', ') :- var(L),!. |
5545 | | ptf_seperator([],'') :- !. |
5546 | | ptf_seperator(_,', '). |
5547 | | |
5548 | | pretty_freetype(Id,A) :- |
5549 | | extract_vartype_names(Id,N), |
5550 | | pretty_freetype2(Id,N,A). |
5551 | | pretty_freetype2(Id,_,A) :- var(Id),!,A='_'. |
5552 | | pretty_freetype2(Id,_,A) :- atomic(Id),!,Id=A. |
5553 | | pretty_freetype2(Id,N,A) :- |
5554 | | Id=..[Name|TypeArgs], |
5555 | | pretty_type2_l(TypeArgs,N,PArgs), |
5556 | | ajoin_with_sep(PArgs,',',P), |
5557 | | ajoin([Name,'(',P,')'],A). |
5558 | | |
5559 | | name_variables([],_,[]). |
5560 | | name_variables([_|VRest],Index,[Name|NRest]) :- |
5561 | | (nth1(Index,"ABCDEFGHIJKLMNOPQRSTUVWXYZ",C) -> SName = [C] ; number_codes(Index,SName)), |
5562 | | append("_",SName,CName),atom_codes(Name,CName), |
5563 | | Next is Index+1, |
5564 | | name_variables(VRest,Next,NRest). |
5565 | | |
5566 | | ppatom(Var) --> {var(Var)},!, ppatom('$VARIABLE'). |
5567 | | ppatom(Cmp) --> {compound(Cmp)},!, ppatom('$COMPOUND_TERM'). |
5568 | | ppatom(Atom) --> {safe_atom_codes(Atom,Codes)}, ppcodes(Codes). |
5569 | | |
5570 | | ppnumber(Number) --> {var(Number)},!,pp_clpfd_variable(Number). |
5571 | | ppnumber(inf) --> !,"inf". |
5572 | | ppnumber(minus_inf) --> !,"minus_inf". |
5573 | | ppnumber(Number) --> {number(Number),number_codes(Number,Codes)},!, ppcodes(Codes). |
5574 | | ppnumber(Number) --> {add_internal_error('Not a number: ',ppnumber(Number,_,_))}, "<<" ,ppterm(Number), ">>". |
5575 | | |
5576 | | pp_numberedvar(N) --> "_",ppnumber(N),"_". |
5577 | | |
5578 | | pp_clpfd_variable(X) --> "?:",{fd_dom(X,Dom)},write_to_codes(Dom), pp_frozen_info(X). |
5579 | | |
5580 | | pp_frozen_info(_X) --> {get_preference(translate_print_frozen_infos,false)},!,[]. |
5581 | | pp_frozen_info(X) --> |
5582 | | ":(",{frozen(X,Goal)}, |
5583 | | write_goal_with_max_depth(Goal), |
5584 | | ")". |
5585 | | |
5586 | | write_goal_with_max_depth((A,B)) --> !, "(",write_goal_with_max_depth(A), |
5587 | | ", ", write_goal_with_max_depth(B), ")". |
5588 | | write_goal_with_max_depth(Term) --> write_with_max_depth(3,Term). |
5589 | | |
5590 | | write_with_max_depth(Depth,Term,S1,S2) :- write_term_to_codes(Term,S1,S2,[max_depth(Depth)]). |
5591 | | |
5592 | | ppterm(Term) --> write_to_codes(Term). |
5593 | | |
5594 | | ppcodes([],S,S). |
5595 | | ppcodes([C|Rest],[C|In],Out) :- ppcodes(Rest,In,Out). |
5596 | | |
5597 | | ppterm_with_limit_reached(Term,LimitReached) --> |
5598 | | {write_to_codes(Term,Codes,[])}, ppcodes_with_limit_reached(Codes,LimitReached). |
5599 | | |
5600 | | ppcodes_with_limit_reached([C|Rest],LimitReached,[C|In],Out) :- var(LimitReached), !, |
5601 | | ppcodes_with_limit_reached(Rest,LimitReached,In,Out). |
5602 | | ppcodes_with_limit_reached(_,_LimitReached,S,S). |
5603 | | |
5604 | | % for debugging: |
5605 | | :- public b_portray_hook/1. |
5606 | | b_portray_hook(X) :- |
5607 | | nonvar(X), |
5608 | | (is_texpr(X), ground(X) -> write('{# '),print_bexpr_or_subst(X),write(' #}') |
5609 | | ; X=avl_set(_), ground(X) -> write('{#avl '), print_bvalue(X), write(')}') |
5610 | | ; X=wfx(WF0,_,WFE,Info) -> format('wfx(~w,$mutable,~w,~w)',[WF0,WFE,Info]) % to do: short summary of prios & call stack |
5611 | | ). |
5612 | | |
5613 | | install_b_portray_hook :- % register portray hook mainly for the Prolog debugger |
5614 | | assertz(( user:portray(X) :- translate:b_portray_hook(X) )). |
5615 | | remove_b_portray_hook :- |
5616 | | retractall( user:portray(_) ). |
5617 | | |
5618 | | |
5619 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
5620 | | % Pretty-print of Event-B models as classical B |
5621 | | |
5622 | | translate_eventb_to_classicalb(EBMachine,AddInfo,Rep) :- |
5623 | | ( conversion_check(EBMachine) -> |
5624 | | convert_eventb_classicalb(EBMachine,CBMachine), |
5625 | | call_cleanup(( set_animation_mode(b), % clear minor mode "eventb" |
5626 | | translate_machine(CBMachine,Rep,AddInfo),!), |
5627 | | set_animation_minor_mode(eventb)) |
5628 | | ; \+ animation_minor_mode(eventb) -> add_error(translate,'Conversion only applicable to Event-B models') |
5629 | | ; |
5630 | | add_error_and_fail(translate,'Conversion not applicable, check if you limited the number of abstract level to 0') |
5631 | | ). |
5632 | | |
5633 | | convert_eventb_classicalb(EBMachine,CBMachine) :- |
5634 | | select_section(operation_bodies,In,Out,EBMachine,CBMachine1), |
5635 | | maplist(convert_eventop,In,Out), |
5636 | | select_section(initialisation,IIn,IOut,CBMachine1,CBMachine), |
5637 | | convert_event(IIn,[],IOut). |
5638 | | convert_eventop(EBOp,CBOp) :- |
5639 | | get_texpr_expr(EBOp,operation(Id,[],Args,EBBody)), |
5640 | | get_texpr_info(EBOp,Info), |
5641 | | convert_event(EBBody,Args,CBBody), |
5642 | | % Remove the arguments |
5643 | | create_texpr(operation(Id,[],[],CBBody),op([],[]),Info,CBOp). |
5644 | | convert_event(TEvent,Parameters,TSubstitution) :- |
5645 | | get_texpr_expr(TEvent,rlevent(_Id,_Section,_Status,_Parameters,Guard,_Theorems,Actions,_VariableWitnesses,_ParameterWitnesses,_Ums,_Refined)), |
5646 | | in_parallel(Actions,PAction), |
5647 | | convert_event2(Parameters,Guard,PAction,TSubstitution). |
5648 | | convert_event2([],Guard,Action,Action) :- |
5649 | | is_truth(Guard),!. |
5650 | | convert_event2([],Guard,Action,Select) :- |
5651 | | !,create_texpr(select([When]),subst,[],Select), |
5652 | | create_texpr(select_when(Guard,Action),subst,[],When). |
5653 | | convert_event2(Parameters,Guard,Action,Any) :- |
5654 | | create_texpr(any(Parameters,Guard,Action),subst,[],Any). |
5655 | | in_parallel([],Skip) :- !,create_texpr(skip,subst,[],Skip). |
5656 | | in_parallel([A],A) :- !. |
5657 | | in_parallel(Actions,Parallel) :- create_texpr(parallel(Actions),subst,[],Parallel). |
5658 | | |
5659 | | conversion_check(Machine) :- |
5660 | | animation_mode(b), |
5661 | | animation_minor_mode(eventb), |
5662 | | get_section(initialisation,Machine,Init), |
5663 | | get_texpr_expr(Init,rlevent(_Id,_Sec,_St,_Par,_Grd,_Thms,_Act,_VW,_PW,_Ums,[])). |
5664 | | |
5665 | | % ------------------------------------------------------------ |
5666 | | |
5667 | | % divide a B typed expression into columns for CSV export or Table viewing of its values |
5668 | | get_bexpression_column_template(b(couple(A,B),_,_),(AVal,BVal),ColHeaders,Columns) :- !, |
5669 | | get_bexpression_column_template(A,AVal,AHeaders,AColumns), |
5670 | | get_bexpression_column_template(B,BVal,BHeaders,BColumns), |
5671 | | append(AHeaders,BHeaders,ColHeaders), |
5672 | | append(AColumns,BColumns,Columns). |
5673 | | get_bexpression_column_template(TypedExpr,Value,[ColHeader],[Value]) :- |
5674 | | translate:translate_bexpression_with_limit(TypedExpr,100,ColHeader). |
5675 | | |
5676 | | |
5677 | | % a version of member that creates an error when info list not instantiated |
5678 | | member_in_info(X,T) :- var(T),!, add_internal_error('Illegal info field:', member_in_info(X,T)),fail. |
5679 | | member_in_info(X,[X|_]). |
5680 | | member_in_info(X,[_|T]) :- member_in_info(X,T). |
5681 | | |
5682 | | memberchk_in_info(X,T) :- var(T),!, add_internal_error('Illegal info field:', memberchk_in_info(X,T)),fail. |
5683 | | memberchk_in_info(X,[X|_]) :- !. |
5684 | | memberchk_in_info(X,[_|T]) :- memberchk_in_info(X,T). |
5685 | | |
5686 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
5687 | | |
5688 | | :- use_module(library(clpfd)). |
5689 | | |
5690 | | % print also partially instantiated variables with CLP(FD) Info |
5691 | | print_value_variable(X) :- var(X), !, print(X). |
5692 | | print_value_variable(int(X)) :- print('int('), print_clpfd_variable(X), print(')'). |
5693 | | print_value_variable(fd(X,T)) :- print('fd('), print_clpfd_variable(X), print(','), print(T),print(')'). |
5694 | | print_value_variable(X) :- print(X). |
5695 | | |
5696 | | print_clpfd_variable(X) :- var(X),!,print(X), print(':'), fd_dom(X,Dom), print(Dom), print_frozen_info(X). |
5697 | | print_clpfd_variable(X) :- print(X). |
5698 | | |
5699 | | %print_clpfd_variables([]). |
5700 | | %print_clpfd_variables([H|T]) :- print('CLPFD: '),print_clpfd_variable(H), nl, print_clpfd_variables(T). |
5701 | | |
5702 | | |
5703 | | :- public l_print_frozen_info/1. |
5704 | | l_print_frozen_info([]). |
5705 | | l_print_frozen_info([H|T]) :- print(H), print(' '), |
5706 | | (var(H) -> print_frozen_info(H) ; |
5707 | | H=fd_var(V,_) -> print_frozen_info(V) ; true), l_print_frozen_info(T). |
5708 | | |
5709 | | print_frozen_info(X) :- frozen(X,Goal), print_frozen_goal(Goal). |
5710 | | print_frozen_goal((A,B)) :- !, print_frozen_goal(A), print(','), print_frozen_goal(B). |
5711 | | print_frozen_goal(prolog:trig_nondif(_A,_B,R,_S)) :- !, frozen(R,G2), print_frozen_goal2(G2). |
5712 | | print_frozen_goal(G) :- print_frozen_goal2(G). |
5713 | | print_frozen_goal2(V) :- var(V),!, print(V). |
5714 | | print_frozen_goal2(true) :- !. |
5715 | | print_frozen_goal2((A,B)) :- !, print_frozen_goal2(A), print(','), print_frozen_goal2(B). |
5716 | | print_frozen_goal2(G) :- print(' :: '), tools_printing:print_term_summary(G). |
5717 | | |
5718 | | |
5719 | | /* Event-B operators */ |
5720 | | translate_eventb_operators([]) --> !. |
5721 | | translate_eventb_operators([Name-Call|Rest]) --> |
5722 | | translate_eventb_operator(Call,Name), |
5723 | | translate_eventb_operators(Rest). |
5724 | | |
5725 | | translate_eventb_operator(Module:Call,Name) --> |
5726 | | insertcodes("\n "), |
5727 | | indention_codes(In,Out), |
5728 | | {Call =.. [Functor|Args], |
5729 | | translate_eventb_operator2(Functor,Args,Module,Call,Name,In,Out)}. |
5730 | | |
5731 | | |
5732 | | translate_eventb_operator2(direct_definition,[Args,_RawWD,RawBody,TypeParas|_],_Module,_Call,Name) --> |
5733 | | pp_eventb_direct_definition_header(Name,Args),!, |
5734 | | ppcodes(" direct_definition ["), |
5735 | | pp_eventb_operator_args(TypeParas), |
5736 | | ppcodes("] "), |
5737 | | {translate_in_mode(eqeq,'==',EqEqStr)}, ppatom(EqEqStr), |
5738 | | ppcodes(" "), |
5739 | | pp_raw_formula(RawBody). % TO DO: use indentation |
5740 | | translate_eventb_operator2(axiomatic_definition,[Tag|_],_Module,_Call,Name) --> !, |
5741 | | ppterm(Name), |
5742 | | ppcodes(": Operator implemented by axiomatic definition using "), |
5743 | | ppatom(Tag). |
5744 | | translate_eventb_operator2(Functor,_,Module,_Call,Name) --> |
5745 | | ppterm(Name), |
5746 | | ppcodes(": Operator implemented by "), |
5747 | | ppatom(Module),ppcodes(":"),ppatom(Functor). |
5748 | | |
5749 | | % example direct definition: |
5750 | | %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))),[]) |
5751 | | |
5752 | | pp_eventb_direct_definition_header(Name,Args) --> |
5753 | | ppterm(Name), ppcodes("("), |
5754 | | pp_eventb_operator_args(Args), ppcodes(")"). |
5755 | | |
5756 | | translate_eventb_direct_definition_header(Name,Args,ResAtom) :- |
5757 | | (pp_eventb_direct_definition_header(Name,Args,C,[]) |
5758 | | -> atom_codes(ResAtom,C) ; ResAtom='<<UNABLE TO PRETTY-PRINT OPERATOR HEADER>>'). |
5759 | | translate_eventb_direct_definition_body(RawBody,ResAtom) :- |
5760 | | (pp_raw_formula(RawBody,C,[]) -> atom_codes(ResAtom,C) ; ResAtom='<<UNABLE TO PRETTY-PRINT OPERATOR BODY>>'). |
5761 | | |
5762 | | pp_raw_formula(RawExpr) --> {transform_raw(RawExpr,TExpr)},!, pp_expr(TExpr,_,_LR). |
5763 | | pp_raw_formula(_) --> ppcodes("<<UNABLE TO PRETTY-PRINT>>"). |
5764 | | |
5765 | | |
5766 | | pp_eventb_operator_args([]) --> []. |
5767 | | pp_eventb_operator_args([Arg]) --> !, pp_argument(Arg). |
5768 | | pp_eventb_operator_args([Arg|T]) --> pp_argument(Arg), ppcodes(","), |
5769 | | pp_eventb_operator_args(T). |
5770 | | pp_argument(argument(ID,_RawType)) --> !, ppatom(ID). |
5771 | | pp_argument(identifier(_,ID)) --> !, "<",ppatom(ID),">". |
5772 | | pp_argument(Atom) --> ppatom(Atom). |
5773 | | |
5774 | | % --------------------------------------- |
5775 | | |
5776 | | % translate a predicate into B machine for manipulation |
5777 | | translate_predicate_into_machine(Pred,MchName,ResultAtom) :- |
5778 | | get_global_identifiers(Ignored,ignore_promoted_constants), |
5779 | | find_typed_identifier_uses(Pred, Ignored, TUsedIds), |
5780 | | get_texpr_ids(TUsedIds,UsedIds), |
5781 | | add_typing_predicates(TUsedIds,Pred,TPred), |
5782 | | set_print_type_infos(all), |
5783 | | specfile:set_animation_mode(b), % clear eventb minor mode; to do: set back |
5784 | | translate_bexpression(TPred,PredAtom), %print(res(UsedIds,ResultAtom)),nl, |
5785 | | set_print_type_infos(none), |
5786 | | convert_and_ajoin_ids(UsedIds,AllIds), |
5787 | | bmachine:get_full_b_machine(_Name,BMachine), |
5788 | | include(relevant_section,BMachine,RelevantSections), |
5789 | | % TO DO: we could filter out enumerate/deferred sets not occuring in Pred |
5790 | | translate_section_list(RelevantSections,SetsParas), |
5791 | | atom_codes(ASP,SetsParas), |
5792 | | ajoin(['MACHINE ', MchName, '\n',ASP,'CONSTANTS ',AllIds,'\nPROPERTIES\n ',PredAtom,'\nEND\n'],ResultAtom). |
5793 | | |
5794 | | relevant_section(deferred_sets/_). |
5795 | | relevant_section(enumerated_elements/_). |
5796 | | relevant_section(parameters/_). |
5797 | | |
5798 | | :- use_module(library(system),[ datime/1]). |
5799 | | :- use_module(specfile,[currently_opened_file/1]). |
5800 | | :- use_module(probsrc(version), [format_prob_version/1]). |
5801 | | % print a Proof Obligation aka Sequent as a B machine |
5802 | | nested_print_sequent_as_classicalb(Stream,HypsList,Goal,AllHypsList,MchName,ProofInfos) :- |
5803 | | set_suppress_rodin_positions(false,Chng), % ensure we print Rodin labels if available |
5804 | | call_cleanup(nested_print_sequent_as_classicalb_aux(Stream,HypsList,Goal,AllHypsList,MchName,ProofInfos), |
5805 | | reset_suppress_rodin_positions(Chng)). |
5806 | | |
5807 | | % convert identifier by adding backquote if necessary for unicode, reserved keywords, ... |
5808 | | convert_id(Atom,CAtom) :- pp_identifier(Atom,Codes,[]), atom_codes(CAtom,Codes). |
5809 | | convert_and_ajoin_ids(UsedIds,AllIdsWithCommas) :- |
5810 | | maplist(convert_id,UsedIds,ConvUsedIds), |
5811 | | ajoin_with_sep(ConvUsedIds,', ',AllIdsWithCommas). |
5812 | | |
5813 | | nested_print_sequent_as_classicalb_aux(Stream,HypsList,Goal,AllHypsList,MchName,ProofInfos) :- |
5814 | | conjunct_predicates(HypsList,HypsPred), |
5815 | | conjunct_predicates([Goal|HypsList],Pred), |
5816 | | 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 |
5817 | | find_typed_identifier_uses(Pred, Ignored, TUsedIds), |
5818 | | get_texpr_ids(TUsedIds,UsedIds), |
5819 | | convert_and_ajoin_ids(UsedIds,AllIds), |
5820 | | bmachine:get_full_b_machine(_Name,BMachine), |
5821 | | include(relevant_section,BMachine,RelevantSections), |
5822 | | % TO DO: we could filter out enumerate/deferred sets not occuring in Pred |
5823 | | translate_section_list(RelevantSections,SetsParas), |
5824 | | set_print_type_infos(all), |
5825 | | datime(datime(Yr,Mon,Day,Hr,Min,_Sec)), |
5826 | | format(Stream,'MACHINE ~w~n /* Exported: ~w/~w/~w ~w:~w */~n',[MchName,Day,Mon,Yr,Hr,Min]), |
5827 | | (currently_opened_file(File), bmachine:b_machine_name(Name) |
5828 | | -> format(Stream,' /* Origin: ~w : ~w */~n',[Name,File]) ; true), |
5829 | | write(Stream,' /* '),format_prob_version(Stream), format(Stream,' */~n',[]), |
5830 | | format(Stream,' /* Use static asssertion checking (probcli -cbc_assertions) to look for counter examples */~n',[]), |
5831 | | maplist(format_proof_infos(Stream),ProofInfos), |
5832 | | format(Stream,'~sCONSTANTS~n ~w~nPROPERTIES /* Selected Hypotheses: */~n',[SetsParas,AllIds]), |
5833 | | add_typing_predicates(TUsedIds,HypsPred,HypsT), |
5834 | | current_output(OldStream), |
5835 | | set_output(Stream), |
5836 | | nested_print_bexpr_as_classicalb2(HypsT,s(0)), % TODO: pass stream to this predicate |
5837 | | format(Stream,'~nASSERTIONS /* Proof Goal: */~n',[]), |
5838 | | nested_print_bexpr_as_classicalb2(Goal,s(0)), % TODO: pass stream to this predicate |
5839 | | (AllHypsList = [] -> true |
5840 | | ; sort(AllHypsList,SAL), sort(HypsList,SL), |
5841 | | ord_subtract(SAL,SL,RemainingHypsList), % TODO: we could preserve order |
5842 | | conjunct_predicates(RemainingHypsList,AllHypsPred), |
5843 | | find_typed_identifier_uses(AllHypsPred, Ignored, TAllUsedIds), |
5844 | | get_texpr_ids(TAllUsedIds,AllUsedIds), |
5845 | | ord_subtract(AllUsedIds,UsedIds,NewIds), % compute new ids not used in selected hyps and goal |
5846 | | (NewIds = [] |
5847 | | -> format(Stream,'OPERATIONS~n CheckRemainingHypotheses = SELECT~n',[]) |
5848 | | ; ajoin_with_sep(NewIds,', ',NIdLst), |
5849 | | format(Stream,'OPERATIONS~n CheckRemainingHypotheses(~w) = SELECT~n',[NIdLst]) |
5850 | | ), |
5851 | | nested_print_bexpr_as_classicalb2(AllHypsPred,s(0)), % TODO: pass stream to this predicate |
5852 | | format(Stream,' THEN skip~n END /* CheckRemainingHypotheses */~n',[]) |
5853 | | ), |
5854 | | set_output(OldStream), |
5855 | | set_print_type_infos(none), |
5856 | | format(Stream,'DEFINITIONS~n SET_PREF_DISPROVER_MODE == TRUE~n ; SET_PREF_TRY_FIND_ABORT == FALSE~n',[]), |
5857 | | format(Stream,' ; SET_PREF_ALLOW_REALS == FALSE~n',[]), |
5858 | | % The Rodin DisproverCommand.java usually enables CHR; |
5859 | | % TODO: we could also look for options(List) in ProofInfos and check use_chr_solver/true in List, ... |
5860 | | (get_preference(use_clpfd_solver,false) -> format(Stream,' ; SET_PREF_CHR == FALSE~n',[]) ; true), |
5861 | | (get_preference(use_chr_solver,true) -> format(Stream,' ; SET_PREF_CHR == TRUE~n',[]) ; true), |
5862 | | (get_preference(use_smt_mode,true) -> format(Stream,' ; SET_PREF_SMT == TRUE~n',[]) ; true), |
5863 | | (get_preference(use_smt_mode,true) -> format(Stream,' ; SET_PREF_SMT == TRUE~n',[]) ; true), |
5864 | | (get_preference(use_common_subexpression_elimination,true) -> format(Stream,' ; SET_PREF_CSE == TRUE~n',[]) ; true), |
5865 | | (get_preference(smt_supported_interpreter,true) -> format(Stream,' ; SET_PREF_SMT_SUPPORTED_INTERPRETER == TRUE~n',[]) ; true), |
5866 | | format(Stream,'END~n',[]). |
5867 | | |
5868 | | format_proof_infos(_,Var) :- var(Var),!. |
5869 | | format_proof_infos(Stream,disprover_result(Prover,Hyps,Result)) :- nonvar(Result),functor(Result,FR,_),!, |
5870 | | format(Stream,' /* ProB Disprover ~w result on ~w : ~w */~n',[Prover,Hyps,FR]). |
5871 | | format_proof_infos(Stream,E) :- format(Stream,' /* ~w */~n',[E]). |
5872 | | |
5873 | | |
5874 | | % --------------------------------------- |
5875 | | |
5876 | | |
5877 | | % show non obvious functors |
5878 | | get_texpr_top_level_symbol(TExpr,Symbol,2,infix) :- |
5879 | | translate:binary_infix_symbol(TExpr,Symbol),!. |
5880 | | get_texpr_top_level_symbol(b(E,_,_),Symbol,1,postfix) :- |
5881 | | functor(E,F,1), translate:unary_postfix_in_mode(F,Symbol,_),!. |
5882 | | get_texpr_top_level_symbol(b(E,_,_),Symbol,3,prefix) :- |
5883 | | functor(E,F,Arity), (Arity=3 ; Arity=2), % 2 for exists |
5884 | | quantified_in_mode(F,Symbol),!. |
5885 | | get_texpr_top_level_symbol(b(E,_,_),Symbol,N,prefix) :- |
5886 | | functor(E,F,N), |
5887 | | function_like_in_mode(F,Symbol). |
5888 | | |
5889 | | % --------------- |
5890 | | |
5891 | | % feedback to user about values |
5892 | | translate_bvalue_kind([],Res) :- !, Res='EMPTY-Set'. |
5893 | | translate_bvalue_kind([_|_],Res) :- !, Res='LIST-Set'. |
5894 | | translate_bvalue_kind(avl_set(A),Res) :- !, avl_size(A,Size), ajoin(['AVL-Set:',Size],Res). |
5895 | | translate_bvalue_kind(int(_),Res) :- !, Res = 'INTEGER'. |
5896 | | translate_bvalue_kind(term(floating(_)),Res) :- !, Res = 'FLOAT'. |
5897 | | translate_bvalue_kind(string(_),Res) :- !, Res = 'STRING'. |
5898 | | translate_bvalue_kind(pred_true,Res) :- !, Res = 'TRUE'. |
5899 | | translate_bvalue_kind(pred_false,Res) :- !, Res = 'FALSE'. |
5900 | | translate_bvalue_kind(fd(_,T),Res) :- !, Res = T. |
5901 | | translate_bvalue_kind((_,_),Res) :- !, Res = 'PAIR'. |
5902 | | translate_bvalue_kind(rec(_),Res) :- !, Res = 'RECORD'. |
5903 | | translate_bvalue_kind(freeval(Freetype,_Case,_),Res) :- !, Res = Freetype. |
5904 | | translate_bvalue_kind(CL,Res) :- custom_explicit_sets:is_interval_closure(CL,_,_),!, Res= 'INTERVAL'. |
5905 | | translate_bvalue_kind(CL,Res) :- custom_explicit_sets:is_infinite_explicit_set(CL),!, Res= 'INFINITE-Set'. |
5906 | | translate_bvalue_kind(closure(_,_,_),Res) :- !, Res= 'SYMBOLIC-Set'. |
5907 | | |
5908 | | |
5909 | | % --------------------------------------- |