1 % (c) 2009-2026 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 %:- set_prolog_flag(source_info,on).
6 % comment in if you want source location, e.g., for exceptions,...
7 % you can also comment in a line in remove_debugging_calls in debugging_calls_te.pl to see location of nl/0
8 % (and ensure debugging_calls.pl is loaded below and in term_expansion hook is set in debugging_calls_te.pl)
9 % with ?- trace, leash(off). one can creep without entering return in the debugger; with leash([redo]) the debugger only stops at the Redo-Port. Use @<RETURN> to enter Prolog commands in the debugger.
10 % leash(exception) also useful
11 % Note: to run probcli from source for ProB2 change change probcli.sh: PROBCOMMAND=probproxy and start probsli -s 8888
12
13 :- module(prob_cli, [go_cli/0,
14 run_probcli/2, run_probcli_with_argv_string/1,
15 reset_cli/0, recognised_cli_option/4, recognised_option/2, go_proxy/0,
16 print_version/1, cli_print_statistics/1]).
17
18 :- set_prolog_flag(double_quotes, codes).
19
20 :- if(predicate_property(expects_dialect(_), _)).
21 :- expects_dialect(sicstus4).
22 :- endif.
23
24 :- multifile user:portray_message/2.
25 user:portray_message(informational, imported(_Nr,_M1,_M2)) :- !.
26 user:portray_message(informational, loading(_Nr,_,_File)) :- !.
27 %user:portray_message(informational, loaded(_Nr,compiled,_File,M,MS,_)) :- !, format('~w ms for ~w~n',[MS,M]).
28 user:portray_message(informational, loaded(_Nr,_CompiledLoaded,_File,_Module,_TimeMS,_Bytes)) :- !.
29 user:portray_message(informational, foreign_resource(_Nr,_Status,_File,_Mod)) :- !.
30 user:portray_message(informational, chr_banner) :- !.
31 %user:portray_message(informational, halt) :- !.
32 %user:portray_message(informational, prompt(off,0,user,off,off,off)) :- !.
33 %user:portray_message(informational, M) :- !, write(M),nl,nl.
34
35
36 :- meta_predicate if_option_set(-,0).
37 :- meta_predicate if_option_set(-,0,0).
38 :- meta_predicate if_options_set(-,0).
39 :- meta_predicate if_option_set_loaded(-,-,0).
40 :- meta_predicate ifm_option_set(-,0).
41 :- meta_predicate ifm_option_set(-,-,0).
42 :- meta_predicate ifm_option_set_loaded(-,-,0).
43
44
45 % patch for SICStus 4.3.3 performance issue
46 % sprm_14972_patch.pl BEGIN
47 :- if((current_prolog_flag(dialect, sicstus),
48 current_prolog_flag(version_data, sicstus(4,3,3,_,_)))).
49 prolog:wf_call_like_arg(A, B, C, D, E, F, G, H, I, _) :-
50 prolog:wellformed_body_iso(A, B, C, D, E, F, G, H, I, quiet),
51 !.
52 prolog:wf_call_like_arg(A, B, C, A, D, _, E, _, _, _) :-
53 F=E:A,
54 prolog:condense_layout(B, G),
55 prolog:comp_layout2(B, G, B, H),
56 C=call(F),
57 prolog:comp_layout1(B, H, D).
58 :- endif.
59 % sprm_14972_patch.pl END
60
61
62 %:- include('self_check_off.pl').
63
64 :- use_module(module_information).
65 :- module_info(group,cli).
66 :- module_info(description,'ProB start file in cli mode.').
67
68 %:- use_module(debugging_calls).
69 %:- register_debugging_calls([pp_mnf(*), pp_cll(*), mnf(*), mnf(-,*), det_call(*)]).
70 %:- disable_debugging_calls.
71
72 :- use_module(prob_startup, [startup_prob/0]).
73 %:- use_module(pathes,[set_search_pathes/0]). % called first to set_compile_time_search_pathes
74 :- use_module(tools,[string_concatenate/3,arg_is_number/2, print_memory_used_wo_gc/1, print_memory_used_wo_gc/0,
75 split_atom/3, get_options/5,
76 start_ms_timer/1, stop_ms_timer/1, stop_ms_timer/2, stop_ms_timer_with_msg/2]).
77 :- use_module(tools_printing,[print_error/1,format_with_colour/4, format_with_colour_nl/4]).
78 :- use_module(tools_strings,[atom_split/4,convert_atom_to_number/2]).
79 :- use_module(tools_meta,[safe_time_out/3]).
80 :- use_module(tools_lists,[count_occurences/2]).
81
82 :- use_module(preferences).
83 :- set_prob_application_type(probcli). %
84
85 :- use_module(library(lists)).
86 :- use_module(library(file_systems),[file_exists/1]).
87 :- use_module(library(system)).
88 :- use_module(library(codesio)).
89 :- use_module(library(between),[between/3]).
90 :- use_module(library(terms),[term_hash/2]).
91 :- use_module(library(random),[random/3, setrand/1]).
92
93 :- use_module(self_check,[disable_interaction_on_errors/0,
94 perform_self_check/2,turn_off_run_time_type_checks/0,turn_on_run_time_type_checks/0]).
95 :- use_module(debug).
96 :- use_module(error_manager).
97 :- use_module(translate,[pretty_type/2]).
98 :- use_module(tools,[safe_absolute_file_name/2, safe_absolute_file_name/3, convert_ms_time_to_string/2]).
99 :- use_module(extension('counter/counter'),
100 [counter_init/0, new_counter/1, get_counter/2, inc_counter/1, inc_counter/2, reset_counter/1]).
101 :- use_module(state_space,[current_expression/2]).
102
103
104 :- dynamic junit_mode/1.
105 :- use_module(junit_tests,[set_junit_dir/1, create_and_print_junit_result/4]).
106
107 :- use_module(b_trace_checking,[check_default_trace_for_specfile/1, tcltk_check_state_sequence_from_file/1,
108 tcltk_check_sequence_from_file/3, get_default_trace_file/3,
109 tcltk_save_history_as_trace_file/2,tcltk_save_history_as_trace_file/3]).
110 :- use_module(eventhandling,[store_virtual_event/1]).
111 :- use_module(bmachine,[b_set_initial_machine/0]).
112 :- use_module(specfile).
113 :- use_module(test_typechecker,[run_typecheck_testcase/2]).
114 :- use_module(basic_unit_tests). % basic unit tests
115 :- use_module(bsyntaxtree,[size_of_conjunction/2, get_texpr_id/2, get_texpr_description/2,
116 conjunction_to_list/2,
117 get_texpr_label/2, predicate_components/2, get_texpr_pos/2]).
118 :- use_module(bmachine,[b_write_machine_representation_to_file/3,
119 full_b_machine/1, b_write_eventb_machine_to_classicalb_to_file/1]).
120 :- use_module(state_space,[current_state_id/1, get_state_space_stats/4, compute_full_state_space_hash/1]).
121 :- use_module(xtl_interface,[set_cspm_main_process/1]).
122 :- use_module(extrasrc(meta_interface),[is_dot_command/1, call_dot_command_with_engine/4,
123 is_dot_command_for_expr/1,call_dot_command_with_engine_for_expr/5,
124 is_plantuml_command/1, is_plantuml_command_for_expr/1,
125 is_table_command/1, is_table_command_for_expr/1,
126 call_plantuml_command/2, call_plantuml_command_for_expr/4,
127 call_command/5, is_table_command/6, write_table_to_csv_file/3,
128 command_description/3]).
129 :- use_module(kodkodsrc(kodkod_test),[test_kodkod/1, compare_kodkod_performance/2]).
130 :- use_module(kodkodsrc(predicate_analysis),[test_predicate_analysis/0]).
131 :- use_module(b_show_history,[write_history_to_file/2,write_values_to_file/1,
132 write_all_values_to_dir/1,write_history_to_user_output/1]).
133 :- use_module(cbcsrc(sap), [write_all_deadlocking_paths_to_xml/1, test_generation_by_xml_description/1]).
134 :- use_module(smtlib_solver(smtlib2_cli),[smtlib2_file/2]).
135 :- use_module(disproversrc(disprover_test_runner), [run_disprover_on_all_pos/1,
136 load_po_file/1,print_disprover_stats/0, set_disprover_timeout/1,
137 set_disprover_options/1, reset_disprover_timeout/0]).
138 :- use_module(extrasrc(latex_processor), [process_latex_file/2]).
139 :- use_module(probltlsrc(ltl),[ltl_check_assertions/2,ltl_model_check/4]).
140 :- use_module(probltlsrc(ctl),[ctl_model_check/4]).
141
142 :- use_module(logger).
143 :- use_module(extension('zmq/master/master'),[start_master/8]).
144 :- use_module(extension('zmq/worker/worker'),[start_worker/5]).
145 :- use_module(extension('ltsmin/ltsmin'),
146 [start_ltsmin/4,ltsmin_init/3,ltsmin_loop/1,ltsmin_teardown/2,ltsmin_generate_ltlfile/2]).
147 :- use_module(extrasrc(coverage_statistics),[compute_the_coverage/5]).
148 :- use_module(value_persistance, [set_storage_directory/2, print_value_persistance_stats/0,
149 delete_cache_files_for_machine/1, delete_cache_files/0,
150 get_value_persistance_stats/1, show_cache_file_contents/1]).
151 :- use_module(prob_socketserver,[start_prob_socketserver/2]).
152 :- use_module(tcltk_interface).
153 %:- compile(gui_tcltk).
154 :- use_module(eclipse_interface).
155 :- use_module(prob2_interface,[start_animation/0, is_initialised_state/1, reset_animator/0,
156 set_eclipse_preference/2, update_preferences_from_spec/1,
157 load_cspm_spec_from_cspm_file/1, load_xtl_spec_from_prolog_file/1]).
158
159 start_probcli_timer(timer(T1,WT1)) :-
160 statistics(runtime,[T1,_]),
161 statistics(walltime,[WT1,_]).
162 stop_probcli_debug_timer(Timer,Msg) :- (debug_mode(on) -> stop_probcli_timer(Timer,Msg) ; true).
163 stop_probcli_timer(timer(T1,WT1),Msg) :- stop_probcli_timer(timer(T1,WT1),Msg,_).
164 stop_probcli_timer(timer(T1,WT1),Msg,WTotTime) :-
165 statistics(runtime,[T2,_]), TotTime is T2-T1,
166 statistics(walltime,[WT2,_]), WTotTime is WT2-WT1,
167 convert_ms_time_to_string(WT2,WTString),
168 format('~w ~w ms walltime (~w ms runtime), since start: ~w~n',[Msg,WTotTime,TotTime,WTString]),
169 !.
170 stop_probcli_timer(Timer,Msg,_) :- add_internal_error('Illegal timer call: ',stop_probcli_timer(Timer,Msg)).
171 print_total_probcli_timer :-
172 statistics(runtime,[T2,_]),
173 statistics(walltime,[WT2,_]),
174 format('Since start of probcli: ~w ms walltime (~w ms runtime)~n',[WT2,T2]).
175 get_probcli_elapsed_walltime(timer(_,WT1),WTotTime) :-
176 statistics(walltime,[WT2,_]), WTotTime is WT2-WT1.
177 get_probcli_elapsed_runtime(timer(RT1,_),RTotTime) :-
178 statistics(runtime,[RT2,_]), RTotTime is RT2-RT1.
179
180 :- meta_predicate timeout_call(0,-,-).
181 timeout_call(Call,NOW,PP) :- option(timeout(TO)),!,
182 statistics(runtime,[T1,_]),
183 safe_time_out(Call,TO,Res),
184 statistics(runtime,[T2,_]), Runtime is T2-T1,
185 formatsilent('Runtime for ~w: ~w ms~n',[PP,Runtime]),
186 (Res=time_out -> print('*** Timeout occurred: '), print(TO),nl,
187 print('*** Call: '), print(Call),nl,
188 nl,
189 writeln_log(timeout_occurred(NOW,Call))
190 ; true).
191 timeout_call(Call,_NOW,PP) :-
192 statistics(runtime,[T1,_]),
193 call(Call),
194 statistics(runtime,[T2,_]), Runtime is T2-T1,
195 formatsilent('Runtime for ~w: ~w ms~n',[PP,Runtime]).
196
197 set_junit_mode(X) :-
198 set_junit_dir(X),
199 retractall(junit_mode(_)),
200 statistics(runtime,[Start,_]),
201 assertz(junit_mode(Start)).
202
203 go_proxy :-
204 catch( run_probcli(['-s','8888'],[proxy]), halt(ExitCode),
205 ( nl,write('CLI halt prevented, exit code '),write(ExitCode),nl) ).
206
207 go_cli :-
208 % set_prob_application_type(probcli) is already done at compile_time
209 current_prolog_flag(argv,ArgV),
210 run_probcli_with_junit_check(ArgV).
211
212 initialise_cli :- counter_init,
213 new_counter(cli_execute_inits),
214 new_counter(cli_errors), new_counter(cli_warnings),
215 new_counter(cli_expected_errors).
216
217 % called from test_runner.pl:
218 reset_cli :-
219 announce_event(clear_specification),
220 announce_event(reset_prob),
221 reset_cli_options,
222 reset_expected_error_occurred,
223 reset_optional_errors_or_warnings,
224 reset_counter(cli_errors), reset_counter(cli_warnings),
225 reset_counter(cli_expected_errors),
226 retractall(accumulated_infos(_,_,_)),
227 retractall(merged_individual_file_infos(_,_,_)),
228 retractall(individual_file_infos(_,_,_)),
229 (file_loaded(_)
230 -> clear_loaded_machines, % TODO: also treat by reset_prob eventhandling?
231 retractall(file_loaded(_,_)),
232 retractall(loaded_main_file(_,_))
233 ; true).
234
235 reset_cli_options :- option_verbose,verbose_off,fail.
236 reset_cli_options :- option(set_gc_trace(_X)),set_gc_trace(off),fail.
237 reset_cli_options :- option(profiling_on),profiling_off,fail.
238 % TODO: are there more options to reset?
239 reset_cli_options.
240
241 run_probcli_with_junit_check(ArgV) :-
242 catch( run_probcli(ArgV,[junit]),
243 halt(ExitCode),
244 ( ExitCode = 0 ->
245 true
246 ; ( junit_mode(S) ->
247 statistics(runtime,[E,_]), T is E - S,
248 create_and_print_junit_result(['Integration Tests'],ArgV,T,error([ExitCode]))
249 ; true),
250 throw(halt(ExitCode)))).
251
252
253 % a useful entry point for Jupyter to mimic probcli execution in notebooks
254 run_probcli_with_argv_string(ArgVAtom) :- split_argv_string(ArgVAtom,Atoms),
255 (Atoms = [probcli|Atoms2] -> true ; Atoms2=Atoms),
256 run_probcli(Atoms2,[run_probcli_with_argv_string]).
257
258 split_argv_string(ArgVAtom,Atoms) :- split_atom(ArgVAtom,[' '],Atoms). % TODO: treat quoting
259
260 run_probcli(ArgV,Context) :- % format(user_output,'~n* Starting probcli with argv: ~w~n~n',[ArgV]),
261 (catch(
262 run_probcli2(ArgV),
263 Exc,
264 process_exception(Exc,Context)
265 )
266 -> true
267 ; flush_output,
268 print_error('INTERNAL ERROR OCCURRED (run_probcli failed) !'),nl,
269 error_occurred(internal_error),
270 halt_exception(1)
271 ).
272
273 :- use_module(translate,[translate_error_term/2]).
274 %process_exception(Exception,_) :- write('Exception: '),write(Exception),nl,fail. % for debugging
275 process_exception(halt(A),_) :- !, throw(halt(A)).
276 process_exception('$aborted',_) :- !, throw('$aborted'). % thrown by SWI-Prolog on abort by user
277 process_exception(user_interrupt_signal,Context) :- !,
278 %add_error(probcli,'probcli interrupted by user (CTRL-C)').
279 statistics(walltime,[WStart,_]),
280 format_with_colour_nl(user_error,[red],'~nprobcli interrupted by user (CTRL-C), total walltime ~w ms',[WStart]),
281 (member(test_runner,Context)
282 -> throw(user_interrupt_signal) % will be caught by test_runner
283 ; error_occurred_with_msg(user_interrupt_signal,'probcli interrupted by user (CTRL-C)')
284 ).
285 process_exception(Exc,_) :-
286 (translate_error_term(Exc,S)
287 -> format_error_with_nl('Uncaught exception in probcli: ~w',[S])
288 ; true),
289 error_occurred(internal_error(exception(Exc))),fail.
290
291 ?no_command_issued :- \+ command_option(_).
292 ?command_option(X) :- option(X), \+ not_command_option(X).
293 not_command_option(verbose(_)).
294 not_command_option(profiling_on).
295 not_command_option(set_pref(_,_)).
296 not_command_option(set_preference_group(_,_)).
297 not_command_option(set_card(_,_)).
298 not_command_option(set_argv(_)).
299 not_command_option(silent).
300 not_command_option(strict_raise_error).
301 not_command_option(no_color).
302
303 probcli_startup :-
304 %print_total_probcli_timer,
305 startup_prob, % % startup_prob will already call init_preferences
306 %myheap_init,
307 initialise_cli.
308
309 :- load_files(library(system), [when(compile_time), imports([environ/2])]).
310 :- if(environ(prob_logging_mode,true)).
311 cli_set_options(ArgV,RemArgV) :-
312 cli_init_options(['-ll'|ArgV],RemArgV). %% adds -ll to have an automatically logging probcli to /tmp/prob_cli_debug.log
313 :- else.
314 cli_set_options(ArgV,RemArgV) :- cli_init_options(ArgV,RemArgV).
315 :- endif.
316
317 %:- use_module(extension('myheap/myheap')).
318 run_probcli2(ArgV) :- %print(probcli_startup),nl_time,
319 treat_important_options_beforehand(ArgV),
320 probcli_startup,
321 external_functions:reset_argv,
322 cli_set_options(ArgV,RemArgV), % recognise command-line options
323 %% cli_set_options(['-vv','-version'|ArgV],RemArgV), %% comment in to have an automatically verbose probcli
324 maplist(prob_cli:check_atom_looks_like_file,RemArgV),
325 (option(prolog_trace) -> error_manager:safe_trace ; true),
326 !,
327 run_probcli3(ArgV,RemArgV).
328
329 % treat important options beforehand, e.g., to enable debug prints straight-away, e.g., before probcli_startup
330 treat_important_options_beforehand(ArgV) :-
331 ? member(Opt,ArgV),recognised_option(Opt,RecognisedOpt),treat_important_option(RecognisedOpt),fail.
332 treat_important_options_beforehand(_).
333
334 treat_important_option(verbose(Nr)) :- verbose(Nr).
335 treat_important_option(set_gc_trace(X)) :- set_gc_trace(X).
336 treat_important_option(profiling_on) :- profiling_on.
337
338
339 run_probcli3(ArgV,RemArgV) :-
340 ( RemArgV=[File],no_command_issued,
341 get_filename_extension(File,Ext),
342 \+ do_not_execute_automatically(Ext)
343 % then assume we want to do -execute_all:
344 -> assert_option(execute(2147483647,false,current_state(1)))
345 ; true),
346 if_option_set(set_application_type(PAT),set_prob_application_type(PAT)),
347 if_option_set(test_mode,set_random_seed_to_deterministic_start_seed, set_new_random_seed),
348 ifm_option_set(verbose(VN),
349 verbose(VN), %tcltk_turn_debugging_on(5)),
350 tcltk_turn_debugging_off),
351 % TODO: reset the next three to default values if no flags present, in case we use them for tests:
352 if_option_set(set_gc_trace(GCT),set_gc_trace(GCT)),
353 if_option_set(set_gc_margin(GCM),set_gc_margin(GCM)),
354 if_option_set(set_gc_on_off(GCO),set_gc_on_off(GCO)),
355 if_option_set(profiling_on,profiling_on),
356 debug_print(9,'Command Line Arguments: '),debug_println(9,ArgV),
357 (debug_level_active_for(5) -> print_options ; true),
358 debug_print(6,'Command Line File Args: '),debug_println(6,RemArgV),
359 debug_flush_output,
360 if_option_set(cache_storage(StorageDir,SetStorMode), set_storage_directory(StorageDir,SetStorMode)),
361 if_option_set(parsercp(ParserLoc),
362 (add_message(parsercp,'Command -parcercp PATH deprecated, use -p JAVA_PARSER_PATH PATH',''),
363 set_preference(path_to_java_parser,ParserLoc))
364 ),
365 if_option_set(parserport(ParserPort),
366 connect_to_external_console_parser_on_port(ParserPort)),
367 generate_time_stamp(Datime,NOW),
368 if_option_set(log(LogF,Mode),
369 cli_start_logging(LogF,Mode,NOW,Datime,RemArgV)),
370 if_option_set(runtimechecking,
371 turn_on_run_time_type_checks,
372 turn_off_run_time_type_checks),
373 if_option_set(junit(JUX),
374 set_junit_mode(JUX)),
375 set_prefs,
376 (option_verbose, (option(set_prefs_from_file(_)) ; option(set_preference_group(_,_))),
377 get_non_default_preferences(list(NDPrefs))
378 -> format('Non-default preferences:~n',[]),print_list(NDPrefs),nl ; true),
379 set_optional_errors,
380 check_unavailable_options,
381 cli_show_help(ArgV,RemArgV),
382 if_option_set(set_argv(ArgVStr),
383 set_argv(ArgVStr)),
384 if_option_set(selfcheck(_,_),
385 cli_start_selfcheck),
386 if_option_set(typechecker_test(Filename),
387 (run_typecheck_testcase(Filename,typesok) -> halt_prob(NOW,0); halt_prob(NOW,1))),
388 if_option_set(install_prob_lib(LIBTOINSTALL,INSTALLOPTS), install_prob_lib(LIBTOINSTALL,INSTALLOPTS)),
389 if_options_set(print_version(VERSIONKIND), print_version(VERSIONKIND)),
390 if_option_set(check_java_version, check_java_version),
391 (debug_level_active_for(5) -> preferences:print_preferences ; true),
392 if_option_set(zmq_worker(Identifier), zmq_start_worker(Identifier, NOW)),
393 %if_option_set(zmq_worker2(MasterIP, Port, ProxyID, Logfile), zmq_start_worker(MasterIP,Port,ProxyID,Logfile,NOW)),
394 % process remaining arguments as files to load
395 % some utility commands which do not require main file:
396 ifm_option_set(indent_b_file_to_file(PPBFILE0,OUTFILE,OPTS),
397 indent_b_file_to_file(PPBFILE0,OUTFILE,OPTS)), % utility to format B file
398 ifm_option_set(pretty_print_prolog_file(PPFILE0,OUTFILE),
399 pretty_print_prolog_file(PPFILE0,OUTFILE)), % utility to print Prolog file
400 debug_println(6,processing(RemArgV)),
401 cli_load_files(RemArgV,NOW), % all CLI arguments which are not understood are supposed to be files to be treated
402 debug_println(19,finished_loading(RemArgV)),
403 if_option_set(socket(Port,Loopback),
404 cli_start_socketserver(Port,Loopback)),
405 % check_all_expected_errors_occurred(NOW), % is now checked for each file; socket_server should not generate errors ?
406 debug_println(20,'% probcli execution finished'),
407 cli_print_junit_results(ArgV),
408 debug_println(20,'% Stored Junit results'),
409 stop_xml_probcli_run(NOW),
410 debug_println(20,'% ProB Finished').
411
412 % finish logxml file by writing total number of errors and warnings
413 stop_xml_probcli_run(NOW) :-
414 get_counter(cli_errors,CErrs), get_counter(cli_warnings,CWarns), get_counter(cli_expected_errors,EErrs),
415 writeln_log_time(prob_finished(NOW,CErrs,CWarns)),
416 (EErrs>0
417 -> write_xml_element_to_log('probcli-errors',[errors/CErrs,warnings/CWarns,expected_errors/EErrs])
418 ; write_xml_element_to_log('probcli-errors',[errors/CErrs,warnings/CWarns])
419 ),
420 ((CErrs>0 ; CWarns>0) -> format(user_error,'! Total Errors: ~w, Warnings:~w~n',[CErrs,CWarns]) ; true),
421 stop_xml_group_in_log('probcli-run'). % Generating this tag means probcli ran to completion without segfault,...
422
423 % check if a cli argument looks like a proper filename
424 :- public check_file_arg/2. % is actually called when parsing options
425 check_file_arg(File,Command) :- normalise_option_atom(File,NF),
426 recognised_option(NF,_,_,_),!,
427 ajoin(['Command-line file argument for ', Command, ' looks like another probcli command: '],Msg),
428 add_warning(probcli,Msg,File).
429 check_file_arg(File,Command) :-
430 tools:check_filename_arg(File,Command).
431
432 % check if a remaining argument looks suspicious (e.g., like an unknown command)
433 check_atom_looks_like_file(Number) :- number(Number),!,
434 add_warning(probcli,'Command-line argument is a number (expected file name or probcli command): ',Number).
435 check_atom_looks_like_file(File) :- atom_codes(File,Codes),
436 check_codes_look_like_file(Codes,File).
437 check_codes_look_like_file(Codes,Arg) :-
438 check_codes_resembles_command(Codes,Arg),!.
439 check_codes_look_like_file([D|T],Arg) :- D >= 0'0, D =< 0'9,
440 nonmember(0'/,T), % detect things like 01_Jan/a.mch
441 !,
442 add_message(probcli,'Command-line argument looks like a number: ',Arg).
443 check_codes_look_like_file(_,_).
444
445 check_codes_resembles_command([45|_],Arg) :- !,
446 (get_possible_fuzzy_match_options(Arg,FuzzyMatches),
447 FuzzyMatches \= []
448 -> (FuzzyMatches=[FM]
449 -> ajoin(['Command-line argument ', Arg, ' looks like a probcli command! Did you mean: '],Msg),
450 add_warning(probcli,Msg,FM)
451 ; ajoin(['Command-line argument ', Arg, ' looks like a probcli command! Did you mean any of: '],Msg),
452 add_warning(probcli,Msg,FuzzyMatches)
453 )
454 ; get_possible_options_completion_msg(Arg,Completions)
455 -> ajoin(['Command-line argument ', Arg, ' looks like a probcli command! Did you mean: '],Msg),
456 add_warning(probcli,Msg,Completions)
457 ; add_message(probcli,'Command-line argument looks like an unknown probcli command: ',Arg)).
458
459 :- use_module(extrasrc(refinement_checker),[valid_failures_model/2]).
460 check_failures_mode(Shortcut,FailuresModel) :- valid_failures_model(FailuresModel,Shortcut),!.
461 check_failures_mode(Shortcut,trace) :-
462 add_warning(probcli,'Unrecognised refinement model flag (must be F, FD, T, R, RD, SF, V, VD; using default trace model T): ',Shortcut).
463
464 % ----------
465
466 cli_init_options(ArgV,RemArgV) :- %print(argv(ArgV)),nl,
467 append(ProBArgV,['--'|BArgV],ArgV),!, % pass arguments after -- to B via external_functions
468 cli_init_options2(ProBArgV,RemArgV),
469 debug_println(20,set_argv_from_list(BArgV)),
470 external_functions:set_argv_from_list(BArgV).
471 cli_init_options(ArgV,RemArgV) :- cli_init_options2(ArgV,RemArgV).
472 cli_init_options2(ArgV,RemArgV) :-
473 reset_options,
474 %%assertz(option(log('/tmp/ProBLog.log'))), print('LOGGING'),nl, %% coment in to build a version of probcli that automatically logs
475 ( get_options(ArgV,recognised_cli_option,Options,RemArgV,throw(halt(1))) ->
476 assert_all_options(Options)
477 ;
478 print_error(get_options_failed(ArgV)),definite_error_occurred).
479 cli_show_help(ArgV,RemArgV) :-
480 ( (option(help) ; ArgV=[]) ->
481 print_help, (RemArgV=[] -> halt_exception ; true)
482 ; true).
483 cli_start_logging(F,Mode,NOW,Datime,RemArgV) :-
484 debug_print(20,'%logging to: '), debug_println(20,F),
485 set_log_file(F), set_logging_mode(Mode),
486 start_xml_group_in_log('probcli-run'),
487 writeln_log(start_logging(NOW,F)),
488 version(V1,V2,V3,Suffix), revision(Rev), lastchangeddate(LCD),
489 writeln_log(version(NOW,V1,V2,V3,Suffix,Rev,LCD)), % still used by log_analyser
490 current_prolog_flag(version,PV),
491 write_xml_element_to_log(version,[major/V1,minor/V2,patch/V3,suffix/Suffix,revision/Rev,lastchanged/LCD,prolog/PV]),
492 findall(Opt, option(Opt), Options),
493 write_prolog_term_as_xml_to_log(options(NOW,Options)),
494 write_prolog_term_as_xml_to_log(files(NOW,RemArgV)), %
495 datime(Datime,DateRecord),
496 writeln_log(date(NOW,DateRecord)),
497 (DateRecord=datime(Yr,Mon,Day,Hr,Min,Sec)
498 -> write_xml_element_to_log(date,[year/Yr,month/Mon,day/Day,hour/Hr,minutes/Min,seconds/Sec]) ; true).
499
500 cli_start_selfcheck :-
501 %clear_loaded_machines_wo_errors,
502 b_set_initial_machine,
503 set_animation_mode(b),
504 store_virtual_event(clear_specification), % TO DO: try and get rid of the need for this
505 start_animation,
506 option(selfcheck(ModuleCombo,Opts)),
507 (atom(ModuleCombo),
508 atom_split(Module,':',TestNrA,ModuleCombo)
509 -> convert_atom_to_number(TestNrA,TestNr),
510 Opts2=[run_only_nr(TestNr)|Opts]
511 ; Module=ModuleCombo, Opts2=Opts
512 ),
513 (option(silent) -> Opts3=[silent|Opts2] ; option_verbose -> Opts3=[verbose|Opts2] ; Opts3=Opts2),
514 (perform_self_check(Module,Opts3) -> true ; error_occurred(selfcheck)),
515 fail.
516 cli_start_selfcheck.
517
518
519 :- dynamic file_loaded/2.
520 file_loaded(Status) :- file_loaded(Status,_File).
521
522
523 cli_load_files([],NOW) :- % no files are provided
524 !,
525 ? ( options_allow_start_without_file
526 -> debug_format(19,'Using empty machine to process probcli command~n',[]),
527 cli_set_empty_machine
528 ; we_did_something -> true
529 ; print('No file to process'),nl),
530 writeln_log_time(start_processing_empty_machine(NOW)),
531 start_xml_feature(process_file,filename,'$EMPTY_MACHINE',FINFO),
532 cli_process_loaded_file(NOW,'$EMPTY_MACHINE'),
533 check_all_expected_errors_occurred(NOW), % check that all expected errors occurred; below they will be checked for each file
534 stop_xml_feature(process_file,FINFO),
535 (option(benchmark_info_csv_output(_,_,_)) -> print_accumulated_infos(0) ; true).
536 cli_load_files(RemArgV,NOW) :-
537 cli_load_files2(RemArgV,NOW,0).
538
539
540 cli_set_empty_machine :- % TO DO: do this more properly here and for initialise_required
541 set_animation_mode(b),
542 bmachine:b_set_empty_machine,
543 assertz(file_loaded(true,'$$empty_machine')).
544
545 empty_machine_loaded :- file_loaded(true,'$$empty_machine').
546
547
548 options_allow_start_without_file :- option(run_benchmark(_,_,_)).
549 options_allow_start_without_file :- option(eval_repl(_)).
550 ?options_allow_start_without_file :- option(eval_string_or_file(_,_,_,_,_)).
551 options_allow_start_without_file :- option(check_log(_)).
552 options_allow_start_without_file :- option(process_latex_file(_,_)).
553 options_allow_start_without_file :- option(socket(_,_)).
554
555 we_did_something :- option(print_version(_)).
556 we_did_something :- option(check_java_version).
557 we_did_something :- option(check_parser_version).
558 we_did_something :- option(install_prob_lib(_,_)).
559 we_did_something :- option(indent_b_file_to_file(_,_,_)).
560 we_did_something :- option(pretty_print_prolog_file(_,_)).
561
562 option_only_works_for_single_file(zmq_assertion(_Identifier)).
563 option_only_works_for_single_file(zmq_master(_Identifier)).
564
565 clear_loaded_files :-
566 (file_loaded(_) -> clear_loaded_machines_wo_errors ; true).
567
568 % called if we have at least one file
569 cli_load_files2([],_,NrFilesProcessed) :- !,
570 debug_println(19,finished_procesing_all_files(NrFilesProcessed)),
571 print_accumulated_infos(NrFilesProcessed). % print summary of all runs for different files
572 cli_load_files2([F1,F2|T],NOW,_NrFilesProcessed) :-
573 ? option(Option),
574 option_only_works_for_single_file(Option),!,
575 add_error(probcli,'The following option can only be used for a single file: ',Option),
576 add_error(probcli,'Multiple files provided: ',[F1,F2|T]),
577 halt_prob(NOW,0).
578 cli_load_files2(RemArgV,NOW,NrFilesProcessed) :-
579 %print_total_probcli_timer,
580 clear_loaded_files,
581 retractall(file_loaded(_,_)),
582 RemArgV = [MainFile0|Rest],!,
583 N1 is NrFilesProcessed+1,
584 cli_load_files3(MainFile0,Rest,NOW,N1).
585 cli_load_files3(MainFile0,Rest,NOW,NrOfFile) :-
586 safe_absolute_file_name(MainFile0,MainFile,[access(none)]), % converts Windows slash into Unix slash,...
587 if_option_set(file_info,print_file_info(MainFile)),
588 ((Rest=[_|_] ; NrOfFile>1)
589 -> length(Rest,RLen), Tot is NrOfFile+RLen,
590 format('~n~n% Processing file ~w/~w: ~w~n',[NrOfFile,Tot,MainFile]) % was formatsilent
591 ; true),
592 start_xml_feature(process_file,filename,MainFile,FINFO),
593 ( file_exists(MainFile) ->
594 debug_println(6,file_exists(MainFile)),
595 ( load_main_file(MainFile,NOW,Already_FullyProcessed) ->
596 (Already_FullyProcessed==true
597 -> true
598 ; assertz(file_loaded(true,MainFile)),
599 trimcore_if_useful(Rest),
600 writeln_log_time(start_processing(NOW)),
601 start_probcli_timer(Timer),
602 catch((cli_process_loaded_file(NOW,MainFile)
603 -> stop_probcli_debug_timer(Timer,'% Finished processing file after')
604 ; print_error('Processing or loading file failed: '), print_error(MainFile),
605 start_repl_even_after_failure
606 ),
607 user_interrupt_signal, % catch CTRL-C by user but give chance to enter REPL
608 start_repl_even_after_failure
609 ),
610 writeln_log_time(finished_processing(NOW))
611 )
612 ;
613 assertz(file_loaded(error,MainFile)),
614 print_error('Loading Specification Failed'),
615 writeln_log_time(loading_failed(NOW,MainFile)),
616 error_occurred(load_main_file)
617 %start_repl_even_after_failure : TODO: fix issues with bmachine not precompiled and counter extension
618 ),
619 nls,
620 ifm_option_set(indent_main_b_file(PPFILE0),
621 indent_main_b_file(PPFILE0)),
622 ifm_option_set(pretty_print_prolog_file(PPFILE0),
623 pretty_print_prolog_file(PPFILE0))
624 ; % not file_exists
625 nl, assertz(file_loaded(error,MainFile)),
626 (number(MainFile0)
627 -> add_error(load_main_file,'Command-line argument is a number which is not associated with a command and does not exist as file: ',MainFile0)
628 ; atom_codes(MainFile0,[45|_]) % starts with a dash - : probably an illegal command-line option
629 -> add_error(load_main_file,'Specified option or file does not exist: ',MainFile0)
630 ; get_filename_extension(MainFile,Ext), \+ known_spec_file_extension(Ext,_)
631 -> (Ext = '' -> EMsg = 'Specified file does not exist and has no file extension:'
632 ; ajoin(['Specified file does not exist and has an unrecognised file extension ".',Ext,'" :'], EMsg)
633 ),
634 add_error(load_main_file,EMsg,MainFile)
635 ; add_error(load_main_file,'Specified file does not exist:',MainFile)
636 )
637 ),
638 check_all_expected_errors_occurred(NOW),
639 stop_xml_feature(process_file,FINFO),
640
641 debug_println(19,reset_expected_error_occurred),
642 reset_expected_error_occurred, % reset for next file
643 debug_println(19,resetting_errors),
644 reset_errors,
645 debug_println(19,update_time_stamp),
646 NOW1 is NOW+1,
647 update_time_stamp(NOW1),
648 debug_println(19,remaining_files_to_process(Rest)),
649 cli_load_files2(Rest,NOW1,NrOfFile).
650
651 start_repl_even_after_failure :-
652 (option(eval_repl([]))
653 -> format_with_colour_nl(user_output,[blue],'Starting REPL, but ignoring any other commands',[]),
654 % TODO: check if setup_constants_fails and then suggest e.g. :core @PROPERTIES command
655 start_repl_if_required % can be useful to debug properties, e.g, one can fix an error and reload
656 ; true
657 ).
658
659 print_file_info(F) :-
660 print('Specification_File('), print(F), print(')'),nl.
661
662 :- use_module(probsrc(tools),[statistics_memory_used/1]).
663 trimcore_if_useful(_) :- option(release_java_parser),!, prob_trimcore.
664 % if user wants to release java parser, this is an indication that the .prob files are big and it can be good to free memory
665 trimcore_if_useful([]) :- % try and reduce Prologs memory consumption, see also PROLOGKEEPSIZE parameter
666 % a lot of memory can be consumed loading .prob file and doing machine construction
667 !,
668 ? (option(X), memory_intensive_option(X)
669 -> debug_format(9,'Not trimming memory usage because of memory intensive option: ~w~n',[X])
670 ; statistics_memory_used(M), M< 300000000 % less than 300 MB used
671 -> debug_format(9,'Not trimming memory usage because of memory used is already low: ~w~n',[M])
672 ; prob_trimcore
673 ).
674 trimcore_if_useful(_) :- debug_println(9,'Not trimming memory usage as there are still files to process').
675
676 prob_trimcore :- (option_verbose ; option(release_java_parser)),!,prob_trimcore_verbose.
677 prob_trimcore :- prob_trimcore_silent.
678
679 prob_trimcore_verbose :-
680 print('Memory used before trimming: '),print_memory_used_wo_gc,flush_output, nl_time,
681 prob_trimcore_silent,
682 print('Memory used after trimming : '),print_memory_used_wo_gc,flush_output, nl_time.
683 prob_trimcore_silent :-
684 garbage_collect, % is important, otherwise trimming may achieve very little
685 trimcore.
686
687 memory_intensive_option(cli_mc(_)).
688 memory_intensive_option(ltl_formula_model_check(_,_)).
689 memory_intensive_option(ctl_formula_model_check(_,_)).
690 memory_intensive_option(pctl_formula_model_check(_,_)).
691 memory_intensive_option(refinement_check(_,_,_)).
692 memory_intensive_option(generate_all_traces_until(_,_,_)).
693
694 % ---------------------
695
696 % process all the commands for a loaded file:
697 cli_process_loaded_file(NOW,MainFile) :-
698 (real_error_occurred -> print_error('% *** Errors occurred while loading ! ***'),nl,nl ; true),
699 get_errors, reset_errors,
700 if_option_set(kodkod_performance(KPFile,Iterations),
701 compare_kodkod_performance1(KPFile,Iterations,NOW)),
702 if_option_set(kodkod_comparision(MaxResiduePreds),
703 test_kodkod_and_exit(MaxResiduePreds,NOW)),
704 % if_option_set(add_csp_guide(CspGuide), tcltk_add_csp_file(CspGuide)), %% moved to later to ensure B machine is precompiled; allows e.g. type_check_csp_and_b to run
705
706 if_option_set(csp_main(MAINPROC),
707 set_cspm_main_process(MAINPROC)),
708
709 if_option_set(zmq_master(Identifier), zmq_start_master(invariant,Identifier)),
710 %if_option_set(zmq_master(IP, Logfile), zmq_start_master(invariant,200,-1,5000,0,IP,Logfile)),
711
712 ifm_option_set(check_machine_file_sha(FileToCheck,ExpectedSha1Hash),
713 check_machine_file_sha(FileToCheck,ExpectedSha1Hash)),
714 ifm_option_set(clear_value_persistance_cache(MachineToClear),
715 delete_cache_files_for_machine(MachineToClear)),
716 ifm_option_set(clear_value_persistance_cache,
717 delete_cache_files),
718
719 % STARTING ANIMATION/MODEL CHECKING
720 ? cli_start_animation(NOW),
721
722 if_option_set_loaded(cli_core_properties(MaxCoreSize),cli_core_properties,
723 cli_core_properties(MaxCoreSize)),
724
725 if_option_set_loaded(default_trace_check,default_trace_check,
726 cli_start_default_trace_check(MainFile)),
727 if_option_set_loaded(trace_check(TrStyle,TraceFile,ChkMode),trace_check,
728 cli_start_trace_check(TrStyle,TraceFile,ChkMode)),
729
730 cli_process_loaded_file_afer_start_animation(NOW).
731
732 cli_process_loaded_file_afer_start_animation(NOW) :-
733 ifm_option_set(cli_print_machine_info(IKind),
734 cli_print_machine_info(IKind)),
735 ifm_option_set(pretty_print_internal_rep(PPFILE1,MachName1,TYPES1,ASCII1),
736 pretty_print_internal_rep(PPFILE1,MachName1,TYPES1,ASCII1)),
737 ifm_option_set(pretty_print_internal_rep_to_B(PPFILE3),
738 b_write_eventb_machine_to_classicalb_to_file(PPFILE3)),
739
740 if_option_set_loaded(state_trace(TraceFile),state_trace,
741 cli_start_trace_state_check(TraceFile)),
742
743 if_option_set(evaldot(EvalDotF),
744 set_eval_dot_file(EvalDotF)),
745
746 ? (initialise_required
747 -> check_loaded(initialise),
748 cli_start_initialisation(NOW),
749 writeln_log_time(initialised(NOW))
750 ; true),
751 if_option_set(check_abstract_constants,
752 check_abstract_constants),
753
754 if_option_set(zmq_assertion(Identifier),
755 zmq_start_master(assertion,Identifier)),
756
757 if_option_set(cli_lint,cli_lint(_)),
758 ifm_option_set_loaded(cli_lint(LintCheck),cli_lint,cli_lint(LintCheck)),
759 if_option_set(cli_wd_check(Disch,TotPos),cli_wd_check(Disch,TotPos)),
760 if_option_set(cli_wd_inv_proof(UnchangedNr,ProvenNr,TotPOsNr),cli_wd_inv_proof(UnchangedNr,ProvenNr,TotPOsNr)),
761 if_option_set(cli_start_mc_with_tlc,cli_start_mc_with_tlc),
762 if_option_set(cli_start_sym_mc_with_lts(LType),cli_start_sym_mc_with_lts(LType)),
763
764 if_option_set(cli_symbolic_model_check(Algorithm),cli_symbolic_model_check(Algorithm)),
765
766 if_option_set_loaded(cli_check_properties,check_properties,
767 cli_check_properties(NOW)),
768 ifm_option_set_loaded(cli_check_assertions(ALL,ReqInfos),check_assertions,
769 cli_check_assertions(ALL,ReqInfos,NOW)),
770 if_option_set(set_goal(GOAL),
771 cli_set_goal(GOAL)),
772 if_option_set(set_searchscope(SCOPE),
773 cli_set_searchscope(SCOPE)),
774 ifm_option_set_loaded(cli_mc(Nr,MCOpts),model_check,
775 cli_start_model_check(Nr,NOW,MCOpts)),
776 ifm_option_set_loaded(cli_random_animate(Steps,ErrOnDeadlock),animate,
777 cli_random_animate(NOW,Steps,ErrOnDeadlock)),
778 ifm_option_set_loaded(execute(ESteps,ErrOnDeadlock,From),execute,
779 cli_execute(ESteps,ErrOnDeadlock,From)),
780 ifm_option_set_loaded(animate_until_ltl(LTLFormula,ExOption,ExpResult,ExpSteps),execute,
781 animate_until_ltl(LTLFormula,ExOption,ExpResult,ExpSteps)),
782 if_option_set_loaded(pa_check,predicate_analysis,
783 test_predicate_analysis),
784
785 cbc_check(NOW),
786
787 ifm_option_set_loaded(logxml_write_ids(Prefix,IDScope),logxml_write_ids,
788 logxml_write_ids(Prefix,IDScope)),
789
790 if_options_set(generate_read_write_matrix_csv(RWCsvFile),
791 generate_read_write_matrix(RWCsvFile)),
792 if_options_set(feasibility_analysis_csv(TimeOut,EnablingCsvFile),
793 do_feasibility_analysis(TimeOut,EnablingCsvFile)),
794 ifm_option_set_loaded(mcm_tests(ADepth1,AMaxS,ATarget1,Output1),mcm_test_cases,
795 mcm_test_case_generation(ADepth1,AMaxS,ATarget1,Output1)),
796 ifm_option_set_loaded(all_deadlocking_paths(File),all_deadlocking_paths,
797 write_all_deadlocking_paths_to_xml(File)),
798 ifm_option_set_loaded(cbc_tests(ADepth2,ATarget2,Output2),cb_test_cases,
799 cbc_test_case_generation(ADepth2,ATarget2,Output2)),
800 ifm_option_set_loaded(test_description(TestDescFile),cb_test_cases,
801 test_generation_by_xml_description(TestDescFile)),
802 if_options_set(csp_in_situ_refinement_check(RP,RType,RQ),
803 cli_csp_in_situ_refinement_check(RP,RType,RQ,NOW)),
804 if_options_set(csp_checkAssertion(Proc,Model,AssertionType),
805 cli_checkAssertion(Proc,Model,AssertionType,NOW)),
806 if_options_set(check_csp_assertion(Assertion),
807 cli_check_csp_assertion(Assertion,NOW)),
808 if_options_set(refinement_check(RefFile,FailuresModel,RefNrNodes),
809 cli_start_refinement_check(RefFile,FailuresModel,RefNrNodes,NOW)),
810 if_options_set(ctl_formula_model_check(CFormula,CExpected),
811 (timeout_call(cli_ctl_model_check(CFormula,init,CExpected,_),NOW,ctl_model_check) -> true; true)),
812 if_options_set(pctl_formula_model_check(PFormula,PExpected),
813 (timeout_call(cli_pctl_model_check(PFormula,init,PExpected,_),NOW,ctl_model_check) -> true; true)),
814 % TO DO print ctl/ltl statistics
815 if_options_set(csp_get_assertions,cli_csp_get_assertions),
816 if_options_set(eval_csp_expression(CspExpr),cli_eval_csp_expression(CspExpr)),
817 if_options_set(csp_translate_to_file(PlFile),cli_csp_translate_to_file(PlFile)),
818 if_options_set(get_coverage_information(CovFileName),cli_get_coverage_information(CovFileName)), %% TODO: replace
819 if_options_set(vacuity_check,cli_vacuity_check),
820 if_option_set_loaded(check_goal,check_goal,cli_check_goal),
821 if_option_set_loaded(animate,animate,
822 (interactive_animate_machine -> true ; true)),
823 if_option_set(ltsmin, start_ltsmin_srv('/tmp/ltsmin.probz', NOW)),
824 if_option_set(ltsmin2(EndpointPath), start_ltsmin_srv(EndpointPath, NOW)),
825 if_option_set(ltsmin_ltl_output(Path), ltsmin_ltl_output(Path, NOW)),
826 if_options_set(run_benchmark(Kind,Option,Path), run_benchmark(Kind,Option,Path)),
827 evaluate_from_commandline,
828 if_option_set_loaded(ltl_assertions,check_ltl_assertions,
829 (timeout_call(ltl_check_assertions,NOW,check_ltl_assertions) -> true; true)),
830 ifm_option_set_loaded(ltl_formula_model_check(LFormula,LExpected),check_ltl_assertions,
831 (option(cli_start_sym_mc_with_lts(_))-> true % we request LTSMin, do not start prob model check
832 ; timeout_call(cli_ltl_model_check(LFormula,init,LExpected,_),NOW,ltl_formula_model_check)
833 -> true; true)),
834 ifm_option_set_loaded(ltl_file(LtlFilename),check_ltl_file,
835 (ltl_check_file(LtlFilename) -> true; true)),
836 ifm_option_set_loaded(visb_history(VJSONFile,VHTMLFile,Options),visb,
837 cli_visb_history(VJSONFile,VHTMLFile,Options)),
838 ifm_option_set_loaded(history(HistoryFilename),history,
839 cli_print_history(HistoryFilename)),
840 ifm_option_set_loaded(print_values(ValuesFilename),sptxt,
841 cli_print_values(ValuesFilename)),
842 ifm_option_set_loaded(print_all_values(ValuesDirname),print_all_values,
843 cli_print_all_values(ValuesDirname)),
844 ifm_option_set_loaded(generate_all_traces_until(LTL_Stop_AsAtom,FilePrefix),generate_all_traces_until,
845 cli_generate_all_traces_until(LTL_Stop_AsAtom,FilePrefix)),
846 if_options_set(save_state_for_refinement(SaveRefF),
847 tcltk_save_specification_state_for_refinement(SaveRefF)),
848 if_options_set(rule_report(File),
849 rule_validation:generate_report(File)),
850 if_options_set(proof_export(Style,File),
851 sequent_prover_exports:export_proof_for_current_state(Style,File)),
852 if_options_set(dot_command(DCommand1,DotFile1,DotEngine1),
853 dot_command(DCommand1,DotFile1,DotEngine1)),
854 if_options_set(dot_command_for_expr(DECommand,Expr,DotFile,Opts,DotEngine),
855 dot_command_for_expr(DECommand,Expr,DotFile,Opts,DotEngine)),
856 if_options_set(plantuml_command(PCommand1,UmlFile1),
857 plantuml_command(PCommand1,UmlFile1)),
858 if_options_set(plantuml_command_for_expr(PECommand,Expr,UmlFile,Opts),
859 plantuml_command_for_expr(PECommand,Expr,UmlFile,Opts)),
860 if_options_set(csv_table_command(TECommand,TableFormulas,TableOptions,TableCSVFile),
861 csv_table_command(TECommand,TableFormulas,TableOptions,TableCSVFile)),
862 if_options_set(evaluate_expression_over_history_to_csv_file(HistExpr,HistDotFile),
863 tcltk_interface:evaluate_expression_over_history_to_csv_file(HistExpr,HistDotFile)),
864 if_options_set(enabling_analysis_csv(EnablingCsvFile),
865 do_enabling_analysis_csv(EnablingCsvFile,NOW)),
866 if_options_set(process_latex_file(LatexF1,LatexF2),
867 process_latex_file(LatexF1,LatexF2)),
868 ifm_option_set(coverage(Nodes,Operations,ShowEnabledInfo),
869 cli_show_coverage(Nodes,Operations,ShowEnabledInfo,NOW)),
870 ifm_option_set(check_statespace_hash(ExpectedHash,Kind),
871 cli_check_statespace_hash(ExpectedHash,Kind)),
872 ifm_option_set(check_op_cache(ExpectedC),
873 cli_check_op_cache(ExpectedC)),
874 ifm_option_set(coverage(ShowEnabledInfo),
875 cli_show_coverage(ShowEnabledInfo,NOW)),
876 if_option_set(save_state_space(StateFile),
877 save_state_space(StateFile)),
878 ifm_option_set(cli_print_statistics(SPARA),
879 cli_print_statistics(SPARA)),
880 if_option_set(show_cache(SCVM),
881 show_cache(SCVM)),
882 if_option_set(cli_cache_stats_check(CStats),cli_cache_stats_check(CStats)),
883 if_option_set(check_complete, check_complete),
884 if_option_set(check_complete_operation_coverage, check_complete_operation_coverage),
885 if_option_set(check_scc_for_ltl_formula(LtlFormula,SCC),cli_check_scc_for_ltl_formula(LtlFormula,SCC)).
886
887 % what needs to be done for files like .po files, where all processing is already done:
888 cli_process_options_for_alrady_fully_processed_file(_MainFile) :-
889 ifm_option_set(cli_print_statistics(SPARA),
890 cli_print_statistics(SPARA)).
891
892 show_cache(default) :- !,
893 (option_verbose -> show_cache(normal) ; show_cache(verbose)).
894 show_cache(Verbose) :-
895 show_cache_file_contents(Verbose).
896
897 cli_cache_stats_check(Expected) :-
898 get_value_persistance_stats(Stats),
899 check_required_infos(Expected,Stats,check_cache_stats).
900
901 % new profiler
902 %:- use_module('../extensions/profiler/profiler.pl').
903 %cli_print_statistics :- pen,nl,garbage_collect,statistics,nl,state_space:state_space_initialise_with_stats.
904
905 :- use_module(runtime_profiler,[print_runtime_profile/0]).
906 :- use_module(source_profiler,[print_source_profile/0]).
907 :- use_module(memoization,[print_memo_profile/0]).
908 :- use_module(state_packing,[print_state_packing_profile/0]).
909 :- use_module(external_functions,[print_external_function_instantiation_profile/0]).
910
911 % old profiler
912 :- use_module(covsrc(hit_profiler),[print_hit_profile_statistics/0]).
913 :- use_module(extrasrc(b_operation_cache),[print_op_cache_profile/0, reset_b_operation_cache_with_statistics/0]).
914 :- use_module(memoization,[reset_memo_with_statistics/0]).
915 :- use_module(disproversrc(disprover),[print_prover_result_stats/0]).
916 :- use_module(probsrc(tools),[print_mb/1]).
917 cli_print_statistics(hshow) :- !,
918 print_machine_topological_order.
919 cli_print_statistics(memory) :- !,
920 print_memory_statistics(user_output).
921 cli_print_statistics(value_persistance_stats) :- !,
922 print_value_persistance_stats.
923 cli_print_statistics(sicstus_profile) :- !,
924 format('SICStus Prolog PROFILE STATISTICS~n',[]),
925 sicstus_profile_statistics.
926 cli_print_statistics(disprover_profile) :- !,
927 print_prover_result_stats.
928 cli_print_statistics(prob_profile) :- !,
929 statistics(walltime,[WT,_]),
930 statistics(runtime,[RT,_]),
931 format('--------------------------~nPROB PROFILING INFORMATION after ~w ms walltime (~w ms runtime) ',[WT,RT]),
932 statistics_memory_used(M), print_mb(M),nl,
933 print_source_profile,
934 print_runtime_profile,
935 print_memo_profile,
936 print_state_packing_profile,
937 print_external_function_instantiation_profile,
938 (get_preference(operation_reuse_setting,false) -> true ; print_op_cache_profile). % relevant for test 2152 under SWI
939 cli_print_statistics(hit_profile) :- !,
940 (print_hit_profile_statistics -> true ; true). % mainly used by external functions
941 cli_print_statistics(op_cache_profile) :- !,
942 get_preference(try_operation_reuse,OR),
943 format('PROB OPERATION_REUSE (value:~w) STATISTICS~n',[OR]),
944 print_op_cache_profile.
945 cli_print_statistics(full) :- format('PROB FULL STATISTICS~n',[]),
946 sicstus_profile_statistics,
947 garbage_collect,
948 statistics,
949 nl,
950 print_op_cache_profile,
951 print_prover_result_stats,
952 state_space:state_space_initialise_with_stats,
953 reset_memo_with_statistics,
954 reset_b_operation_cache_with_statistics.
955
956 print_memory_statistics(Stream) :-
957 garbage_collect,
958 write(Stream,'ProB memory used: '),
959 print_memory_used_wo_gc(Stream), nl(Stream), flush_output(Stream).
960
961 sicstus_profile_statistics :-
962 %(hit_profiler:print_hit_profile_statistics -> true ; true), % only used by external functions
963 (option(profiling_on)
964 -> catch(print_profile,
965 error(existence_error(_,_),_),
966 print_red('SICStus Prolog Profiler can only be used when running from source'))
967 ; true).
968
969
970 :- use_module(state_space,[not_all_transitions_added/1, not_invariant_checked/1,
971 not_interesting/1, get_operation_name_coverage_infos/4]).
972 check_complete :-
973 (tcltk_find_max_reached_node(Node1) ->
974 add_error(check_complete,'Maximum number of transitions reached for at least one state: ',Node1) ; true),
975 (not_all_transitions_added(Node2) ->
976 add_error(check_complete,'At least one state was not examined: ',Node2) ; true),
977 (not_invariant_checked(Node3) ->
978 add_error(check_complete,'The invariant was not checked for at least one state: ',Node3) ; true),
979 (not_interesting(Node4) ->
980 add_message(check_complete,'At least one state was ignored (not satisfying the SCOPE predicate): ',Node4) ; true).
981
982 check_complete_operation_coverage :-
983 (state_space: operation_name_not_yet_covered(OpName) ->
984 add_error(check_complete_operation_coverage,'At least one operation is not covered: ', OpName)
985 ; true).
986
987 show_operation_coverage_summary(NOW) :-
988 get_operation_name_coverage_infos(PossibleNr,FeasibleNr,UncovNr,UncoveredList),
989 writeln_log(uncovered_info(NOW,PossibleNr,UncoveredList)),
990 (UncovNr=0 -> format(' All ~w possible operations have been covered',[PossibleNr]),nl
991 ; (FeasibleNr=PossibleNr
992 -> format(' The following ~w operations (out of ~w) were not covered:~n ~w~n',
993 [UncovNr, PossibleNr,UncoveredList])
994 ; INr is PossibleNr-FeasibleNr,
995 format(' The following ~w operations (out of ~w with ~w infeasible) were not covered:~n ~w~n',
996 [UncovNr, PossibleNr, INr,UncoveredList])
997 )).
998 show_initialisation_summary(NOW) :-
999 findall(ID,state_space:is_concrete_constants_state_id(ID),L),
1000 length(L,Nr), N1 is Nr+1, % for root
1001 writeln_log(uninitialised_states(NOW,N1)),
1002 format(' Uninitialised states: ~w (root and constants only)~n',[N1]).
1003
1004 % ---------------------
1005
1006 animation_mode_does_not_support_animation(File) :-
1007 loaded_main_file(smt2,File).
1008 cli_start_animation(NOW) :-
1009 file_loaded(true,LoadedFile),
1010 \+ animation_mode_does_not_support_animation(LoadedFile),
1011 !,
1012 debug_println(20,'% Starting Animation'),
1013 writeln_log_time(start_animation(NOW)),
1014 start_probcli_timer(Timer1),
1015 start_animation_without_computing,
1016 stop_probcli_debug_timer(Timer1,'% Finished Starting Animation'),
1017 if_option_set(add_csp_guide(CspGuide), tcltk_add_csp_file(CspGuide)),
1018
1019 xml_log_machine_statistics,
1020 getAllOperations(Ops),
1021 debug_print(20,'Operations: '), debug_println(20,Ops),
1022
1023 (we_need_only_static_assertions(ALL)
1024 -> debug_println(20,'% Projecting on static ASSERTIONS'),
1025 ? b_interpreter:set_projection_on_static_assertions(ALL) ; true),
1026
1027 (option(load_state(File))
1028 -> debug_println(20,'% Loading stored state from file'),
1029 state_space:tcltk_load_state(File)
1030 ? ; computeOperations_for_root_required ->
1031 debug_println(20,'% Searching for valid initial states'),
1032 start_probcli_timer(Timer2),
1033 cli_computeOperations(EO),
1034 stop_probcli_debug_timer(Timer2,'% Finished searching for valid initial states'),
1035 debug_println(10,EO)
1036 ; debug_println(20,'% No initialisation required')
1037 ).
1038 cli_start_animation(_NOW).
1039
1040 start_animation_without_computing :-
1041 update_preferences_from_spec(ListOfPrefs),
1042 (ListOfPrefs=[] -> true ; write_prolog_term_as_xml_to_log(b_machine_preferences(ListOfPrefs))),
1043 set_prefs, % override SET_PREF in DEFINITIONS with values from command-line;
1044 start_animation,
1045 ifm_option_set(add_additional_property(PROP),
1046 cli_add_additional_property(PROP)),
1047 get_errors.
1048
1049 animate_until_ltl(LTLFormula,ExOption,ExpectedResult,ExpectedNrSteps) :-
1050 tcltk_animate_until(LTLFormula,ExOption,StepsExecuted,Result),
1051 formatsilent('Found trace of length ~w for LTL formula. Result: ~w ~n',[StepsExecuted,Result]),
1052 print_history_as_counter_example(false), % TODO: only print from current id before command
1053 (ExpectedResult=Result -> true % Result can be ltl_found, maximum_nr_of_steps_reached, deadlock
1054 ; add_error(animate_until_ltl,'Unexpected animation result: ',Result),
1055 error_occurred(animate_until_ltl)
1056 ),
1057 (ExpectedNrSteps=StepsExecuted -> true
1058 ; add_error(animate_until_ltl,'Unexpected number of animation steps: ',StepsExecuted),
1059 error_occurred(animate_until_ltl)
1060 ).
1061
1062 % ---------------------
1063
1064 % an execution engine with minimal overhead: states are not stored in visited_expression database, only first enabled operation is taken
1065
1066 cli_execute(Steps,ErrorOnDeadlock,FromWhere) :-
1067 temporary_set_preference(operation_reuse_setting,false,ChangeOccured),
1068 (ChangeOccured=true % operation reuse not compatible with cut used below after solution found
1069 -> add_debug_message(execute_model,'Disabling OPERATION_REUSE preference for -execute ',Steps) ; true),
1070 call_cleanup(cli_execute2(Steps,ErrorOnDeadlock,FromWhere),
1071 reset_temporary_preference(operation_reuse_setting,ChangeOccured)).
1072 cli_execute2(Steps,ErrorOnDeadlock,FromWhere) :-
1073 FromWhere=from_all_initial_states,!,
1074 % try out all initial states and from each of those perform deterministic execution
1075 start_ms_timer(Start),
1076 format('Running execute from all initial states~n',[]),
1077 reset_counter(cli_execute_inits),
1078 findall(Result,
1079 (cli_trans(root,Action,CurState,0,'$NO_OPERATION'), %print(Action),nl,
1080 (\+ functor(Action,'$setup_constants',_)
1081 -> inc_counter(cli_execute_inits,Nr),
1082 format('~nExecuting model from initial state ~w~n',[Nr]),
1083 (option(animate_stats) -> print_state_silent(CurState) ; true),
1084 (cli_execute_from(CurState,Steps,ErrorOnDeadlock,1,Result) -> true)
1085 ; format('~nInitialising state~n',[]), % we need to execute initialise_machine
1086 cli_trans(CurState,_ActionName,NewState,0,'$NO_OPERATION'),
1087 inc_counter(cli_execute_inits,Nr),
1088 format('~nExecuting model from initial state ~w with constants~n',[Nr]),
1089 (option(animate_stats) -> print_state_silent(NewState) ; true),
1090 (cli_execute_from(NewState,Steps,ErrorOnDeadlock,2,Result) -> true)
1091 )), Results),
1092 get_counter(cli_execute_inits,Nr),
1093 format('---------~nTotal runtime for all ~w executions:',[Nr]),nl,
1094 stop_ms_timer(Start),
1095 count_occurences(Results,Occs), format('Results: ~w~n',[Occs]).
1096 cli_execute2(Steps,ErrorOnDeadlock,current_state(Repetitions)) :-
1097 current_expression(ID,CurState),
1098 start_xml_feature(execute,max_steps,Steps,FINFO),
1099 start_ms_timer(Start),
1100 (between(1,Repetitions,RepNr),
1101 % with -strict option we will stop after first error found
1102 % for repetitions you should probably set RANDOMISE_OPERATION_ORDER and RANDOMISE_ENUMERATION_ORDER to TRUE
1103 debug_format(19,'Starting execute (~w/~w) from state ~w with maximum number of steps ~w~n',[RepNr,Repetitions,ID,Steps]),
1104 (cli_execute_from(CurState,Steps,ErrorOnDeadlock,1,_Result) -> fail ; fail)
1105 ; Repetitions>1 -> stop_ms_timer_with_msg(Start,'-execute-repeat')
1106 ; true),
1107 stop_xml_feature(execute,FINFO).
1108
1109 :- use_module(bmachine,[b_top_level_operation/1]).
1110 allow_filter_unused_constants :-
1111 b_or_z_mode,
1112 b_top_level_operation(_), % we can filter out unused constants, unless there are no operations in which case the user probably wants to see the constant values
1113 \+ options_can_eval_any_cst,
1114 \+ option(cache_storage(_,_)). % we do not know what constants other machines using the cache may use
1115
1116 options_can_eval_any_cst :- option(eval_repl(_)).
1117 options_can_eval_any_cst :- option(eval_string_or_file(_,_,_,_,_)).
1118 options_can_eval_any_cst :- option(dot_command(_,_,_)).
1119 options_can_eval_any_cst :- option(dot_command_for_expr(_,_,_,_,_)).
1120 options_can_eval_any_cst :- option(process_latex_file(_,_)).
1121 options_can_eval_any_cst :- option(logxml_write_ids(all,_)). % the user writes out constants (not just variables) to file: also do not filter
1122
1123 :- dynamic execute_timeout_occurred/0.
1124
1125 cli_execute_from(CurState,Steps,ErrorOnDeadlock,FirstStepNr,Result) :-
1126 retractall(max_walltime(_,_,_)),
1127 retractall(execute_timeout_occurred),
1128 start_ms_timer(Start),
1129 (allow_filter_unused_constants -> temporary_set_preference(filter_unused_constants,true,CHNG) ; true),
1130 cli_execute_aux(FirstStepNr,Steps,CurState,_MEMO,ErrorOnDeadlock,'$NO_OPERATION',Result),
1131 (allow_filter_unused_constants -> reset_temporary_preference(filter_unused_constants,CHNG) ; true),
1132 (option(silent) -> true ; stop_ms_timer_with_msg(Start,'-execute')),
1133 print_max_walltime.
1134
1135 :- use_module(tools_strings,[ajoin/2, ajoin_with_sep/3]).
1136 :- use_module(external_functions,[reset_side_effect_occurred/0, side_effect_occurred/1]).
1137 cli_execute_aux(Nr,Steps,CurState,_,_ErrorOnDeadlock,_LastActionName,Result) :- Nr>Steps,!,
1138 formatsilent('Stopping execution after ~w steps~n',[Steps]), Result = stopped,
1139 print_state_silent(CurState),
1140 cli_execute_add_virtual_transition(Steps,CurState,Result).
1141 cli_execute_aux(Nr,Steps,CurState0,MEMO,ErrorOnDeadlock,LastActionName,Result) :-
1142 (Nr mod 5000 =:= 0, \+option(animate_stats), \+option(silent)
1143 -> (var(LastActionName) -> format('Step ~w~n',[Nr])
1144 ; format('Step ~w (after ~w)~n',[Nr,LastActionName])),
1145 (option_verbose -> print_state_silent(CurState0) ; true),
1146 %copy_term(CurState0,CurState), tools_printing:print_term_summary((CurState0)),nl,
1147 !,
1148 garbage_collect,
1149 !,
1150 print('Memory used: '),print_memory_used_wo_gc,flush_output,nl %nl_time
1151 ; true),
1152 prepare_state_for_specfile_trans(CurState0,unknown,MEMO,CurState), % ensure we memoize expanded constants in MEMO
1153 % avoid re-expanding constants in every state !
1154 % relevant e.g. for probcli -execute 20001 DataValidationTestSmallStep.mch -init
1155 (cli_invariant_ko(CurState,LastActionName,InvStatus,CliErr) -> % also recognises no_inv command
1156 N1 is Nr-1,
1157 ajoin(['INVARIANT ',InvStatus,' after ',N1,' steps (after ',LastActionName,').'],ErrMsg),
1158 format('~w~n',[ErrMsg]),!,
1159 print_state_silent(CurState),
1160 error_occurred_with_msg(CliErr,ErrMsg),
1161 Result=CliErr,
1162 cli_execute_add_virtual_transition(N1,CurState,Result,NewID),
1163 %(option_verbose -> b_interpreter:analyse_invariant_for_state(NewID) ; true)
1164 b_interpreter:analyse_invariant_for_state(NewID)
1165 ; cli_assertions_ko(CurState,LastActionName,AssRes) -> % also recognises no_inv command
1166 N1 is Nr-1,
1167 format('ASSERTIONS ~w after ~w steps (after ~w).~n',[AssRes,N1,LastActionName]),!,
1168 print_state_silent(CurState),
1169 error_occurred(assertion_violation), Result=assertion_violation,
1170 cli_execute_add_virtual_transition(N1,CurState,Result)
1171 ; cli_goal_found(CurState) -> % also recognizes no_goal command
1172 N1 is Nr-1,
1173 format('GOAL FOUND after ~w steps (after ~w).~n',[N1,LastActionName]),!,
1174 print_state_silent(CurState), Result=goal_found,
1175 cli_execute_add_virtual_transition(N1,CurState,Result)
1176 ; reset_side_effect_occurred,
1177 cli_trans(CurState,ActionName,NewState,Nr,LastActionName), % Compute new transition
1178 !,
1179 N1 is Nr+1,
1180 (NewState=CurState0, % could be expensive for large states; states are expanded ! % TO DO: look only at written variables ?!
1181 \+ side_effect_occurred(file)
1182 -> formatsilent('Infinite loop reached after ~w steps (looping on ~w).~n',[N1,ActionName]),
1183 Result=loop,
1184 print_state_silent(CurState),
1185 cli_execute_add_virtual_transition(N1,CurState,Result)
1186 ; cli_execute_aux(N1,Steps,NewState,MEMO,ErrorOnDeadlock,ActionName,Result))
1187 ).
1188 cli_execute_aux(Nr,_Steps,CurState,_,_ErrorOnDeadlock,LastActionName,Result) :- execute_timeout_occurred,!,
1189 N1 is Nr-1,
1190 formatsilent('Timeout occurred after ~w steps (after ~w).~n',[N1,LastActionName]),
1191 Result=time_out,
1192 print_state_silent(CurState),
1193 cli_execute_add_virtual_transition(N1,CurState,Result).
1194 cli_execute_aux(Nr,_Steps,CurState,_,ErrorOnDeadlock,LastActionName,Result) :- N1 is Nr-1,
1195 formatsilent('Deadlock reached after ~w steps (after ~w).~n',[N1,LastActionName]),
1196 Result=deadlock,
1197 (ErrorOnDeadlock=true,\+ option(no_deadlocks) -> error_occurred(deadlock) ; true),
1198 print_state_silent(CurState),
1199 cli_execute_add_virtual_transition(N1,CurState,Result).
1200
1201 check_nr_of_steps(Steps) :- option(execute_expect_steps(ExpSteps)),
1202 (Steps = ExpSteps -> formatsilent('The expected number of steps were executed: ~w~n',[Steps]),fail
1203 ; true),
1204 !,
1205 ajoin(['Unexpected number of steps ',Steps,', expected:'],Msg),
1206 add_error(cli_execute,Msg,ExpSteps).
1207 check_nr_of_steps(_).
1208
1209 cli_execute_add_virtual_transition(Steps,CurState,Result) :-
1210 cli_execute_add_virtual_transition(Steps,CurState,Result,_).
1211 cli_execute_add_virtual_transition(Steps,CurState,Result,ToID) :-
1212 current_state_id(CurID),
1213 write_xml_element_to_log(executed,[steps/Steps,result/Result]),
1214 (Steps=0 -> true
1215 ; some_command_requires_state_space % check whether storing is actually useful for any outstanding command
1216 -> (CurID=root
1217 -> tcltk_interface:tcltk_add_cbc_state(CurState,'$execute'(Steps)) % generate separate constants state
1218 ; tcltk_interface:tcltk_add_new_transition(CurID,'$execute'(Steps),ToID,CurState,[]),
1219 tcltk_goto_state('$execute'(Steps),ToID)
1220 ),
1221 debug_format(19,'Added transition ~w -> ~w to state space for ~w execution steps~n',[CurID,ToID,Steps])
1222 ; debug_format(19,'Not adding transition for -execute ~w steps; not required by other commands~n',[Steps])
1223 ),
1224 check_nr_of_steps(Steps).
1225
1226 some_command_requires_state_space :-
1227 option(X),
1228 \+ does_not_require_state_space(X),
1229 !.
1230 does_not_require_state_space(execute_expect_steps(_)).
1231 does_not_require_state_space(execute(_,_,_)).
1232 does_not_require_state_space(animate_stats).
1233 does_not_require_state_space(execute_monitoring).
1234 does_not_require_state_space(set_pref(_,_)).
1235 does_not_require_state_space(set_preference_group(_,_)).
1236 does_not_require_state_space(timeout(_)).
1237 does_not_require_state_space(verbose(_)).
1238 does_not_require_state_space(verbose_off).
1239 does_not_require_state_space(silent).
1240 does_not_require_state_space(force_no_silent).
1241 does_not_require_state_space(strict_raise_error).
1242 does_not_require_state_space(release_java_parser).
1243 does_not_require_state_space(fast_read_prob).
1244 does_not_require_state_space(file_info).
1245 does_not_require_state_space(print_version(_)).
1246 does_not_require_state_space(check_java_version).
1247 does_not_require_state_space(pretty_print_internal_rep(_,_,_,_)).
1248 does_not_require_state_space(expect_error(_)).
1249 does_not_require_state_space(optional_error(_)).
1250 does_not_require_state_space(no_deadlocks).
1251 does_not_require_state_space(no_invariant_violations).
1252 does_not_require_state_space(no_goal).
1253 does_not_require_state_space(no_assertion_violations).
1254 does_not_require_state_space(no_state_errors).
1255 does_not_require_state_space(no_counter_examples).
1256 does_not_require_state_space(no_color).
1257 % TODO: register more commands that do not require the state space
1258
1259 :- dynamic max_walltime/3.
1260 print_max_walltime :- (max_walltime(Action,Nr,WT),option_verbose
1261 -> format('% Maximum walltime ~w ms at step ~w for ~w.~n',[WT,Nr,Action]) ; true).
1262
1263 % will be used to compute a single successor
1264 % b_operation_cannot_modify_state
1265 cli_trans(CurState,ActionName,NewState,Nr,LastActionName) :-
1266 option(animate_stats),!, % provide statistics about the animation
1267 start_probcli_timer(Timer),
1268 cli_trans_aux(CurState,ActionName,Act,NewState,Nr,LastActionName),
1269 (option_verbose -> translate:translate_event(Act,TStr)
1270 ; translate:translate_event_with_limit(Act,100,TStr)),
1271 format('~w~5|: ~w~n',[Nr,TStr]),
1272 format(' ~5|',[]),stop_probcli_timer(Timer,' '),
1273 (option_verbose -> format(' ~5|',[]),print_memory_used_wo_gc,nl ; true),
1274 flush_output,
1275 get_probcli_elapsed_walltime(Timer,WallTime),
1276 get_probcli_elapsed_runtime(Timer,RunTime),
1277 accumulate_infos(animate_stats,[step-1,step_nr-Nr,runtime-RunTime,walltime-WallTime]),
1278 (max_walltime(_,_,MWT), MWT >= WallTime -> true
1279 ; retractall(max_walltime(_,_,_)),
1280 assertz(max_walltime(ActionName,Nr,WallTime))).
1281 cli_trans(CurState,ActionName,NewState,Nr,LastActionName) :-
1282 cli_trans_aux(CurState,ActionName,_,NewState,Nr,LastActionName).
1283
1284 cli_trans_aux(CurState,ActionName,Act,NewState,Nr,LastActionName) :-
1285 option(timeout(TO)),!,
1286 safe_time_out(cli_trans_aux2(CurState,ActionName,Act,NewState,LastActionName),TO,Res),
1287 (Res=time_out -> format_error_with_nl('! Timeout occurred while performing step ~w of execute: ~w ms',[Nr,TO]),
1288 % TO DO: try and obtain operation name in which time-out occured
1289 error_occurred(time_out,execute),
1290 assertz(execute_timeout_occurred),
1291 fail
1292 ; true).
1293 cli_trans_aux(CurState,ActionName,Act,NewState,_Nr,LastActionName) :-
1294 cli_trans_aux2(CurState,ActionName,Act,NewState,LastActionName).
1295
1296 cli_trans_aux2(CurState,ActionName,Act,NewState,LastActionName) :-
1297 catch_enumeration_warning_exceptions(
1298 (throw_enumeration_warnings_in_current_scope,
1299 cli_execute_trans(CurState,ActionName,Act,NewState,LastActionName), % no time-out !
1300 (error_occurred_in_error_scope -> ErrorEvent=true ; ErrorEvent=false)
1301 ),
1302 (error_occurred(virtual_time_out_execute),
1303 ActionName = '*** VIRTUAL_TIME_OUT ***', Act=ActionName,
1304 CurState=NewState) % this forces loop detection above; not very elegant way of signalling
1305 ),
1306 (ErrorEvent==true,option(strict_raise_error)
1307 -> print('*** ERROR OCCURED DURING EXECUTE ***'),nl, error_occurred(execute),fail
1308 ; true).
1309
1310 :- use_module(runtime_profiler,[profile_single_call/3]).
1311 :- use_module(specfile,[get_specification_description/2]).
1312 cli_execute_trans(CurState,ActionName,Act,NewState,LastActionName) :-
1313 statistics(runtime,[StartExecuteForState,_]),
1314 get_possible_next_operation_for_execute(CurState,LastActionName,ActionName),
1315 start_check_disabled(ActionName,StartActionTime),
1316 catch(
1317 profile_single_call(ActionName,
1318 unknown, % state Unknown
1319 specfile_trans_with_check(CurState,ActionName,Act,NewState,Residue) % no time-out !
1320 ),
1321 EXC,
1322 (translate_exception(EXC,EMSG),
1323 (nonvar(ActionName)
1324 -> get_specification_description(operation,OP),
1325 format_with_colour_nl(user_error,[red,bold],'~n*** ~w while executing ~w "~w"~n',[EMSG,OP,ActionName])
1326 ; get_specification_description(operations,OP),
1327 format_with_colour_nl(user_error,[red,bold],'~n*** ~w while computing ~w~n',[EMSG,OP])
1328 ),
1329 perform_feedback_options_after_exception,
1330 throw(EXC))),
1331 (Residue=[]
1332 -> check_trans_time(StartExecuteForState,StartActionTime,ActionName)
1333 ; error_occurred(cli_execute_residue(ActionName,Residue,Act))).
1334
1335 :- use_module(probsrc(static_enabling_analysis),[static_cannot_enable/2,
1336 static_disables_itself/1, static_disabled_after/2]).
1337 % compute all possible next operations to try out in -execute, based on LastActionName
1338 % the predicate makes use of the fact that operations are tried in order
1339 get_possible_next_operation_for_execute(CurState,LastActionName,ActionName) :-
1340 get_preference(randomise_operation_order,false),
1341 get_preference(use_po,true), % PROOF_INFO: should we use a proper preference for use_po_for_execute ?
1342 b_or_z_mode,
1343 b_top_level_operation(LastActionName),
1344 % prevent trying ActionName which we know is infeasible according to previous LastActionName
1345 % we rely on the fact that execute tries the operations in order
1346 findall(AN,specfile_possible_trans_name_for_successors(CurState,AN),ANS),
1347 !,
1348 member_with_last(ActionName,ANS,LastActionName,FoundLast),
1349 (var(FoundLast)
1350 -> % ActionName occurs before LastActionName, this means
1351 % we did try this ActionName at the last execution step and it was not possible
1352 % format('** Checking operation ~w against ~w~n',[ActionName,LastActionName]),debug:nl_time,
1353 %Note: we could use result of cbc enabling analysis if it was performed
1354 (static_cannot_enable(LastActionName,ActionName)
1355 -> %format('Operation ~w : ~w cannot be enabled by ~w : ~w~n',[Nr2,ActionName,Nr1,LastActionName]),
1356 %print('- '),
1357 fail
1358 ; true
1359 )
1360 ; ActionName=LastActionName, static_disables_itself(ActionName)
1361 -> %format('** Operation ~w cannot be enabled after itself~n',[ActionName]),
1362 fail
1363 %; static_disabled_after(LastActionName,ActionName) % TODO: check if this more general case is worth it
1364 % -> format('** Operation ~w cannot be enabled after ~w~n',[ActionName,LastActionName]),
1365 % fail
1366 ; true % we did not try this ActionName at the last execution step
1367 ).
1368 get_possible_next_operation_for_execute(CurState,_LastActionName,ActionName) :-
1369 specfile_possible_trans_name_for_successors(CurState,ActionName).
1370
1371 % like member but instantiate FoundLast when we pass the element Last
1372 member_with_last(X,[H|T],Last,FoundLast) :-
1373 (H=Last -> !,FoundLast=true, member(X,[H|T]) ; X=H).
1374 member_with_last(X,[_|T],Last,FoundLast) :- member_with_last(X,T,Last,FoundLast).
1375
1376 :- use_module(probsrc(value_persistance),[start_cache_execute_modus/1,stop_cache_execute_modus/0,
1377 add_new_transition_to_cache_from_expanded_state/4]).
1378 % also checks whether a setup_constants_inconsistent error should be raised:
1379 specfile_trans_with_check(CurState,ActionName,Act,NewState,Residue) :-
1380 start_cache_execute_modus(CacheInfo),
1381 if(specfile_trans_or_partial_trans(CurState,ActionName,Act,NewState,_TransInfo,Residue,Partial), % no time-out !
1382 (check_partial_trans(Partial,ActionName),
1383 (Partial=true -> true ; add_new_transition_to_cache_from_expanded_state(CurState,Act,NewState,CacheInfo)),
1384 stop_cache_execute_modus
1385 ),
1386 (stop_cache_execute_modus,
1387 check_deadlock_fail(ActionName) % add_deadlock_to_cache_from_expanded_state(CurState,ActionName)
1388 )
1389 ).
1390
1391 % check whether we should raise errors on deadlock in -execute:
1392 check_deadlock_fail('$setup_constants') :- !, error_occurred(setup_constants_inconsistent),fail.
1393
1394 % check whether we should raise errors due to partial transitions in -execute:
1395 check_partial_trans(true,'$setup_constants') :- !, error_occurred(setup_constants_inconsistent).
1396 check_partial_trans(true,ActionName) :- !, format('Unknown partial transition: ~w~n',[ActionName]),
1397 error_occurred(setup_constants_inconsistent).
1398 check_partial_trans(_,_).
1399
1400 % check if we did not spend too much time on disabled operations and print warning if we do
1401 check_trans_time(StartExecuteForState,StartActionTime,ActionName) :-
1402 option(execute_monitoring),
1403 statistics(runtime,[CurrentTime,_]),
1404 Delta1 is StartActionTime-StartExecuteForState,
1405 Delta2 is CurrentTime-StartActionTime,
1406 Delta1 > 100, Delta1 > Delta2,
1407 !,
1408 format_with_colour(user_output,[blue],'~n ~5|: WARNING from -execute_monitor: ~w ms for disabled operations and ~w ms for operation ~w itself~n',[Delta1,Delta2,ActionName]).
1409 check_trans_time(_,_,_).
1410
1411 % check if we did not spend too much time on a single disabled operations and print warning if we do
1412 start_check_disabled(ActionName,StartActionTime) :- option(execute_monitoring),!,
1413 statistics(runtime,[StartActionTime,_]),
1414 (true
1415 ; statistics(runtime,[EndActionTime,_]),
1416 Delta is EndActionTime - StartActionTime,
1417 Delta > 50,
1418 format_with_colour(user_output,[blue],'~n ~5|: WARNING from -execute_monitor: ~w ms for disabled operation ~w~n',[Delta,ActionName]),
1419 fail
1420 ).
1421 start_check_disabled(_,0).
1422
1423 translate_exception(user_interrupt_signal,'User-Interrupt (CTRL-C)').
1424 translate_exception(enumeration_warning(_,_,_,_,_),'Enumeration Warning').
1425 translate_exception(E,E).
1426
1427 :- use_module(bmachine,[b_machine_has_constants/0]).
1428 print_state_silent(_) :- option(silent),!.
1429 print_state_silent(CurState) :- \+ b_or_z_mode, !, translate:print_state(CurState), nl.
1430 print_state_silent(CurState) :- (option_verbose;\+ b_machine_has_constants),!,
1431 translate:print_bstate_limited(CurState,1000,-1),nl.
1432 print_state_silent(CurState) :- remove_constants(CurState,VarState),
1433 % only print variables
1434 format('VARIABLES (use -v to see constants or -silent to suppress output):~n',[]),
1435 translate:print_bstate_limited(VarState,1000,-1),nl.
1436
1437 :- use_module(bmachine,[b_is_constant/1]).
1438 is_constant_binding(bind(C,_)) :- b_is_constant(C).
1439 remove_constants(const_and_vars(_,Vars),Res) :- !,Res=Vars.
1440 remove_constants([H|T],Res) :- !,exclude(prob_cli:is_constant_binding,[H|T],Res).
1441 remove_constants(root,Res) :- !,Res=[].
1442 remove_constants(concrete_constants(_),Res) :- !, Res=[].
1443 remove_constants(X,X).
1444
1445 % write vars to xml log file if they start with a given prefix
1446 logxml_write_ids(variables,Prefix) :- !,
1447 current_expression(_,CurState),
1448 remove_constants(CurState,VarState),
1449 % TO DO: store also final state in xml_log
1450 write_bstate_to_log(VarState,Prefix).
1451 logxml_write_ids(_,Prefix) :- !,
1452 current_expression(_,CurState),
1453 expand_const_and_vars_to_full_store(CurState,EState),
1454 write_bstate_to_log(EState,Prefix).
1455
1456 :- use_module(bmachine,[b_get_invariant_from_machine/1, b_specialized_invariant_for_op/2, b_machine_has_constants/0]).
1457 cli_invariant_ko(_,_,_,_) :- option(no_invariant_violations),!,fail. % user asks not to check it
1458 cli_invariant_ko(_,_,_,_) :- get_preference(do_invariant_checking,false),!,fail. % user asks not to check it via preference
1459 cli_invariant_ko(CurState,LastActionName,ResInvStatus,CliError) :-
1460 profile_single_call('INVARIANT',unknown,cli_invariant_ko2(CurState,LastActionName,ResInvStatus,CliError)).
1461 cli_invariant_ko2(CurState,LastActionName,ResInvStatus,CliError) :-
1462 state_corresponds_to_initialised_b_machine(CurState,BState),!,
1463 start_probcli_timer(InvTimer),
1464 (b_specialized_invariant_for_op(LastActionName,Invariant) -> true
1465 %, print('Specialized invariant: '),translate:print_bexpr(Invariant),nl
1466 ; b_get_invariant_from_machine(Invariant)),
1467 cli_test_pred(BState,'INVARIANT',Invariant,ResInvStatus),
1468 stop_probcli_debug_timer(InvTimer,'Finished Invariant Checking'),
1469 ResInvStatus \= 'TRUE',
1470 (ResInvStatus == 'FALSE' -> CliError = invariant_violation
1471 ; ResInvStatus == 'UNKNOWN' -> CliError = invariant_unknown
1472 ; ResInvStatus == 'TIME-OUT' -> CliError = invariant_time_out
1473 ; format_error_with_nl('Unexpected invariant status: ~w',[ResInvStatus]),
1474 CliError= invariant_unknown).
1475 %cli_invariant_ko(_,_,_,_) :- fail. % not yet initialised
1476
1477 :- use_module(b_interpreter,[b_test_boolean_expression_for_ground_state/4]).
1478 cli_test_pred(BState,PredKind,Pred) :- cli_test_pred(BState,PredKind,Pred,'TRUE').
1479 % comment in following clause to get more precise location for exceptions/virtual timeouts:
1480 %cli_test_pred(BState,PredKind,Pred,Res) :- option_verbose, bsyntaxtree:decompose_conjunct(Pred,A,B),!,
1481 % cli_test_pred(BState,PredKind,A,ResA), (ResA = 'TRUE' -> cli_test_pred(BState,PredKind,B,Res) ; Res = ResA).
1482 cli_test_pred(BState,PredKind,Pred,Res) :- option(timeout(TO)),!,
1483 debug_format(9,'Testing ~w with time-out ~w~n',[PredKind,TO]),
1484 safe_time_out(cli_test_pred2(BState,PredKind,Pred,Res), TO, TRes),
1485 (Res=time_out -> TRes='TIME-OUT' ; true).
1486 cli_test_pred(BState,PredKind,Pred,Res) :-
1487 debug_format(9,'Checking ~w without a time-out~n',[PredKind]),
1488 cli_test_pred2(BState,PredKind,Pred,Res).
1489 cli_test_pred2(BState,PredKind,Pred,Res) :-
1490 % currently does not do a time-out: % b_interpreter calls: time_out_with_enum_warning_one_solution_no_new_error_scope
1491 catch(
1492 on_enumeration_warning(b_test_boolean_expression_for_ground_state(Pred,[],BState,PredKind ), (
1493 add_error(cli_test_pred,'Enumeration warning while testing',PredKind,Pred),
1494 cli_print_pred_info(Pred),
1495 Res='UNKNOWN')
1496 ),
1497 E,
1498 (
1499 ajoin(['VIRTUAL TIME-OUT or exception while testing ',PredKind,': '],Msg),
1500 add_error(cli_test_pred,Msg,E,Pred), % E can also be user_interrupt_signal
1501 cli_print_pred_info(Pred),
1502 Res='UNKNOWN'
1503 )
1504 ),
1505 !,
1506 (var(Res) -> Res = 'TRUE' ; true).
1507 cli_test_pred2(_BState,_PredKind,_Pred,'FALSE').
1508
1509 cli_print_pred_info(Pred) :- get_texpr_label(Pred,Label),
1510 format('Label = ~w~n',[Label]),fail.
1511 cli_print_pred_info(Pred) :- get_texpr_description(Pred,Desc),
1512 format('Description = ~w~n',[Desc]),fail.
1513 %cli_print_pred_info(Pred) :- bsyntaxtree:get_texpr_pos(Pred,Pos), Pos \= none, translate_span(Pos,Str),
1514 % format('Location = ~w~n',[Str]),fail.
1515 cli_print_pred_info(Pred) :-
1516 option_verbose,
1517 write('Predicate: '), translate:nested_print_bexpr(Pred),nl.
1518
1519 :- use_module(bmachine,[get_assertions_from_machine/2]).
1520 % TO DO: also check static assertions
1521 cli_assertions_ko(_,_,_) :- option(no_assertion_violations),!,fail. % user asks not to check it
1522 cli_assertions_ko(CurState,_LastActionName,Res) :-
1523 state_corresponds_to_initialised_b_machine(CurState,BState),
1524 get_assertions_from_machine(dynamic,Assertions), % TO DO: do something similar to b_specialized_invariant_for_op
1525 !,
1526 profile_single_call('ASSERTIONS',unknown,cli_assertions_ko2(BState,Assertions,Res)).
1527
1528
1529 cli_assertions_ko2(BState,Assertions,Res) :-
1530 start_probcli_timer(AssTimer),
1531 %nl,nl,print(check),nl,maplist(translate:print_bexpr,Assertions),nl,
1532 (member(Ass,Assertions),
1533 cli_test_pred(BState,'ASSERTION',Ass,Res),
1534 Res \= 'TRUE' -> true
1535 ; Res = 'TRUE'
1536 ),
1537 stop_probcli_debug_timer(AssTimer,'Finished Checking Assertions'),
1538 Res \= 'TRUE'.
1539
1540
1541 :- use_module(bmachine,[b_get_machine_goal/1]).
1542 cli_goal_found(_):- option(no_goal),!,fail.
1543 cli_goal_found(CurState) :-
1544 b_get_machine_goal(Goal),
1545 state_corresponds_to_initialised_b_machine(CurState,BState),
1546 profile_single_call('GOAL',unknown,cli_goal_found2(Goal,BState)).
1547 cli_goal_found2(Goal,BState) :-
1548 b_test_boolean_expression_for_ground_state(Goal,[],BState,'GOAL').
1549
1550
1551 % random animation
1552 :- public cli_random_animate/2. % for repl to use -animate command
1553 cli_random_animate(Steps,Err) :- probcli_time_stamp(NOW),
1554 cli_random_animate(NOW,Steps,Err).
1555 cli_random_animate(_NOW,Steps,ErrorOnDeadlock) :-
1556 start_xml_feature(random_animate,max_steps,Steps,FINFO),
1557 start_ms_timer(Start),
1558 perform_random_steps(Steps,ErrorOnDeadlock),
1559 (option(silent) -> true ; stop_ms_timer_with_msg(Start,'-animate')),
1560 %tcltk_save_history_as_trace_file(prolog,user),
1561 stop_xml_feature(random_animate,FINFO).
1562
1563 :- use_module(bmachine,[b_get_assertions/3]).
1564 we_need_only_static_assertions(ALL) :- specfile:b_or_z_mode,
1565 (option(cli_check_assertions(main,_)) -> ALL=main
1566 ; option(cli_check_assertions(ALL,_))),
1567 % we do an assertion check
1568 ? \+ ((option(A), option_requires_all_properties(A))),
1569 b_get_assertions(ALL,dynamic,[]). % the assertions do not reference variables
1570
1571 % do we need all properties/constants of the machine, or only certain ones (e.g., static)
1572 option_requires_all_properties(cli_mc(_,_)).
1573 option_requires_all_properties(cli_check_properties). % we may want to check all properties
1574 option_requires_all_properties(cli_core_properties(_)).
1575 option_requires_all_properties(cli_random_animate(_)).
1576 option_requires_all_properties(default_trace_check).
1577 option_requires_all_properties(trace_check(_,_,_)).
1578 option_requires_all_properties(state_trace(_)).
1579 option_requires_all_properties(mcm_tests(_,_,_,_)).
1580 option_requires_all_properties(cbc_tests(_,_,_)).
1581 option_requires_all_properties(animate).
1582 option_requires_all_properties(initialise). % INITIALISATION may access constants
1583 option_requires_all_properties(eval_repl(_)).
1584 option_requires_all_properties(eval_string_or_file(_,_,_,_,_)).
1585 option_requires_all_properties(ltl_assertions).
1586 option_requires_all_properties(ltl_file(_)).
1587 option_requires_all_properties(refinement_check(_,_,_)).
1588 option_requires_all_properties(cli_start_mc_with_tlc).
1589 option_requires_all_properties(cli_symbolic_model_check(_)).
1590 option_requires_all_properties(process_latex_file(_,_)).
1591 option_requires_all_properties(cli_wd_check(_,_)).
1592 option_requires_all_properties(cli_lint(_)).
1593 option_requires_all_properties(visb_history(_,_,_)).
1594
1595 :- use_module(b_intelligent_trace_replay,[replay_json_trace_file/2]).
1596 :- public default_trace_check/0.
1597 default_trace_check :- loaded_main_file(_,MainFile),
1598 cli_start_default_trace_check(MainFile).
1599 cli_start_default_trace_check(MainFile) :-
1600 debug_println(20,'% Starting Default Trace Check: '),
1601 (check_default_trace_for_specfile(MainFile) -> true ; error_occurred(trace_check)).
1602
1603 default_json_trace_save :-
1604 loaded_main_file(_,MainFile),
1605 get_default_trace_file(MainFile,'.prob2trace',HistFile),
1606 format('Saving history to JSON ProB2-UI default trace file: ~w~n',[HistFile]),
1607 tcltk_save_history_as_trace_file(json,HistFile).
1608 cli_start_trace_check(json,File,default_trace_replay) :- !,
1609 replay_json_trace_file(File,Status),
1610 (Status=perfect -> true
1611 ; Status = imperfect -> add_warning(trace_replay,'Imperfect JSON trace replay:',Status)
1612 ; add_error(trace_replay,'Failed JSON trace replay:',Status)
1613 ).
1614 cli_start_trace_check(Style,File,Mode) :-
1615 debug_format(20,'% Starting Trace Check (~w:~w): ~w~n',[Style,Mode,File]),
1616 (tcltk_check_sequence_from_file(Style,File,Mode) -> true ; error_occurred(trace_check)).
1617 cli_start_trace_state_check(File) :-
1618 debug_println(20,'% Starting Trace Check: '),
1619 (tcltk_check_state_sequence_from_file(File) -> true ; error_occurred(state_trace)).
1620
1621 % is it necessary to compute enabled operations for root state
1622 ?computeOperations_for_root_required :- initialise_required.
1623 computeOperations_for_root_required :- option(default_trace_check).
1624 computeOperations_for_root_required :- option(trace_check(_,_,_)).
1625 computeOperations_for_root_required :- option(state_trace(_)).
1626 computeOperations_for_root_required :- option(ltl_assertions).
1627 computeOperations_for_root_required :- option(cli_random_animate(_,_)).
1628 computeOperations_for_root_required :- option(socket(_,_)).
1629 computeOperations_for_root_required :- option(cli_mc(_,_)).
1630 computeOperations_for_root_required :- option(ltl_file(_)).
1631 computeOperations_for_root_required :- option(ltl_formula_model_check(_,_)).
1632 computeOperations_for_root_required :- option(ctl_formula_model_check(_,_)).
1633 computeOperations_for_root_required :- option(pctl_formula_model_check(_,_)).
1634 computeOperations_for_root_required :- option(refinement_check(_,_,_)).
1635 computeOperations_for_root_required :- option(csp_in_situ_refinement_check(_,_)).
1636 computeOperations_for_root_required :- option(csp_checkAssertion(_,_)).
1637 computeOperations_for_root_required :- option(mcm_tests(_,_,_,_)).
1638 computeOperations_for_root_required :- option(mcm_cover(_)).
1639
1640 % is an initialisation mandatory:
1641 initialise_required :- option(initialise), \+ empty_machine_loaded.
1642 initialise_required :- \+ option(default_trace_check), \+ option(trace_check(_,_,_)), \+ option(state_trace(_)),
1643 \+ option(load_state(_)),
1644 \+ empty_machine_loaded,
1645 \+ (option(execute(Nr,_,_)), Nr>=2), % execute will also initialise machine
1646 ? init_req2.
1647 init_req2 :- option(cli_check_properties).
1648 init_req2 :- option(zmq_assertion(_,_,_)).
1649 init_req2 :- option(cli_check_assertions(_,_)).
1650 init_req2 :- option(process_latex_file(_,_)).
1651 init_req2 :- option(eval_string_or_file(_,_,_,_,_)). % ensure that we initialise/precompile empty machine in case no main file specified; currently no longer required
1652 init_req2 :- option(check_abstract_constants).
1653 init_req2 :- option(visb_click(_)).
1654 init_req2 :- option(dot_command_for_expr(Cat,_,_,_,_)),
1655 nonmember(Cat,[transition_diagram,expression_coverage]). % see test 1033, option also works with empty state space
1656 %init_req2 :- option(csv_table_command(Cat,_,_,_)), ...
1657
1658 :- public initialise/0. % for REPL
1659 initialise :- probcli_time_stamp(NOW),cli_start_initialisation(NOW).
1660
1661 cli_start_initialisation(NOW) :-
1662 debug_println(20,'% Performing INITIALISATION: '),
1663 (perform_random_initialisation -> true ;
1664 writeln_log_time(cli_start_initialisation_failed(NOW)),
1665 fail).
1666
1667 :- use_module(wdsrc(well_def_analyser),[analyse_wd_for_machine/4]).
1668 :- public cli_wd_check/2. % for REPL
1669 cli_wd_check(ExpectedDis,ExpectedTot) :-
1670 (option(timeout(TO)) -> true ; TO=5000), % this is global_time_out option
1671 (option(silent) -> Opts=[discharge_po,ignore_wd_infos,reorder_conjuncts]
1672 ; Opts=[create_not_discharged_msg(warning),discharge_po,ignore_wd_infos,reorder_conjuncts]),
1673 statistics(walltime,[W1,_]),
1674 safe_time_out(analyse_wd_for_machine(NrDischarged,NrTot,_Res,Opts),TO,Res),
1675 statistics(walltime,[W2,_]), WT is W2-W1,
1676 (Res=time_out -> accumulate_infos(wd_check,[timeout-1,walltime-WT]), % discharged and total are unknown
1677 add_error(cli_wd_check,'TIME-OUT in WD Analysis (use -global_time_out X to increase it)')
1678 ; format(user_output,'WD Analysis Result: discharged ~w / ~w',[NrDischarged,NrTot]),
1679 (NrTot >0
1680 -> Perc is 100*NrDischarged/NrTot,
1681 (NrDischarged=NrTot -> Col=[green,bold] ; Col=[red])
1682 ; Perc = 100, Col=[]),
1683 format_with_colour(user_output,Col,' (~2f %)~n',[Perc]),
1684 WDInfos = [discharged-NrDischarged,timeout-0,total-NrTot,walltime-WT],
1685 accumulate_infos(wd_check,WDInfos),
1686 (ExpectedDis==ExpectedTot, ExpectedTot = NrTot -> true ; true), % for -wd-check-all: bind ExpectedDis
1687 check_required_infos([discharged-ExpectedDis,total-ExpectedTot],WDInfos,cli_wd_check)
1688 ).
1689 :- use_module(wdsrc(well_def_analyser),[analyse_invariants_for_machine/5]).
1690 cli_wd_inv_proof(UnchangedNr,ProvenNr,TotPOsNr) :-
1691 (option(timeout(TO)) -> true ; TO=5000),
1692 Options=[],
1693 statistics(walltime,[W1,_]),
1694 safe_time_out(analyse_invariants_for_machine(UnchangedNr,ProvenNr,UnProvenNr,TotPOsNr,Options),TO,Res),
1695 statistics(walltime,[W2,_]), WT is W2-W1,
1696 (Res=time_out -> accumulate_infos(wd_inv_proof,[timeout-1,walltime-WT]), % discharged and total are unknown
1697 add_error(cli_wd_check,'TIME-OUT in WD Invariant Proving (use -global_time_out X to increase it)')
1698 ;
1699 (TotPOsNr>0 -> Perc is (UnchangedNr+ProvenNr)*100/ TotPOsNr ; Perc = 100.0),
1700 format('Proof summary for ~w Invariant POs (~2f % discharged): ~w unchanged, ~w proven, ~w unproven~n',
1701 [TotPOsNr,Perc,UnchangedNr,ProvenNr,UnProvenNr]),
1702 WDInfos = [proven-ProvenNr,timeout-0,total-TotPOsNr,unchanged-UnchangedNr,unproven-UnProvenNr,walltime-WT],
1703 accumulate_infos(wd_inv_proof,WDInfos)
1704 ).
1705
1706
1707 :- use_module(bmachine_static_checks,[extended_static_check_machine/1]).
1708 :- use_module(visbsrc(visb_visualiser),[extended_static_check_default_visb_file/0]).
1709 % perform some additional static checks
1710 :- public cli_lint/0. % for REPL
1711 cli_lint(Check) :-
1712 extended_static_check_machine(Check),
1713 (unavailable_extension(visb_extension,_) -> true
1714 ; Check=visb -> extended_static_check_default_visb_file
1715 ; true).
1716 cli_lint :- cli_lint(_).
1717
1718
1719 :- use_module(extrasrc(predicate_debugger),[tcltk_debug_properties/3]).
1720 :- use_module(state_space,[current_state_corresponds_to_setup_constants_b_machine/0]).
1721 :- public cli_check_properties/0. % for REPL
1722 cli_check_properties :- probcli_time_stamp(NOW),
1723 cli_check_properties(NOW).
1724 cli_check_properties(NOW) :-
1725 printsilent('% Checking PROPERTIES: '),nls,
1726 writeln_log_time(starting_check_properties(NOW)),
1727 ( current_state_corresponds_to_setup_constants_b_machine ->
1728 set_analyse_hook('_P'),
1729 predicate_evaluator:tcltk_analyse_properties(_PROPRES,PROPInfos),
1730 unset_analyse_hook,
1731 printsilent(PROPInfos),nls, % ex: [total/33,true/29,false/0,unknown/4,timeout/4,runtime/49950]
1732 accumulate_infos(properties,PROPInfos),
1733 write_important_xml_element_to_log(check_properties,PROPInfos),
1734 (predicate_evaluator:check_summary_all_true(PROPInfos) -> true
1735 ; print_error('Not all PROPERTIES true'), error_occurred(check_properties))
1736 ;
1737 (tcltk_debug_properties(list(PROPRES),false,Satisfiable)
1738 -> printsilent(PROPRES),nls,
1739 printsilent(Satisfiable),nls
1740 ; error_occurred(debug_properties_failed))
1741 ),
1742 writeln_log_time(finished_check_properties(NOW,PROPInfos)),
1743 loaded_root_filename(RootName),
1744 formatsilent('% Finished checking PROPERTIES of ~w~n',[RootName]).
1745
1746 % TODO: provide argument so that we run it only if necessary; e.g., when ProB has not already found a solution
1747
1748 cli_core_properties(Algorithm) :-
1749 format('% Checking CONSISTENCY of PROPERTIES by finding UNSAT CORE (using ~w)~n',[Algorithm]),
1750 b_get_properties_from_machine(Properties),!,
1751 size_of_conjunction(Properties,NrOfConjuncts),
1752 statistics(walltime,[W1,_]),
1753 (find_core(Algorithm,Properties,Core,Result)
1754 -> statistics(walltime,[W2,_]), WTime is W2-W1,
1755 length(Core,Len),
1756 accumulate_infos(properties_core,[contradiction_found-1,core_length-Len,
1757 properties-NrOfConjuncts,walltime-WTime]),
1758 format('UNSAT CORE of length ~w found, PROPERTIES are inconsistent! (~w, ~w ms walltime using ~w)~n',[Len,Result,WTime,Algorithm]),
1759 translate:nested_print_bexpr_as_classicalb(Core),
1760 format('% END OF UNSAT CORE (~w conjuncts)~n',[Len])
1761 % TODO: raise setup_constants_fails and avoid trying to solve properties later
1762 ; statistics(walltime,[W2,_]), WTime is W2-W1,
1763 accumulate_infos(properties_core,[contradiction_found-0,core_length-0,
1764 properties-NrOfConjuncts,walltime-WTime]),
1765 format('No small UNSAT CORE found, PROPERTIES may be consistent (~w ms walltime).~n',[WTime])
1766 ).
1767
1768 :- use_module(extrasrc(unsat_cores),[quick_bup_core_up_to/4]).
1769 :- use_module(wdsrc(well_def_analyser),[find_inconsistent_axiom/3]).
1770 find_core(wd_prover,_,Core,Result) :-
1771 find_inconsistent_axiom([],Axiom,NecHyps),
1772 Core = [Axiom|NecHyps], Result = contradiction_found.
1773 find_core(z3_bup(MaxSize),Properties,Core,Result) :-
1774 (var(MaxSize) -> MaxSize=2 ; true),
1775 quick_bup_core_up_to(Properties,MaxSize,Core,Result).
1776
1777
1778 % -----------------------
1779
1780 :- public cli_check_assertions/2. % for REPL
1781 cli_check_assertions(ALL,RI) :-
1782 probcli_time_stamp(NOW),
1783 cli_check_assertions(ALL,RI,NOW).
1784 cli_check_assertions(ALL,ReqInfos,NOW) :-
1785 printsilent('% Checking ASSERTIONS: '),nls,
1786 writeln_log_time(starting_check_assertions(NOW)),
1787 set_analyse_hook('_A'), % for dot output, in case users wants to generate dot files for assertions
1788 ? predicate_evaluator:tcltk_analyse_assertions(ALL,_ASSRES,Infos), % also checks CSP assertions
1789 unset_analyse_hook,
1790 printsilent(Infos),nls,
1791 ? accumulate_infos(assertions,Infos),
1792 write_important_xml_element_to_log(check_assertions,Infos),
1793 check_required_infos(ReqInfos,Infos,check_assertions),
1794 writeln_log_time(finished_check_assertions(NOW,Infos)),
1795 loaded_root_filename(RootName),
1796 formatsilent('% Finished checking ASSERTIONS of ~w~n',[RootName]),!.
1797 cli_check_assertions(ALL,ReqInfos,NOW) :-
1798 add_internal_error('Analyse ASSERTIONS unexpectedly failed',cli_check_assertions(ALL,ReqInfos,NOW)),
1799 error_occurred(internal_error).
1800 cli_set_goal(GOAL) :-
1801 debug_println(20,set_goal(GOAL)), %print(set_goal(GOAL)), nl,
1802 (bmachine:b_set_machine_goal(GOAL) -> true
1803 ; add_error(scope,'Setting GOAL predicate failed:',GOAL)).
1804 cli_add_additional_property(PROP) :-
1805 debug_println(20,add_additional_property(PROP)),
1806 (bmachine:add_additional_property(PROP,'command line -property') -> true
1807 ; add_error(scope,'Adding additional predicate to PROPERTIES failed:',PROP)).
1808 cli_set_searchscope(GOAL) :-
1809 debug_println(20,set_searchscope(GOAL)),
1810 format('Setting SCOPE for verification: ~w~n (Only states satisfying this predicate will be examined)~n',[GOAL]),
1811 (b_or_z_mode, bmachine:b_set_machine_searchscope(GOAL) -> true
1812 ; (xtl_mode, xtl_interface:xtl_set_search_scope(GOAL) -> true
1813 ; add_error(scope,'Setting model checking search SCOPE failed:',GOAL))
1814 ).
1815 cli_check_goal :- \+ b_get_machine_goal(_),!,
1816 add_error(cli_check_goal,'No GOAL DEFINITION found'),
1817 error_occurred(cli_check_goal).
1818 cli_check_goal :-
1819 printsilent('% Checking GOAL predicate: '),nls,
1820 tcltk_analyse_goal(_List,Summary),
1821 debug_println(20,Summary),
1822 accumulate_infos(check_goal,Summary),
1823 write_important_xml_element_to_log(check_goal,Summary),
1824 check_required_infos([false/0,unknown/0],Summary,check_goal).
1825 :- public cli_mc/2. % for REPL
1826 cli_mc(Nr,Opts) :- probcli_time_stamp(NOW), cli_start_model_check(Nr,NOW,Opts).
1827 cli_start_model_check(Nr,NOW,Options) :-
1828 (member(reset_state_space,Options)
1829 -> formatsilent('Resetting state space for benchmarking model checking (limit:~w, options:~w)~n',[Nr, Options]),
1830 announce_event(reset_specification) % for benchmarking purposes
1831 %,state_space:portray_state_space,nl
1832 ; true),
1833 start_xml_feature(model_check,max_states,Nr,FINFO),
1834 regular_safety_model_check_now(Nr,Time,WallTime,MCRes,NOW),
1835 %nl,
1836 stop_xml_feature(model_check,FINFO),
1837 get_state_space_stats(TS,TT,PT,IgnT),
1838 statistics_memory_used(Mem),
1839 (MCRes=time_out -> TInfos=[timeout/1] ; TInfos=[]),
1840 ? accumulate_infos(model_check,[runtime-Time,walltime-WallTime, % mc only runtime, and total wall time
1841 processed_states/PT,total_states/TS,total_transitions/TT,
1842 ignored_states/IgnT, memory_used/Mem|TInfos]), %for bench_csv output
1843 writeln_log_time(model_check(NOW,Nr,Time,WallTime,MCRes)),
1844 (select(repeat(RepNr),Options,RestOptions)
1845 -> (RepNr>1
1846 -> N1 is RepNr-1,
1847 cli_start_model_check(Nr,NOW,[repeat(N1)|RestOptions])
1848 ; merge_accumulated_infos(model_check)
1849 )
1850 ; true
1851 ).
1852
1853 cli_start_mc_with_tlc :-
1854 (animation_mode(b), \+ animation_minor_mode(eventb) -> true
1855 ; error_manager: add_error_and_fail(mc_with_tlc,'TLC4B tool can be used only for classical B models.')),
1856 % TO DO: use b_write_eventb_machine_to_classicalb_to_file to do conversion
1857 catch(
1858 safe_absolute_file_name(prob_lib('TLC4B.jar'),TLC4BTool),
1859 error(E,_),
1860 error_manager:add_error_fail(get_tlc_command,'Could not find TLC4B.jar file.',E)),
1861 start_xml_feature(model_check_with_tlc,tlc4bjar,TLC4BTool,FINFO),
1862 construct_and_execute_tlc_command(TLC4BTool),
1863 stop_xml_feature(model_check_with_tlc,FINFO).
1864
1865 :- use_module(system_call,[system_call/4]).
1866 construct_and_execute_tlc_command(TLC4BTool) :-
1867 parsercall: get_java_command_path(JavaCmd),
1868 loaded_main_file(File),
1869 % determine extra arguments:
1870 (get_preference(tlc_number_of_workers,TLCWorkers), TLCWorkers>1
1871 -> number_codes(TLCWorkers,CC), atom_codes(TLAWA,CC), WW = ['-workers',TLAWA]
1872 ; WW=[]),
1873 (option(no_assertion_violations) -> WA = ['-noass'] ; WA=[]),
1874 (option(no_deadlocks) -> WD = ['-nodead'] ; WD=[]),
1875 (option(no_invariant_violations) -> WI = ['-noinv'] ; WI=[]),
1876 (option(no_goal) -> WG = ['-nogoal'] ; WG=[]),
1877 (option(no_ltl) -> WL = ['-noltl'] ; WL=[]),
1878 (option_verbose -> WV = ['-verbose'] ; WV=[]),
1879 (option(silent) -> WS = ['-silent'] ; WS=[]),
1880 (option(logtlc(Log)) -> WLG = ['-log',Log] ; WLG=[]),
1881 (get_preference(tlc_use_prob_constant_setup,true),
1882 tcltk_get_constants_predicate(DNF_Pred)
1883 -> WCS = ['-constantssetup', DNF_Pred]
1884 ; WCS=[]),
1885 append([WW,WA,WD,WI,WG,WL,WCS,WV,WS,WLG,[File]],TLCArgs),
1886 debug_println(19,tlc_args(TLCArgs)),
1887 statistics(walltime,[W1,_]),
1888 % we could call get_jvm_options: '-Xss5m' is useful e.g. for Generated1000.mch
1889 system_call(JavaCmd, ['-Xss5m', '-jar', TLC4BTool | TLCArgs], Text,JExit),
1890 statistics(walltime,[W2,_]),
1891 WTime is W2-W1,
1892 formatsilent('exit : ~w walltime: ~w ms~n',[JExit,WTime]),
1893 (JExit=exit(0)
1894 -> accumulate_infos(mc_with_tlc,[walltime-WTime,model_check_ok-1])
1895 ; accumulate_infos(mc_with_tlc,[walltime-WTime,model_check_error-1]),
1896 add_error(construct_and_execute_tlc_command,'Error while model checking with TLC: ',TLC4BTool/File),
1897 atom_codes(T,Text),
1898 add_error_fail(construct_and_execute_tlc_command,'Std error: ',T)
1899 ).
1900
1901 % SymbolicOrSequential = symbolic or sequential
1902 cli_start_sym_mc_with_lts(SymbolicOrSequential) :-
1903 (option(no_deadlocks) -> NoDead = true ; NoDead = false),
1904 (option(no_invariant_violations) -> NoInv = true ; NoInv = false), % does LTSMin support goal checking
1905 findall(Option,option(ltsmin_option(Option)),MoreFlags1),
1906 findall(ltl_formula(LTLF),option(ltl_formula_model_check(LTLF,_)),MoreFlags2),
1907 append(MoreFlags1,MoreFlags2,MoreFlags),
1908 (NoDead = false, NoInv = false ->
1909 print_error('ERROR: cannot start LTSmin with both deadlock and invariant checking'),
1910 print_error(' use either the -noinv or -nodead flag'),
1911 flush_output(user_error)
1912 ; true),
1913 formatsilent('starting prob2lts-sym/seq (flags nodead=~w, noinv=~w, moreflags=~w)~n',[NoDead,NoInv,MoreFlags]),
1914 statistics(walltime,[W1,_]),
1915 start_ltsmin(SymbolicOrSequential, [NoDead, NoInv], MoreFlags,Result),
1916 process_ltsmin_result(Result,AccInfos),
1917 statistics(walltime,[W2,_]), WT is W2-W1,
1918 accumulate_infos(mc_with_lts_min(SymbolicOrSequential),[walltime-WT|AccInfos]).
1919 % TO DO: start lts-sym + start start_ltsmin_srv('/tmp/ltsmin.probz', NOW) + print output
1920
1921 :- use_module(extension('ltsmin/ltsmin_trace'),[csv_to_trace/3]).
1922 process_ltsmin_result(ltsmin_model_checking_ok,[model_check_ok-1]) :-
1923 print_green('LTSMin found no counter example\n').
1924 process_ltsmin_result(ltsmin_model_checking_aborted,[model_check_aborted-1]) :-
1925 add_warning(ltsmin_model_checking_aborted,'LTSMin was aborted (e.g., by CTRL-C)').
1926 process_ltsmin_result(ltsmin_counter_example_found(CsvFile),[model_check_counter_example-1]) :-
1927 add_error(ltsmin_counter_example_found,'LTSMin found a counter example, written to:',CsvFile),
1928 (option(silent) -> true
1929 ; csv_to_trace(CsvFile,_States,Transitions) ->
1930 print('*** TRACE: '),nl,print_list(Transitions) % ,print(_States),nl
1931 ; add_error(ltsmin,'Could not extract trace information from LTSmin file: ',CsvFile)
1932 ).
1933
1934 :- use_module(symbolic_model_checker(ic3), [ic3_symbolic_model_check/1]).
1935 :- use_module(symbolic_model_checker(ctigar), [ctigar_symbolic_model_check/1]).
1936 :- use_module(symbolic_model_checker(kinduction), [kinduction_symbolic_model_check/1,
1937 tinduction_symbolic_model_check/1]).
1938 :- use_module(symbolic_model_checker(bmc), [bmc_symbolic_model_check/1]).
1939 cli_symbolic_model_check(Algorithm) :-
1940 debug_format(20,'% Starting Symbolic Model Check. Using ~w Algorithm', [Algorithm]),
1941 start_xml_feature(model_check,algorithm,Algorithm,FINFO),
1942 (animation_mode(b)
1943 -> true
1944 ; error_manager:add_error_and_fail(cli_symbolic_model_check,'Symbolic Model Checking is currently only available for B and Event-B.')),
1945 perform_symbolic_model_checking(Algorithm,Result),
1946 handle_symbolic_model_check_result(Result),
1947 stop_xml_feature(model_check,FINFO).
1948
1949 perform_symbolic_model_checking(ic3,Result) :- !, ic3_symbolic_model_check(Result).
1950 perform_symbolic_model_checking(ctigar,Result) :- !, ctigar_symbolic_model_check(Result).
1951 perform_symbolic_model_checking(kinduction,Result) :- !, kinduction_symbolic_model_check(Result).
1952 perform_symbolic_model_checking(tinduction,Result) :- !, tinduction_symbolic_model_check(Result).
1953 perform_symbolic_model_checking(bmc,Result) :- !, bmc_symbolic_model_check(Result).
1954 perform_symbolic_model_checking(Alg,_) :- add_error_fail(cli_symbolic_model_check,'Invalid symbolic model checking algorithm: ',Alg).
1955
1956 handle_symbolic_model_check_result(counterexample_found) :- !, error_occurred(invariant_violation).
1957 handle_symbolic_model_check_result(property_holds) :- !,
1958 format('Model checking complete, invariant holds~n',[]).
1959 handle_symbolic_model_check_result(solver_and_provers_too_weak) :- !,
1960 format('Model checking incomplete because a constraint could not be solved in time~n',[]),
1961 error_occurred(model_check_incomplete).
1962 handle_symbolic_model_check_result(limit_reached) :- !,
1963 format('Model checking incomplete because an iteration limit was reached~n',[]),
1964 error_occurred(model_check_incomplete).
1965
1966 zmq_start_master(invariant,Identifier) :-
1967 start_animation_without_computing,
1968 zmq_get_initialisation_term(InitTerm),
1969 (option(strict_raise_error) -> Strict = 1 ; Strict = 0),
1970 get_preference(port, PortStart),
1971 get_preference(max_states, Max),
1972 get_preference(ip, IP),
1973 get_preference(logdir, LogDir),
1974 get_preference(tmpdir, TmpDir),
1975 get_preference(hash_cycle, HashCycle),
1976 atom_concat(LogDir, '/distb-', ATmp),
1977 atom_concat(ATmp, Identifier, Logfile),
1978 atom_concat(TmpDir, '/db-distb-', TTmp),
1979 atom_concat(TTmp, Identifier, TmpDir2),
1980 start_master(InitTerm,Max,PortStart,Strict,IP,Logfile,TmpDir2,HashCycle),
1981 halt.
1982 zmq_start_master(assertion,Identifier) :-
1983 get_preference(port, PortStart),
1984 get_preference(logdir, LogDir),
1985 get_preference(ip, IP),
1986 get_preference(tmpdir, TmpDir),
1987 get_preference(hash_cycle, HashCycle),
1988 atom_concat(LogDir, '/distb-', ATmp),
1989 atom_concat(ATmp, Identifier, Logfile),
1990 atom_concat(TmpDir, '/db-distb-', TTmp),
1991 atom_concat(TTmp, Identifier, TmpDir2),
1992 current_state_corresponds_to_setup_constants_b_machine,
1993 animation_mode(b),
1994 full_b_machine(Machine),
1995 b_get_assertions(_,static,SAss),
1996 b_get_assertions(_,dynamic,DAss),
1997 append(SAss,DAss,Ass),
1998 count_assertions(Ass,0,N),
1999 assertz(master:assertion_count(N)),
2000 current_expression(_,State1),
2001 specfile:state_corresponds_to_set_up_constants(State1,State),
2002 zmq_get_important_options(Options),
2003 (option(strict_raise_error) -> Strict = 1 ; Strict = 0),
2004 %start_master(assertions(classical_b(Machine,Options),State,Ass),2,-1,PortStart,0,Strict,IP,Logfile,TmpDir2),
2005 start_master(assertions(classical_b(Machine,Options),State,Ass),2,PortStart,Strict,IP,Logfile,TmpDir2,HashCycle),
2006 halt.
2007
2008 zmq_get_initialisation_term(Term) :-
2009 (animation_mode(b) ; animation_mode(csp_and_b)), % CSP file not yet added when ZMQ master starts working
2010 \+ animation_minor_mode(eventb),
2011 option(add_csp_guide(CspGuide)),
2012 !, % Classical B + CSP
2013 debug_println(20,'ZMQ: Transferring CSP || B model'),
2014 full_b_machine(Machine),
2015 % TO DO: extract CSP Term rather than file name: will not work for distribution on other file-systems
2016 zmq_get_important_options(Options),
2017 Term = classical_b_with_csp(Machine,CspGuide,Options).
2018 zmq_get_initialisation_term(Term) :-
2019 debug_println(20,'Generating ZMQ Worker Initialisation'),
2020 animation_mode(b), \+ animation_minor_mode(eventb), !, % Classical B
2021 debug_println(20,'ZMQ: Transferring Classical-B model'),
2022 full_b_machine(Machine),
2023 zmq_get_important_options(Options),
2024 Term = classical_b(Machine,Options).
2025 zmq_get_initialisation_term(Term) :-
2026 animation_mode(b), animation_minor_mode(eventb), !, % Event-B
2027 debug_println(20,'ZMQ: Transferring Event-B model'),
2028 full_b_machine(Machine),
2029 zmq_get_important_options(Options),
2030 Term = eventb(Machine,Options).
2031 zmq_get_initialisation_term(Term) :-
2032 animation_mode(cspm),
2033 loaded_main_file(MainCSPFile),!, % TO DO: pass CSP Prolog term rather than file name (for distribution)
2034 zmq_get_important_options(Options),
2035 debug_println(20,'ZMQ: Transferring CSP specification'),
2036 Term = csp_specification(MainCSPFile,Options).
2037 zmq_get_initialisation_term(_Term) :-
2038 \+ real_error_occurred, % otherwise error occured while loading
2039 animation_mode(Mode),
2040 add_internal_error('Unsupported formalism for ZMQ', Mode),
2041 fail.
2042
2043 zmq_get_initialisation_term(filename(FN)) :-
2044 loaded_main_file(FN).
2045
2046 % get important command-line options to be transmitted to probcli worker
2047 zmq_get_important_options(Options) :- findall(O, (option(O), zmq_important_option(O)), Options),
2048 debug_println(20,transferring_zmq_options_to_workers(Options)).
2049 zmq_important_option(coverage(_)).
2050 zmq_important_option(expect_error(_)).
2051 zmq_important_option(optional_error(_)).
2052 zmq_important_option(file_info).
2053 zmq_important_option(log(_)).
2054 zmq_important_option(print_version(_)).
2055 zmq_important_option(profiling_on).
2056 zmq_important_option(set_card(_,_)).
2057 zmq_important_option(set_pref(_,_)).
2058 zmq_important_option(set_preference_group(_,_)).
2059 zmq_important_option(statistics).
2060 zmq_important_option(csv_table_command(_,_,_,_)).
2061 zmq_important_option(verbose(_)).
2062 zmq_important_option(set_searchscope(_)).
2063 zmq_important_option(no_invariant_violations).
2064 %zmq_important_option(no_deadlocks).
2065 %zmq_important_option(no_goal).
2066 % we could consider also supporting: -argv, -cache, -prefs FILE csp_main(ProcessName) profiling_on prob_profile runtimechecking
2067
2068 % set options received by a zmq worker
2069 :- use_module(b_global_sets, [set_user_defined_scope/2]).
2070 :- use_module(tools_strings, [convert_cli_arg/2]).
2071 zmq_set_important_options(Options) :- debug_println(20,setting_zmq_options(Options)),
2072 maplist(prob_cli:zmq_set_option,Options).
2073 zmq_set_option(file_info) :- !, file_info.
2074 zmq_set_option(log(F)) :- !,
2075 generate_time_stamp(Datime,NOW),
2076 cli_start_logging(F,ascii,NOW,Datime,[zmq_worker]).
2077 zmq_set_option(print_version(V)) :- !, print_version(V).
2078 zmq_set_option(profiling_on) :- !, profiling_on.
2079 zmq_set_option(set_card(Set,V)) :- !,
2080 convert_cli_arg(V,Value),
2081 set_user_defined_scope(Set,Value).
2082 zmq_set_option(set_pref(P,V)) :- !, set_pref(P,V).
2083 zmq_set_option(set_preference_group(P,V)) :- !, set_preference_group(P,V).
2084 zmq_set_option(verbose(Nr)) :- !, verbose(Nr).
2085 zmq_set_option(O) :- zmq_delayed_option(O),!, assert_option(O). % DO IT LATER
2086 zmq_set_option(O) :- add_internal_error('Unsupported option for ZMQ worker: ',zmq_set_option(O)).
2087
2088 zmq_delayed_option(coverage(_)).
2089 zmq_delayed_option(expect_error(_)).
2090 zmq_delayed_option(expect_error_pos(_,_,_)).
2091 zmq_delayed_option(optional_error(_)).
2092 zmq_delayed_option(statistics).
2093 zmq_delayed_option(set_searchscope(_)).
2094 zmq_delayed_option(no_invariant_violations). % not supported yet
2095
2096 ltsmin_ltl_output(Filename, NOW) :-
2097 if_option_set(ltl_formula_model_check(Formula, _),true),
2098 ltsmin_generate_ltlfile(Formula, Filename),
2099 halt_prob(NOW,0). % if we additionally specify -ltsformula, we do not want to model check it
2100
2101
2102 start_ltsmin_srv(X, NOW) :-
2103 nls,println_silent('Starting LTSMin Server...'),
2104 if_option_set(ltl_formula_model_check(Formula, _),true),
2105 ltsmin_init(X, Zocket, Formula),
2106 ltsmin_loop(Zocket),
2107 ltsmin_teardown(Zocket, X),
2108 nls,println_silent('Stopped LTSMin Server.'),
2109 halt_prob(NOW,0). % if we additionally specify -ltsformula, we do not want to model check it
2110
2111 zmq_start_worker(Identifier, NOW) :-
2112 get_preference(port, Port),
2113 get_preference(logdir, LogDir),
2114 get_preference(tmpdir, TmpDir),
2115 get_preference(proxynumber, ProxyNumber),
2116 /* TODO: ensure directory exists (pk, 09.01.2018) */
2117 atom_concat(LogDir, '/worker-', ATmp),
2118 atom_concat(ATmp, Identifier, Logfile),
2119 % TODO: tmp dir currently not used
2120 atom_concat(TmpDir, '/db-worker-', TTmp),
2121 atom_concat(TTmp, Identifier, TmpDir2),
2122 start_worker(Port,ProxyNumber,Logfile,TmpDir2,zmq_worker_load_model),
2123 formatsilent('ZMQ worker finished (Port:~w)~n',[Port]),
2124 cli_process_loaded_file_afer_start_animation(NOW),
2125 println_silent('Exiting probcli worker'),
2126 halt_prob(NOW,0).
2127
2128 zmq_start_animation :-
2129 prob2_interface:start_animation,
2130 if_option_set(set_goal(GOAL),
2131 cli_set_goal(GOAL)), % not used yet
2132 if_option_set(set_searchscope(SCOPE),
2133 cli_set_searchscope(SCOPE)),
2134 cli_computeOperations(_).
2135 zmq_worker_load_model(classical_b(Machine,Options)) :- !,
2136 debug_println(20,'ZMQ WORKER: Loading classical B model'),
2137 zmq_set_important_options(Options),
2138 bmachine:b_machine_reset, bmachine:assert_main_machine(Machine),
2139 set_animation_mode(b),
2140 zmq_start_animation.
2141 zmq_worker_load_model(classical_b_with_csp(Machine,CspGuide,Options)) :- !,
2142 debug_println(20,'ZMQ WORKER: Loading CSP || B model'),
2143 zmq_set_important_options(Options),
2144 bmachine:b_machine_reset, bmachine:assert_main_machine(Machine),
2145 set_animation_mode(b),
2146 prob2_interface:start_animation,
2147 tcltk_add_csp_file(CspGuide), % TO DO: use CSP Prolog term rather than filename <----------------
2148 zmq_start_animation.
2149 zmq_worker_load_model(eventb(Machine,Options)) :- !,
2150 print(loading_eventb(Options)),nl,
2151 zmq_set_important_options(Options),
2152 bmachine:b_machine_reset, bmachine:assert_main_machine(Machine),
2153 set_animation_mode(b), set_animation_minor_mode(eventb),
2154 zmq_start_animation.
2155 zmq_worker_load_model(csp_specification(CSPFile,Options)) :-
2156 zmq_set_important_options(Options),
2157 load_cspm_spec_from_cspm_file(CSPFile), % TO DO: pass CSP Prolog term rather than filename
2158 zmq_start_animation.
2159 zmq_worker_load_model(filename(FN)) :- !,
2160 printsilent('loading file by filename\n'),flush_output,
2161 ( is_eventb_b(FN) ->
2162 eclipse_interface:load_eventb_file(FN)
2163 ;
2164 bmachine:b_load_machine_probfile(FN)),
2165 zmq_start_animation.
2166 zmq_worker_load_model(assertions(Machine,State,Assertions)) :- !,
2167 assertz(assertion_counter(-1)),
2168 println_silent(loaded_model_for_assertion_checking),
2169 zmq_worker_load_model(Machine),
2170 assertz(worker:assertion_state(State)),
2171 make_assertionwps(Assertions).
2172 % assert current state
2173 zmq_worker_load_model(Other) :-
2174 add_internal_error('ZMQ worker: Unexpected machine description', zmq_worker_load_model(Other)),
2175 fail.
2176
2177
2178 :-dynamic assertion_counter/1.
2179
2180 count_assertions([],A,A).
2181 count_assertions([H|T],A,R) :- size_of_conjunction(H,N1),
2182 NN is A + N1,
2183 count_assertions(T,NN,R).
2184
2185 make_assertionwps([]).
2186 make_assertionwps([H|T]) :- conjunction_to_list(H,HL),
2187 sort_assertions(HL,SL),
2188 append_assertion(SL),
2189 make_assertionwps(T).
2190
2191 append_assertion([]).
2192 append_assertion([H|T]) :- assertion_counter(N),
2193 retractall(assertion_counter(_)),
2194 N1 is N + 1,
2195 assertz(assertion_counter(N1)),
2196 assertz(worker:assertion_task(N1,H)),
2197 append_assertion(T).
2198
2199 %assertions_order(A,B) :- term_size(A,NA),term_size(B,NB), NA > NB.
2200 sort_assertions(X,X).
2201 % :- samsort(assertions_order,X,Y).
2202
2203
2204
2205 is_eventb_b(FN) :- append(_,FN,".eventb").
2206 % load_model(Initialisation)
2207
2208
2209 :- use_module(predicate_evaluator).
2210 :- use_module(bmachine,[b_machine_name/1]).
2211 set_analyse_hook(AddPrefix) :- % set a hook to write false/unknown expressions into a dot file
2212 reset_dot_file_number,
2213 if_options_set(dot_analyse_output_prefix(_Path),
2214 (set_dot_file_prefix_if_option_set(AddPrefix),
2215 register_conjunct_error_hook(prob_cli:pred_eval_hook))).
2216 unset_analyse_hook :- predicate_evaluator:reset_conjunct_error_hook.
2217
2218 :- use_module(tools,[get_modulename_filename/2]).
2219 loaded_root_filename(RootName) :- loaded_main_file(MainFile),
2220 get_modulename_filename(MainFile,RootName).
2221
2222 set_dot_file_prefix_if_option_set(AddPrefix) :-
2223 if_options_set(dot_analyse_output_prefix(Path),
2224 (loaded_root_filename(RootName),
2225 % we could also use b_machine_hierarchy:main_machine_name(RootName)
2226 string_concatenate(Path,RootName,P1),
2227 string_concatenate(P1,AddPrefix,FullPath),
2228 set_dot_file_prefix(FullPath),
2229 debug_println(9,dot_file_prefix(FullPath)))).
2230
2231 % Status: true, false, unknown
2232 :- public pred_eval_hook/5.
2233 pred_eval_hook(_Conjunct,true,_EnumWarning,_IsExpanded, _CS) :-
2234 \+ option(dot_generate_for_all_formulas),!. % don't generate .dot for true formulas, unless explicitly requested
2235 pred_eval_hook(Conjunct,Status,_EnumWarning,_IsExpanded, CS) :-
2236 printsilent('Generating dotfile for: '),printsilent(CS),nls,
2237 (write_dot_graph_to_new_file(Status,Conjunct) -> true
2238 ; add_error(dot_output,'Writing dot to file failed: ',CS)).
2239
2240
2241 :- dynamic dot_file_prefix/1.
2242 :- dynamic dot_file_number/1.
2243
2244 dot_file_prefix('~/Desktop/dot').
2245 set_dot_file_prefix(F) :- retractall(dot_file_prefix(_)), assertz(dot_file_prefix(F)).
2246 dot_file_number(0).
2247 reset_dot_file_number :- retractall(dot_file_number(_)), assertz(dot_file_number(0)).
2248 get_next_nr(GNr) :- retract(dot_file_number(Nr)), N1 is Nr+1,
2249 assertz(dot_file_number(N1)), GNr = Nr.
2250 write_dot_graph_to_new_file(Status,BExpr) :-
2251 dot_file_prefix(Dir),get_next_nr(Nr),
2252 string_concatenate('_',Status,Str1),
2253 string_concatenate(Nr,Str1,NS),
2254 string_concatenate(Dir,NS,F1),
2255 atom_concat(F1,'.dot',FileName),
2256 tcltk_interface:write_dot_file_for_pred_expr(BExpr,FileName).
2257
2258 % get dot file name if dot_output has been set
2259 get_dot_file(Type,FileName) :- option(dot_analyse_output_prefix(_)),
2260 set_dot_file_prefix_if_option_set(Type),
2261 dot_file_prefix(Dir),
2262 string_concatenate('_',Type,Str1),
2263 string_concatenate(Dir,Str1,F1),
2264 atom_concat(F1,'.dot',FileName).
2265
2266 :- use_module(extrasrc(refinement_checker),
2267 [tcltk_refinement_search/3, tcltk_load_refine_spec_file/1, tcltk_save_specification_state_for_refinement/1]).
2268 cli_csp_in_situ_refinement_check(P,Type,Q,NOW) :-
2269 debug_println(20,'% Starting CSP Refinement Check'),
2270 loaded_main_file(CSPFile),
2271 ajoin_with_sep(['assert',P,Type,Q], ' ',Assertion),
2272 start_xml_feature(csp_refinement_check,assertion,Assertion,FINFO),
2273 ( timeout_call(tcltk_interface:tcltk_check_csp_assertion(Assertion,CSPFile,'False',_PlTerm,RefTrace),NOW,'cspref')
2274 -> check_ref_result(RefTrace)
2275 ; true),
2276 stop_xml_feature(csp_refinement_check,FINFO).
2277 cli_start_refinement_check(RefFile,FailuresModel,RefNrNodes,NOW) :-
2278 start_xml_feature(refinement_check,file,RefFile,FINFO),
2279 tcltk_load_refine_spec_file(RefFile),
2280 ( timeout_call(tcltk_refinement_search(RefTrace,FailuresModel,RefNrNodes),NOW,refinement_check)
2281 -> check_ref_result(RefTrace)
2282 ; true),
2283 stop_xml_feature(refinement_check,FINFO).
2284 check_ref_result(RefTrace) :-
2285 ( RefTrace==no_counter_example ->
2286 print('==> Refinement Check Successful'),nl
2287 ; RefTrace==no_counter_example_found ->
2288 print('==> Refinement Check did not find Counter-Example but is incomplete'),nl,
2289 error_occurred(refinement_check_incomplete)
2290 ;
2291 print('*** Refinement Check Counter-Example: ***'),nl, print(RefTrace),nl,
2292 print('*** Refinement Check Failed ***'),nl,
2293 error_occurred(refinement_check_fails)).
2294 cli_checkAssertion(Proc,Model,AssertionType,_NOW) :-
2295 loaded_main_file(CSPFile),
2296 ajoin(['assert ',Proc,' :[ ',AssertionType,'[',Model,']',' ]'],Assertion),
2297 start_xml_feature(csp_deadlock_check,assertion,Assertion,FINFO),
2298 ( /*timeout_call(*/tcltk_interface:tcltk_check_csp_assertion(Assertion,CSPFile,'False',_PlTerm,ResTrace)/*,NOW,a)*/
2299 -> check_model_result(Assertion,ResTrace)
2300 ; true),
2301 stop_xml_feature(csp_deadlock_check,FINFO).
2302 cli_check_csp_assertion(Assertion,NOW) :-
2303 start_xml_feature(csp_assertion_check,assertion,Assertion,FINFO),
2304 loaded_main_file(CSPFile),
2305 ajoin(['assert ',Assertion],AssertionFull),
2306 ( timeout_call(tcltk_interface:tcltk_check_csp_assertion(AssertionFull,CSPFile,_Negated,PlTerm,ResTrace),NOW,csp_assertion_check)
2307 -> check_model_result(PlTerm,ResTrace)
2308 ; true),
2309 stop_xml_feature(csp_assertion_check,FINFO).
2310
2311
2312
2313 check_model_result(AssertionPlTerm,ResTrace) :-
2314 ( ResTrace==no_counter_example ->
2315 printsilent('==> Model Check Successful'),nls
2316 ;
2317 (functor(AssertionPlTerm,assertRef,_Arity) ->
2318 print('*** Refinement Check Counter-Example: ***'),nl, print(ResTrace),nl,
2319 print('*** Refinement Check Failed ***'),nl,
2320 error_occurred(refinement_check_fails)
2321 ;
2322 print('*** Model Check Counterexample: ***'),nl,print(ResTrace),nl,
2323 print('*** Model Check Failed ***'),nl,
2324 error_occurred(model_check_fails))
2325 ).
2326 :- use_module(probcspsrc(haskell_csp),[get_csp_assertions_as_string/2,
2327 parse_and_load_cspm_file_into_specific_pl_file/2,
2328 evaluate_csp_expression/2, evaluate_csp_expression/3]).
2329 cli_csp_get_assertions :-
2330 loaded_main_file(CSPFile),
2331 get_csp_assertions_as_string(CSPFile,String),
2332 print('*** Assertions in File (separated by $) ***'),nl,print(String),nl.
2333 cli_eval_csp_expression(E) :-
2334 (loaded_main_file(CSPFile) ->
2335 evaluate_csp_expression(E, CSPFile, Res)
2336 ; evaluate_csp_expression(E,Res)
2337 ), print('Evaluated Expression: '),nl,print(Res),nl.
2338 cli_csp_translate_to_file(PlFile) :-
2339 loaded_main_file(CSPFile),
2340 parse_and_load_cspm_file_into_specific_pl_file(CSPFile,PlFile).
2341 :- use_module(probltlsrc(ltl_fairness),[check_scc_ce/2]).
2342 cli_check_scc_for_ltl_formula(LtlFormula,SCC) :-
2343 check_scc_ce(LtlFormula,SCC).
2344
2345 :- use_module(extrasrc(coverage_statistics),[pretty_print_coverage_information_to_file/1]).
2346 cli_get_coverage_information(FileName) :-
2347 pretty_print_coverage_information_to_file(FileName).
2348 cli_vacuity_check :-
2349 eclipse_interface:get_vacuous_invariants(L),
2350 (L=[] -> print('No vacuous invariants'),nl
2351 ; maplist(prob_cli:add_vacuous_invariant,L)).
2352 add_vacuous_invariant(Inv) :-
2353 translate:translate_bexpression(Inv,TI),
2354 add_error(vacuity_check,'Vacuous invariant: ',TI).
2355 cli_start_socketserver(Port,Loopback) :-
2356 printsilent('Starting Socket Server'),nls,
2357 safe_absolute_file_name(prob_home('.'),AppDir),
2358 printsilent('Application Path: '),printsilent(AppDir),nls,
2359 disable_interaction_on_errors,
2360 ( start_prob_socketserver(Port,Loopback) -> true
2361 ;
2362 print('Starting socket server failed, Port: '), print(Port),nl),
2363 printsilent('Finished Socket Server'),nls.
2364 :- use_module(tools_platform, [platform_is_64_bit/0]).
2365 cli_check_statespace_hash(Expected,Kind) :-
2366 printsilent('Computing hash of entire statespace: '),
2367 compute_full_state_space_hash(Hash),
2368 printsilent(Hash),nls, % TO DO: maybe also compute hash for transitions and check that
2369 (Hash=Expected -> true
2370 ; Kind=='64bit', \+ platform_is_64_bit -> format('Hash does not match ~w (but was computed on 64-bit system)~n',[Expected])
2371 ; Kind=='32bit', platform_is_64_bit -> format('Hash does not match ~w (but was computed on 32-bit system)~n',[Expected])
2372 ; add_error(hash,'Expected Statespace Hash to be: ',Expected)).
2373 :- use_module(extrasrc(b_operation_cache),[get_op_cache_stats/1]).
2374 cli_check_op_cache(ReqInfos) :-
2375 get_op_cache_stats(Stats),
2376 (ReqInfos=[] -> format('Operation caching statistics: ~w~n',[Stats])
2377 ; formatsilent('Operation caching statistics: ~w~n',[Stats])),
2378 accumulate_infos(op_cache,Stats),
2379 check_required_infos(ReqInfos,Stats,op_cache_stats).
2380 cli_show_coverage(ShowEnabledInfo,NOW) :-
2381 cli_show_coverage(_Nodes,_Operations,ShowEnabledInfo,NOW).
2382 cli_show_coverage(Nodes,Operations,ShowEnabledInfo,NOW) :-
2383 ShowEnabledInfo == just_check_stats,!, % no printing of individual transition coverage
2384 get_state_space_stats(TotalNodeSum,TotalTransSum,_ProcessedTotal,_), % no computation overhead
2385 writeln_log(computed_coverage(NOW,TotalNodeSum,TotalTransSum)),
2386 check_totals(Nodes,Operations,TotalNodeSum,TotalTransSum).
2387 cli_show_coverage(Nodes,Operations,ShowEnabledInfo,NOW) :-
2388 ShowEnabledInfo == just_summary,
2389 !, % no printing of detailed transition coverage (avoid traversing state space)
2390 get_state_space_stats(TotalNodeSum,TotalTransSum,ProcessedTotal,Ignored), % no computation overhead
2391 writeln_log(computed_coverage(NOW,TotalNodeSum,TotalTransSum)),
2392 format('Coverage:~n States: ~w (~w processed, ~w ignored)~n Transitions: ~w~n',
2393 [TotalNodeSum,ProcessedTotal,Ignored,TotalTransSum]),
2394 show_initialisation_summary(NOW),
2395 show_operation_coverage_summary(NOW),
2396 (invariant_violated(ID) -> format('At least one state violates the invariant (~w) ~n',[ID]) ; true),
2397 check_totals(Nodes,Operations,TotalNodeSum,TotalTransSum).
2398 cli_show_coverage(Nodes,Operations,ShowEnabledInfo,NOW) :-
2399 print('Coverage:'),nl,
2400 compute_the_coverage(Res,TotalNodeSum,TotalTransSum,ShowEnabledInfo,false),
2401 writeln_log(computed_coverage(NOW,TotalNodeSum,TotalTransSum)),
2402 print(Res),nl,
2403 check_totals(Nodes,Operations,TotalNodeSum,TotalTransSum).
2404 check_totals(Nodes,Operations,TotalNodeSum,TotalTransSum) :-
2405 ( Nodes=TotalNodeSum -> true
2406 ;
2407 add_error(probcli,'Unexpected number of nodes: ',TotalNodeSum),
2408 add_error(probcli,'Expected: ',Nodes),error_occurred(coverage)),
2409 ( Operations=TotalTransSum -> true
2410 ;
2411 add_error(probcli,'Unexpected number of transitions: ',TotalTransSum),
2412 add_error(probcli,'Expected: ',Operations),error_occurred(coverage)).
2413
2414
2415 :- use_module(bmachine,[b_machine_statistics/2, b_get_main_filename/1, b_get_all_used_filenames/1,get_full_b_machine_sha_hash/1]).
2416 :- use_module(tools_strings,[get_hex_bytes/2]).
2417 cli_print_machine_info(statistics) :-
2418 b_machine_name(Name),
2419 %(b_get_main_filename(File) -> true ; File=unknown),
2420 format('Machine statistics for ~w:~n',[Name]),
2421 findall(Key/Nr,b_machine_statistics(Key,Nr),L),
2422 maplist(prob_cli:print_keynr,L),!.
2423 cli_print_machine_info(files(WithSha)) :-
2424 b_machine_name(Name),
2425 (WithSha = with_sha -> Msg2='and SHA1 ' ; Msg2=''),
2426 format('Files ~wused for machine ~w:~n',[Msg2,Name]),
2427 b_get_all_used_filenames(Files),
2428 maplist(prob_cli:print_individual_file(WithSha),Files),!.
2429 cli_print_machine_info(hash(Expected)) :-
2430 b_machine_name(MainName), % to do: findall machines and hashes
2431 get_full_b_machine_sha_hash(HashBytes),
2432 get_hex_bytes(HashBytes,Hash),
2433 format('SHA hash for machine ~w = ~s~n',[MainName,Hash]),!,
2434 write_xml_element_to_log(machine_hash,[hash/Hash]),
2435 (var(Expected) -> true
2436 ; atom_codes(Expected,Hash)
2437 -> format_with_colour_nl(user_output,[green],'Machine hash for ~w matches provided hash.',[MainName])
2438 ; add_error(machine_hash_check,'Unexpected machine hash, expected: ',Expected)).
2439 cli_print_machine_info(Kind) :- add_error(machine_stats,'Could not obtain machine information:',Kind).
2440 print_keynr(Key/Nr) :- format(' ~w : ~w~n',[Key,Nr]).
2441 :- use_module(extension('probhash/probhash'),[raw_sha_hash_file/3]).
2442 :- use_module(tools_strings,[get_hex_bytes/2]).
2443 print_individual_file(with_sha,File) :- Span = machine_info,
2444 raw_sha_hash_file(File,Term,Span),
2445 get_hex_bytes(Term,SHAHexCodes),
2446 format(' ~w, ~s~n',[File,SHAHexCodes]).
2447 print_individual_file(_,File) :- format(' ~w~n',[File]).
2448
2449 check_machine_file_sha(File,ExpectedHash) :- Span = check_machine_file_sha,
2450 get_full_machine_file_path(File,AbsFile),
2451 raw_sha_hash_file(AbsFile,Term,Span),
2452 get_hex_bytes(Term,SHAHexCodes), atom_codes(ExpectedHash,ExpectedShaCodes),
2453 (SHAHexCodes=ExpectedShaCodes
2454 -> format_with_colour_nl(user_output,[green],'Checked SHA1 hash for file ~w is ~s',[AbsFile,SHAHexCodes])
2455 ; add_error(check_machine_file_sha,'Unexpected SHA1 hash of file:',AbsFile),
2456 format_with_colour_nl(user_error,[orange],'! Expected: ~w~n! Actual : ~s',[ExpectedHash,SHAHexCodes])
2457 ).
2458
2459 :- use_module(bmachine,[get_machine_file_number/4, b_absolute_file_name_relative_to_main_machine/2]).
2460 :- use_module(probsrc(tools), [get_parent_directory/2]).
2461 get_full_machine_file_path(File,AbsFile) :-
2462 get_modulename_filename(File,Name),
2463 (get_filename_extension(File,ExtF), ExtF \= ''
2464 -> true ; debug_format(19,'No extension provided for file ~w~n',[File])),
2465 (get_machine_file_number(Name,ExtF,_Nr,AbsFile)
2466 -> get_parent_directory(File,Parent),
2467 (Parent='' -> true % no path provided
2468 ; File=AbsFile -> true % full path provided
2469 ; b_absolute_file_name_relative_to_main_machine(File,AbsFile) -> true % consistent partial path provided
2470 ; add_error(check_machine_file_sha,'File path (relative to main model) is inconsistent with used file:',File),
2471 b_absolute_file_name_relative_to_main_machine(File,AbsFile1),
2472 format_with_colour_nl(user_error,[orange],'! Full path in -check_machine_file_sha:~n ~w',[AbsFile1]),
2473 format_with_colour_nl(user_error,[orange],'! File actually used in B main model :~n ~w',[AbsFile])
2474 )
2475 ; get_machine_file_number(_,_,_,_) ->
2476 add_error(check_machine_file_sha,'Could not locate the file for:',File),
2477 b_absolute_file_name_relative_to_main_machine(File,AbsFile)
2478 ; add_message(check_machine_file_sha,'No main B machine loaded for, converting to absolute path: ',File),
2479 absolute_file_name(File,AbsFile)
2480 ).
2481
2482 :- use_module(tools,[get_tail_filename/2]).
2483 xml_log_machine_statistics :-
2484 animation_mode(Major),
2485 (animation_minor_mode(Minor) -> true ; Minor=none),
2486 write_xml_element_to_log(animation_mode,[major/Major,minor/Minor]),
2487 (b_or_z_mode, b_machine_name(Main)
2488 -> findall(Key/Nr,b_machine_statistics(Key,Nr),BMachStats),
2489 (b_get_main_filename(MainFile) -> get_tail_filename(MainFile,TailFile) ; TailFile = unknown),
2490 write_xml_element_to_log(b_machine_statistics,[machine_name/Main, tail_filename/TailFile|BMachStats])
2491 ; true).
2492
2493 cli_print_junit_results(ArgV) :-
2494 junit_mode(S),!,
2495 statistics(runtime,[E,_]),
2496 T is E - S,
2497 create_and_print_junit_result(['Integration Tests'],ArgV,T,pass).
2498 cli_print_junit_results(_).
2499
2500 :- use_module(visbsrc(visb_visualiser),[load_visb_file/1,
2501 tcltk_perform_visb_click_event/1, generate_visb_html_for_history/2]).
2502 cli_visb_history(JSONFile,HTMLFile,Options) :-
2503 (load_visb_file(JSONFile)
2504 -> ifm_option_set(visb_click(SVGID),tcltk_perform_visb_click_event(SVGID)), % simulate clicks if requested
2505 generate_visb_html_for_history(HTMLFile,Options)
2506 ; true). % errors already reported
2507
2508 cli_print_history(HistFile) :-
2509 findall( O, option(history_option(O)), Options),
2510 debug_println(9,writing_history_to_file(HistFile)),
2511 (select(trace_file,Options,ROpt) -> tcltk_save_history_as_trace_file(prolog,ROpt,HistFile) % save as Prolog trace file for replay with -t
2512 ; select(json,Options,ROpt) -> tcltk_save_history_as_trace_file(json,ROpt,HistFile) % save for replay with ProB2 UI
2513 ; write_history_to_file(HistFile,Options) -> true
2514 ; add_error(history,'Writing history to file failed: ',HistFile)).
2515
2516 cli_print_values(ValuesFilename) :-
2517 (write_values_to_file(ValuesFilename) -> true ; add_error(sptxt,'Writing values to file failed: ',ValuesFilename)).
2518 cli_print_all_values(ValuesDirname) :-
2519 (write_all_values_to_dir(ValuesDirname) -> true ; add_error(sstxt,'Writing all values to directory failed: ',ValuesDirname)).
2520
2521 :- use_module(probltlsrc(trace_generator),[generate_all_traces_until/4]).
2522
2523 cli_generate_all_traces_until(LTL_Stop_AsAtom,FilePrefix) :-
2524 generate_all_traces_until(LTL_Stop_AsAtom,FilePrefix,Result,NrTracesGenerated),
2525 format_with_colour_nl(user_error,[blue],'Generated ~w traces, result=~w~n',[NrTracesGenerated,Result]).
2526
2527 :- dynamic probcli_time_stamp/1.
2528 generate_time_stamp(NOW,TS) :- retractall(probcli_time_stamp(_)),
2529 now(NOW),
2530 current_prolog_flag(argv,ArgV),term_hash(ArgV,Hash),
2531 Rnd is Hash mod 1000,
2532 % random(0,1000,Rnd), always returns 216 % TO DO: try to get milliseconds from some library function
2533 TS is (NOW*1000)+Rnd,
2534 assertz(probcli_time_stamp(TS)).
2535 update_time_stamp(NOW1) :- retractall(probcli_time_stamp(_)),
2536 assertz(probcli_time_stamp(NOW1)).
2537
2538 %get_errors :- \+ real_error_occurred,!, (get_error(_Source,_Msg) -> print('*** Warnings occurred'),nl ; true), reset_errors.
2539 get_errors :-
2540 (get_preference(view_probcli_errors_using_bbresults,true)
2541 -> tools_commands:show_errors_with_bb_results([current]) ; true),
2542 get_error_sources.
2543
2544 get_error_sources :- get_error_with_span(ErrSource,Msg,Span), !,
2545 error_occurred_with_msg(ErrSource,Msg,Span),
2546 findall(1,get_error(ErrSource,_),L), length(L,Nr),
2547 (Nr>0 -> N1 is Nr+1, get_error_category_and_type(ErrSource,Cat,Type),
2548 (Type=error -> print_error('*** Occurences of this error: ')
2549 ; print_error('*** Occurences of this warning: ')),
2550 print_error(N1),
2551 write_xml_element_to_log(multiple_errors_occurred,[category/Cat,(type)/Type,number/N1])
2552 ; true),
2553 get_error_sources.
2554 get_error_sources.
2555
2556 :- use_module(state_space,[state_error/3, invariant_violated/1, time_out_for_invariant/1, time_out_for_assertions/1, time_out_for_node/3]).
2557 ?get_state_space_errors :- option(strict_raise_error),
2558 !,
2559 (\+ option(no_invariant_violations),invariant_violated(ID)
2560 -> (option_verbose ->
2561 format('Invariant violation in state with id = ~w~n',[ID]),
2562 b_interpreter:analyse_invariant_for_state(ID) % caused issue for test 1076
2563 ; format('Invariant violation in state with id = ~w (use -v to print more details)~n',[ID])
2564 ),
2565 error_occurred(invariant_violation)
2566 ; true),
2567 (state_error(_,_,abort_error(TYPE,Msg,_,Span)) -> error_occurred(TYPE,error,Span,Msg) ; true),
2568 get_state_errors(_).
2569 get_state_space_errors.
2570
2571 get_state_errors(ID) :- state_error(ID,_,X), X\=invariant_violated, X\=abort_error(_,_,_,_),
2572 create_state_error_description(X,Msg),error_occurred(Msg),fail.
2573 get_state_errors(ID) :- time_out_for_invariant(ID),error_occurred(time_out_for_invariant),fail.
2574 get_state_errors(ID) :- time_out_for_assertions(ID),error_occurred(time_out_for_assertions),fail.
2575 get_state_errors(ID) :- time_out_for_node(ID,_,time_out),error_occurred(time_out),fail.
2576 get_state_errors(ID) :-
2577 ? time_out_for_node(ID,_,virtual_time_out(_)), %print(virtual_time_out_for_node(ID)),nl,
2578 error_occurred(virtual_time_out),fail.
2579 get_state_errors(_).
2580
2581
2582 create_state_error_description(eventerror(Event,Error,_),Description) :- !,
2583 functor(Error,Functor,_),
2584 ajoin(['event_error:',Event,':',Functor],Description).
2585 create_state_error_description(StateError,Description) :-
2586 functor(StateError,Functor,_),
2587 atom_concat('state_error:',Functor,Description).
2588
2589 % require a real machine to be loaded
2590 check_loaded_not_empty(Action) :-
2591 file_loaded(true,'$$empty_machine'),!,
2592 add_error(probcli,'No file specified; cannot perform command: ',Action),
2593 error_occurred(loading),fail.
2594 check_loaded_not_empty(Action) :- check_loaded(Action).
2595
2596 check_loaded(Action) :-
2597 ( file_loaded(true) -> true
2598 ; file_loaded(error) -> fail /* we have already generated error message */
2599 ;
2600 add_error(probcli,'No file specified; cannot perform action: ',Action),
2601 error_occurred(loading),fail).
2602
2603 :- dynamic loaded_main_file/2.
2604 loaded_main_file(File) :- loaded_main_file(_Ext,File).
2605
2606 :- use_module(tools,[get_filename_extension/2]).
2607 load_main_file(MainFile,NOW,Already_FullyProcessed) :- retractall(loaded_main_file(_,_)),
2608 debug_print(20,'% Loading: '), debug_println(20,MainFile),
2609 writeln_log_time(loading(NOW,MainFile)),
2610 get_filename_extension(MainFile,Ext),
2611 debug_println(6,file_extension(Ext)),
2612 file_extension_can_be_loaded(Ext,MainFile),
2613 start_probcli_timer(Timer),
2614 load_spec_file(Ext,MainFile,Already_FullyProcessed),
2615 stop_probcli_debug_timer(Timer,'% Finished loading'),
2616 (Already_FullyProcessed==true -> true
2617 ; assertz(loaded_main_file(Ext,MainFile))).
2618
2619 known_spec_file_extension('P',xtl).
2620 known_spec_file_extension(als,alloy).
2621 known_spec_file_extension(csp,csp).
2622 known_spec_file_extension(cspm,csp).
2623 known_spec_file_extension(def,b).
2624 known_spec_file_extension(eval,b_eval).
2625 known_spec_file_extension(eventb,eventb).
2626 known_spec_file_extension(fuzz,z).
2627 known_spec_file_extension(imp,b).
2628 known_spec_file_extension(mch,b).
2629 known_spec_file_extension(pb,b).
2630 known_spec_file_extension(pl,xtl). % disprover PO files
2631 known_spec_file_extension(pla,alloy). % Prolog AST of Alloy translation
2632 known_spec_file_extension(prob,b).
2633 known_spec_file_extension(ref,b).
2634 known_spec_file_extension(rmch,b_rules).
2635 known_spec_file_extension(smt,smt).
2636 known_spec_file_extension(smt2,smt).
2637 known_spec_file_extension(sys,b).
2638 known_spec_file_extension(tex,z).
2639 known_spec_file_extension(tla,tla).
2640 known_spec_file_extension(zed,z).
2641
2642 :- use_module(pathes_extensions_db, [load_spec_file_requires_extension/2]).
2643 :- use_module(pathes_lib, [available_extension/1, unavailable_extension/2]).
2644 % check if we can load the file extension given available ProB extensions
2645 file_extension_can_be_loaded(FileExt,_) :- known_spec_file_extension(FileExt,Mode),
2646 load_spec_file_requires_extension(Mode,ProBExtension),
2647 unavailable_extension(ProBExtension,Reason),!,
2648 ajoin(['File with ending .', FileExt,' cannot be loaded because extension not available (',Reason,'):'],Msg),
2649 add_error(probcli,Msg,ProBExtension),
2650 fail.
2651 file_extension_can_be_loaded(_,_). % assume ok; if unrecognized we will load as B machine
2652
2653 %load_spec_file('pl',MainFile) :- !, load_cspm_spec_from_pl_file(MainFile). % no longer needed ?
2654 load_spec_file('pl',MainFile) :- !, load_xtl_spec_from_prolog_file(MainFile).
2655 load_spec_file('csp',MainFile) :- !, load_cspm_spec_from_cspm_file(MainFile).
2656 load_spec_file('cspm',MainFile) :- !, load_cspm_spec_from_cspm_file(MainFile).
2657 load_spec_file('P',MainFile) :- !, load_xtl_spec_from_prolog_file(MainFile).
2658 load_spec_file('p',MainFile) :- !, load_xtl_spec_from_prolog_file(MainFile). % sometimes windows is confused about the upper case letter....
2659 load_spec_file('eventb',MainFile) :- !, load_eventb_file(MainFile).
2660 load_spec_file('v',MainFile) :- !,
2661 print('Warning: .v proof rule file format no longer supported, use -eval_rule_file FILE'),nl,
2662 % but even that may not work; some older rule files required predicate variables
2663 load_b_file_with_options(MainFile). % Siemens Rule File; now use -eval_rule_file
2664 load_spec_file('prob',MainFile) :- !,load_prob_file_with_options(MainFile). % .prob files
2665 load_spec_file('mch',MainFile) :- !,load_b_file_with_options(MainFile).
2666 load_spec_file('sys',MainFile) :- !,load_b_file_with_options(MainFile).
2667 load_spec_file('ref',MainFile) :- !,load_b_file_with_options(MainFile).
2668 load_spec_file('imp',MainFile) :- !,load_b_file_with_options(MainFile).
2669 load_spec_file('rmch',MainFile) :- !,load_b_file_with_options(MainFile).
2670 load_spec_file('def',MainFile) :- !,load_b_file_with_options(MainFile). % .def DEFINITIONS file
2671 load_spec_file('fuzz',MainFile) :- !,tcltk_open_z_file(MainFile).
2672 load_spec_file('tex',MainFile) :- !,tcltk_open_z_tex_file(MainFile).
2673 load_spec_file('zed',MainFile) :- !,tcltk_open_z_tex_file(MainFile). % proz .zed file
2674 load_spec_file('als',MainFile) :- !,tcltk_open_alloy_file(MainFile).
2675 load_spec_file('pla',MainFile) :- !,tcltk_open_alloy_prolog_ast_file(MainFile). % maybe we should detect .als.pl
2676 load_spec_file('tla',MainFile) :- !, load_tla_file(MainFile).
2677 load_spec_file('eval',File) :- !, % .eval file
2678 cli_set_empty_machine,
2679 assertz(option(eval_string_or_file(file(default),File,exists,_,norecheck))).
2680 load_spec_file('pb',File) :- !, cli_set_empty_machine, % .pb file
2681 cli_set_empty_machine,
2682 assertz(option(eval_string_or_file(file(default),File,exists,_,norecheck))).
2683 %load_spec_file('pml',MainFile) :- !,parsercall:call_promela_parser(MainFile),
2684 % parsercall:promela_prolog_filename(MainFile,PrologFile),
2685 % println_silent(consulting(PrologFile)),
2686 % tcltk_open_promela_file(PrologFile).
2687 load_spec_file(EXT,MainFile) :- print_error('Unknown file extension, assuming B machine:'),
2688 print_error(EXT),
2689 load_b_file_with_options(MainFile).
2690
2691 load_spec_file('pl',MainFile, Already_FullyProcessed) :-
2692 load_pl_file_with_disprover(MainFile), !,
2693 Already_FullyProcessed=true,
2694 printsilent('Processing PO file: '),printsilent(MainFile),nls,
2695 load_po_file(MainFile),
2696 (option(timeout(TO)) -> set_disprover_timeout(TO) ; reset_disprover_timeout),
2697 (option(disprover_options(L)) -> set_disprover_options(L) ; set_disprover_options([])),
2698 println_silent('Running ProB Disprover'),
2699 run_disprover_on_all_pos(Summary),
2700 print_disprover_stats,
2701 accumulate_infos(disprover,[po_files-1|Summary]),
2702 get_errors,
2703 (option(cli_check_disprover_result(Infos)) -> check_required_infos(Infos,Summary,load_po_file)
2704 ; option(strict_raise_error) -> check_required_infos([false-0,unknown-0,failure-0],Summary,load_po_file)
2705 % TO DO: provide way for user to specify expected info
2706 ; true),
2707 cli_process_options_for_alrady_fully_processed_file(MainFile),
2708 clear_loaded_machines.
2709 load_spec_file(EXT,MainFile,Already_FullyProcessed) :- (EXT='smt2' ; EXT= 'smt'), !,
2710 Already_FullyProcessed=true,
2711 printsilent('Processing SMT file: '),printsilent(MainFile),nls,
2712 (option(eval_repl([])) -> Opts = [repl] ; Opts=[]),
2713 smtlib2_file(MainFile,Opts).
2714 load_spec_file(EXT,F,false) :- load_spec_file(EXT,F).
2715
2716 % check if we should load a pl file using the disprover runner; if not we will load it in XTL mode
2717 load_pl_file_with_disprover(_MainFile) :- option(disprover_options(_)).
2718 load_pl_file_with_disprover(_MainFile) :- option(cli_check_disprover_result(_)).
2719 load_pl_file_with_disprover(_) :-
2720 \+ computeOperations_for_root_required,
2721 \+ (option(A), option_requires_all_properties(A)).
2722
2723
2724 load_prob_file_with_options(File) :-
2725 (option(release_java_parser) -> Options = [use_fastread] ; Options = []),
2726 load_prob_file(File,Options).
2727 load_b_file_with_options(File) :-
2728 (option(release_java_parser) -> Options = [release_java_parser,use_fastread]
2729 ; option(fast_read_prob) -> Options = [use_fastread] % use fastread for large .prob files
2730 ; Options = []),
2731 % TO DO: automatically release if no option requires parsing and no more file uses it; or print warning if release will affect other options like -repl (DEFINITIONS not available,...)
2732 load_b_file(File,Options).
2733
2734 % do not perform -execute_all if no parameters provided
2735 do_not_execute_automatically('pl').
2736 do_not_execute_automatically('smt2').
2737
2738 test_kodkod_and_exit(MaxResiduePreds,NOW) :-
2739 start_animation_without_computing,
2740 test_kodkod(MaxResiduePreds),
2741 halt_prob(NOW,0).
2742
2743 compare_kodkod_performance1(KPFile,Iterations,NOW) :-
2744 start_animation_without_computing,
2745 compare_kodkod_performance(KPFile,Iterations),
2746 halt_prob(NOW,0).
2747
2748 :- use_module(parsercall,[check_java_version/2,get_parser_version/1, ensure_console_parser_launched/0,
2749 connect_to_external_console_parser_on_port/1]).
2750 check_java_version :- check_java_version(V,Result),
2751 format('Result of checking Java version:~n ~w~n',[V]),
2752 (Result=compatible -> check_parser_version
2753 ; add_error(check_java_version,V)).
2754
2755 check_parser_version :- get_parser_version(PV),!,
2756 format(' ProB B Java Parser available in version: ~w.~n',[PV]). % will also launch parser
2757 check_parser_version :- add_error(check_parser_version,'Cannot start Java B Parser to obtain version number').
2758
2759 :- use_module(pathes_lib,[install_lib_component/2]).
2760 install_prob_lib(Lib,Opts) :- install_lib_component(Lib,Opts).
2761
2762 print_version(Kind) :- print_version(Kind,user_output).
2763
2764 print_version(short,Stream) :- print_short_version(Stream).
2765 print_version(cpp,Stream) :- print_cpp_version(Stream).
2766 print_version(java,Stream) :- print_java_version(Stream).
2767 print_version(full,Stream) :- print_full_version(Stream).
2768 print_version(full_verbose,Stream) :- print_full_version(Stream,verbose).
2769 print_version(host,Stream) :- print_host_version(Stream).
2770 print_version(lib,Stream) :- check_lib_contents(Stream,verbose).
2771
2772 :- use_module(version).
2773 print_short_version(Stream) :-
2774 version(V1,V2,V3,Suffix),revision(Rev),
2775 format(Stream,'VERSION ~p.~p.~p-~p (~p)~N',[V1,V2,V3,Suffix,Rev]).
2776
2777 :- use_module(parsercall,[get_parser_version/1, get_java_command_path/1, get_java_fullversion/1]).
2778 :- use_module(pathes_lib,[check_lib_contents/2]).
2779 print_full_version(Stream) :-
2780 (option_verbose ->
2781 (option_very_verbose
2782 -> print_full_version(Stream,very_verbose)
2783 ; print_full_version(Stream,verbose)
2784 )
2785 ; print_full_version(Stream,normal)
2786 ).
2787 print_full_version(Stream,Verbose) :-
2788 format(Stream,'ProB Command Line Interface~n',[]),
2789 print_probcli_version(Stream),
2790 ( Verbose=normal -> true
2791 ;
2792 current_prolog_flag(system_type,SysType),
2793 format(Stream,' Prolog System Type: ~p~N', [SysType]), % development or runtime
2794 safe_absolute_file_name(prob_home('.'),AppDir),
2795 format(Stream,' Application Path: ~p~N', [AppDir]),
2796 print_host_version(Stream),
2797 print_java_version(Stream),
2798 print_cpp_version(Stream),
2799 (Verbose = very_verbose
2800 -> print_prolog_flags(Stream), print_extensions(Stream), print_modules(Stream),
2801 check_lib_contents(Stream,verbose)
2802 ; check_lib_contents(Stream,silent)
2803 )
2804 ), print_compile_time_flags.
2805
2806 print_java_version(Stream) :-
2807 (get_java_command_path(JavaPath)
2808 -> format(Stream,' Java Runtime: ~p~N', [JavaPath]),
2809 (get_java_fullversion(JavaVersion)
2810 -> format(Stream,' Java Version: ~s~N', [JavaVersion])
2811 ; format(Stream,' Java Version: *** not available ***~N',[])
2812 ),
2813 (get_parser_version(ParserVersion)
2814 -> format(Stream,' Java Parser: ~p~N', [ParserVersion])
2815 ; format(Stream,' Java Parser: *** not available ***~N',[])
2816 )
2817 ; format(Stream,' Java Runtime: *** not available ***~N',[])
2818 ).
2819
2820 :- use_module(tools_platform, [host_platform/1, host_processor/1]).
2821 print_host_version(Stream) :-
2822 host_platform(HP),
2823 host_processor(Proc),
2824 (platform_is_64_bit -> Bits=64 ; Bits=32),
2825 format(Stream,' Host Processor: ~w (~w bits)~n Host Operating System: ~w~n',[Proc,Bits,HP]).
2826
2827
2828 print_probcli_version(Stream) :-
2829 full_version_str(VersStr),
2830 revision(Rev), lastchangeddate(LCD),
2831 current_prolog_flag(dialect, Dialect),
2832 (Dialect= swi, current_prolog_flag(version_git,PV) -> true
2833 ; current_prolog_flag(version,PV)
2834 ),
2835 format(Stream,' VERSION ~w (~p)~N ~p~N Prolog (~w): ~p~N',
2836 [VersStr,Rev,LCD,Dialect, PV]).
2837
2838
2839 :- use_module(compile_time_flags,[compile_time_flags/1, relevant_prolog_flags/1]).
2840 :- use_module(extension('regexp/regexp'),[get_cpp_version/1]).
2841 print_compile_time_flags :-
2842 compile_time_flags(list(Flags)),
2843 (Flags=[], \+ option_verbose -> true ; format(' COMPILE TIME FLAGS: ~w~N',[Flags])).
2844 print_prolog_flags(Stream) :-
2845 relevant_prolog_flags(Flags),
2846 format(Stream,' PROLOG FLAGS: ~w~N',[Flags]).
2847 print_extensions(Stream) :- findall(E,available_extension(E),Es),
2848 format(Stream,' EXTENSIONS: ~w~N',[Es]).
2849 print_cpp_version(Stream) :-
2850 available_extension(regexp_extension),!,
2851 get_cpp_version(V),
2852 format(Stream,' C++ Version for extensions: ~w~n',[V]).
2853 print_cpp_version(_).
2854 print_modules(Stream) :- findall(M,current_module(M),Ms), sort(Ms,SMs),
2855 format(Stream,' PROLOG MODULES: ~w~N',[SMs]).
2856
2857 print_logo :-
2858 % should be improved considerably; doesn't look very nice yet on macOS terminal due to line separation
2859 % â–„â–„â–„â–„ â–„â–„â–„â–„
2860 % â–ˆ â–ˆ â–ˆ â–ˆ
2861 % █▀▀▀ ▄ ▄▄▄ █▀▀▀▄
2862 % █ █ █▄█ █▄▄▄▀
2863 format_with_colour_nl(user_output,[blue],' ~s',[[9604,9604,9604,9604,32,32,32,32,32,32,32,9604,9604,9604,9604]]),
2864 format_with_colour_nl(user_output,[blue],' ~s',[[9608,32,32,32,9608,32,32,32,32,32,32,9608,32,32,32,9608]]),
2865 format_with_colour_nl(user_output,[blue],' ~s',[[9608,9600,9600,9600,32,9604,32,9604,9604,9604,32,9608,9600,9600,9600,9604]]),
2866 format_with_colour_nl(user_output,[blue],' ~s',[[9608,32,32,32,9608,32,32,9608,9604,9608,32,9608,9604,9604,9604,9600]]).
2867
2868 print_help :-
2869 print_version(full),
2870 print('Usage: probcli FILE [OPTIONS]'),nl,
2871 print(' OPTIONS are: '),nl,
2872 print(' -mc Nr model check; checking at most Nr states'),nl,
2873 print(' -model_check model check without limit on states explored'),nl,
2874 ( \+ option_verbose ->
2875 print(' -noXXX XXX=dead,inv,goal,ass (for model check)'),nl % -nodead, -noinv, -nogoal, -noass
2876 ;
2877 print(' -nodead do not look for deadlocks (for model check, animate, execute)'),nl,
2878 print(' -noinv do not look for invariant violations (for model check, animate, execute)'),nl,
2879 print(' -nogoal do not look for GOAL predicate (for model check, execute)'),nl,
2880 print(' -noass do not look for ASSERTION violations (for model check, execute)'),nl
2881 ),
2882 print(' -bf proceed breadth-first (default is mixed bf/df)'),nl,
2883 print(' -df proceed depth-first'),nl,
2884 print(' -mc_mode M M=hash,heuristic,random,dlk,breadth-first,depth-first,mixed,size'),nl, % dlk stands for out_degree_hash
2885 print(' -global_time_out N total timeout in ms for model/refinement checking and'),nl,
2886 print(' and execute steps and disprover checks'),nl,
2887 print(' -disable_timeout disable timeouts for operations, invariants,....'),nl, % speeds up mc
2888 print(' -t trace check (associated .trace file must exist)'),nl,
2889 print(' -trace_replay K F replay trace file F in format K (prolog,json,B)'),nl,
2890 print(' -init initialise specification'),nl,
2891 print(' -cbc OPNAME constraint-based invariant checking for an operation'),nl,
2892 print(' (you can also use OPNAME=all)'),nl,
2893 print(' -cbc_deadlock constraint-based deadlock checking'),nl,
2894 ( \+ option_verbose -> true ;
2895 print(' -cbc_deadlock_pred PRED as above but with additional predicate'),nl
2896 ),
2897 print(' -cbc_assertions constraint-based static assertion checking'),nl,
2898 print(' -cbc_refinement constraint-based static refinement checking'),nl,
2899 print(' -cbc_sequence S constraint-based search for sequence of operations'),nl,
2900 print(' -strict raise error if model-checking finds counter example'),nl,
2901 print(' or trace checking fails or any error state found'),nl,
2902 print(' -expcterr ERR expect error to occur (ERR=cbc,mc,ltl,...)'),nl,
2903 print(' -animate Nr random animation (max. Nr steps)'),nl,
2904 print(' -animate_all random animation until a deadlock is reached'),nl,
2905 print(' -animate_until_ltl P random animation until LTL property satisfied on trace'),nl,
2906 print(' -animate_until_ltl_state_property P until state satisfies LTL state property)'),nl,
2907 print(' -animate_stats provide feedback which operations are animated or executed'),nl,
2908 print(' -execute Nr execute specification (maximally Nr steps)'),nl,
2909 print(' in contrast to -animate: stops at first operation found, is deterministic,'),nl,
2910 print(' does not store intermediate states and does not use TIME_OUT preference'),nl,
2911 print(' -execute_all execute until a deadlock, direct loop, goal or error is reached'),nl,
2912 print(' -execute_monitor monitor performance of execute'),nl,
2913 print(' -his File write history to File'),nl,
2914 print(' -his_option O additional option when writing a history (show_init,show_states,json,trace_file)'),nl,
2915 print(' -sptxt File save constants and variable values of last discovered state to File'),nl,
2916 print(' -sstxt Dir save constants and variable values of all discovered states to files in Dir'),nl,
2917 print(' -cache Directory automatically save constants and operations to files to avoid recomputation'),nl,
2918 print(' -det_check check if animation steps are deterministic'),nl,
2919 print(' -det_constants only check if SETUP_CONSTANTS step is deterministic'),nl,
2920 ( \+ option_verbose -> true ;
2921 print(' -i interactive animation. Only for interactive sessions,'),nl,
2922 print(' the output can arbitrarily change in future versions. '),nl,
2923 print(' Do not build automatic tools using the interactive mode'),nl
2924 ),
2925 print(' -repl start interactive read-eval-loop'),nl,
2926 print(' -eval "E" evaluate expression or predicate'),nl,
2927 print(' -eval_file FILE evaluate expression or predicate from file'),nl,
2928 print(' -c print coverage statistics'),nl,
2929 print(' -cc Nr Nr print and check coverage statistics'),nl,
2930 print(' -vacuity_check look for vacuous implications in invariant'),nl,
2931 print(' -cbc_redundant_invariants Nr find redundant invariants, expecting Nr'),nl, % Nr exepcted
2932 print(' -statistics print memory and other statistics at the end'),nl,
2933 print(' -p PREF Val set preference to value'),nl,
2934 print(' -prefs FILE set preferences from Prolog file'),nl,
2935 print(' -pref_group G S set group G of preferences to predefined value set S'),nl,
2936 print(' -card GS Val set cardinality (aka scope) of B deferred set'),nl,
2937 print(' -goal "PRED" set GOAL predicate for model checker'),nl,
2938 print(' -check_goal check GOAL (after -mc, -t, or -animate)'),nl,
2939 print(' -scope "PRED" set scope predicate for model checker'),nl,
2940 print(' (only states satsifying this predicate will be examined)'),nl,
2941 print(' -property "PRED" virtually add predicate to PROPERTIES'),nl,
2942 print(' -s Port start socket server on given port'),nl,
2943 print(' -ss start socket server on port 9000'),nl,
2944 print(' -sf start socket server on some free port'),nl,
2945 print(' -l LogFile log activities in LogFile'),nl,
2946 print(' -ll log activities in /tmp/prob_cli_debug.log'),nl,
2947 print(' -logxml LogFile log activities in XML LogFile'),nl,
2948 print(' -logxml_write_ids P write variables/constants starting with P to XML LogFile'),nl,
2949 print(' -pp FILE pretty-print internal representation to file (or user_output)'), nl,
2950 print(' -ppf FILE like -pp, but force printing of all type infos'),nl,
2951 print(' -ppAB FILE like -ppf, but make output readable by Atelier-B'),nl,
2952 print(' -ppB FILE pretty-print Event-B model to file in valid B syntax'),nl,
2953 ( \+ option_verbose -> true ;
2954 print(' -ppi FILE pretty-print B model main file with indenatation'),nl,
2955 print(' -indent_b_file BFILE FILE pretty-print BFILE to FILE with indenatation'),nl,
2956 print(' -reformat_b_file BFILE FILE reformat BFILE to FILE (may insert newlines)'),nl,
2957 print(' -pp_pl_file PLFILE FILE indent Prolog PLFILE to FILE'),nl
2958 ),
2959 print(' -v verbose'),nl,
2960 ( \+ option_verbose -> true ;
2961 print(' -vv very verbose'),nl
2962 ),
2963 print(' -mc_with_tlc model check using TLC (see also TLC_WORKERS preference)'),nl,
2964 print(' -mc_with_lts_sym model check using LTSmin (symbolic)'),nl,
2965 print(' -mc_with_lts_seq model check using LTSmin (sequential)'),nl,
2966
2967 ( \+ option_verbose -> true ;
2968 print(' -ltsmin_option OPT set option for LTSmin (e.g, por)'),nl,
2969 print(' -ltsmin_ltl_output FILE set output file for LTSMin'),nl,
2970 print(' -symbolic_model_check ALGO ALGO is bmc, kinduction, ctigar, ic3'),nl,
2971 print(' -enabling_analysis_csv FILE perform operation enabling analysis'),nl,
2972 print(' -feasibility_analysis perform operation feasibility analysis'),nl,
2973 print(' -feasibility_analysis_csv FILE write feasibility result to file'),nl,
2974 print(' -read_write_matrix show read/write matrix for operations'),nl
2975 ),
2976 print(' -version print version information (-svers for short info)'),nl,
2977 print(' -check_java_version check that Java version compatible with ProB parser'),nl,
2978 print(' -assertions check ASSERTIONS'),nl,
2979 print(' -main_assertions check ASSERTIONS from main file only'),nl,
2980 print(' -properties check PROPERTIES'),nl,
2981 print(' -ccache Dir like -cache Dir but create directoy if it does not exist'),nl,
2982 print(' -show_cache show contents of cache'),nl,
2983 print(' -show_cache_verbose show contents of cache in more detail'),nl,
2984 print(' -cache_statistics show statistics about cache reuse'),nl,
2985 print(' -clear_cache clear the cache'),nl,
2986 print(' -clear_cache_for M clear the cache for machine M'),nl,
2987 print(' -show_inclusion_hierarchy useful to determine order for pre-populating cache for constants'),nl,
2988 print(' -ltlfile F check LTL formulas in file F'),nl,
2989 print(' -ltlassertions check LTL assertions (in DEFINITIONS)'),nl,
2990 print(' -ltllimit L explore at most L states when model-checking LTL or CTL'),nl,
2991 print(' -ltlformula \"F\" check the LTL formula F'),nl,
2992 print(' -ctlformula \"F\" check the CTL formula F'),nl,
2993 print(' -save File save state space for later refinement check'),nl,
2994 print(' -refchk File refinement check against previous saved state space'),nl,
2995 print(' -mcm_tests Depth MaxStates EndPredicate File'),nl,
2996 print(' generate test cases with maximum length Depth, explore'),nl,
2997 print(' maximally MaxStates, the last state satisfies EndPredicate'),nl,
2998 print(' and the test cases are written to File'),nl,
2999 print(' -mcm_cover Operation'),nl,
3000 print(' when generating MCM test cases, Operation should be covered'),nl,
3001 print(' -cbc_tests Depth EndPredicate File'),nl,
3002 print(' generate test cases by constraint solving with maximum'),nl,
3003 print(' length Depth, the last state satisfies EndPredicate'),nl,
3004 print(' and the test cases are written to File'),nl,
3005 print(' -cbc_cover Operation'),nl,
3006 print(' when generating CBC test cases, Operation should be covered'),nl,
3007 % print(' -cbc_cover_all try and cover all operations'),nl, % is now default if no cbc_cover provided
3008 print(' -test_description File'),nl,
3009 print(' read information for test generation from File'),nl,
3010 print(' -dot CMD File write a graph to a dot file, with CMD being one of:'),nl,
3011 (is_dot_command(Cmd),command_description(Cmd,_,Desc),
3012 format(' ~w : ~w~n',[Cmd,Desc]),fail
3013 ; true),
3014 print(' -dotexpr CMD Expr File write a graph for Expr to a dot file, with CMD:'),nl,
3015 (is_dot_command_for_expr(Cmd),command_description(Cmd,_,Desc),
3016 format(' ~w : ~w~n',[Cmd,Desc]),fail
3017 ; true),
3018 print(' -puml CMD File write a graph to a plantuml file, with CMD being one of:'),nl,
3019 (is_plantuml_command(Cmd),command_description(Cmd,_,Desc),
3020 format(' ~w : ~w~n',[Cmd,Desc]),fail
3021 ; true),
3022 print(' -pumlexpr CMD Expr File write a graph for Expr to a plantuml file, with CMD:'),nl,
3023 (is_plantuml_command_for_expr(Cmd),command_description(Cmd,_,Desc),
3024 format(' ~w : ~w~n',[Cmd,Desc]),fail
3025 ; true),
3026 print(' -csv CMD File write a table to a CSV file, with CMD being one of:'),nl,
3027 (is_table_command(Cmd),command_description(Cmd,_,Desc),
3028 format(' ~w : ~w~n',[Cmd,Desc]),fail
3029 ; true),
3030 print(' -csvexpr CMD Expr File write a table for Expr to a CSV file, with CMD:'),nl,
3031 (is_table_command_for_expr(Cmd),command_description(Cmd,_,Desc),
3032 format(' ~w : ~w~n',[Cmd,Desc]),fail
3033 ; true),
3034 print(' -dot_output Path generate dot files for false assertions/properties'),nl,
3035 print(' -dot_all also generate dot files for true assertions/properties'),nl,
3036 print(' -rule_report generate HTML validation report for rules machines (.rmch)'),nl,
3037 print(' -proof_export generate HTML proof export in sequent prover mode (for .pl PO files)'),nl,
3038 print(' -csvhist E File evaluate expression over history and generate CSV file'),nl,
3039 print(' -visb JFile HFile use VisB JSON file JFILE to create HTML visualistion of history'),nl,
3040 print(' -visb_with_vars JFile HFile (similar, but also show variable values)'),nl,
3041 print(' -load_state File load state of ProB from a saved state space (generated by ProB Tcl/Tk or -save_state)'),nl,
3042 % For Eclipse Version only
3043 %% print(' -parsercp CP class path of the B Parser, this has to be a valid Java class path'),nl,
3044 %% print(' -cspm load CSP-M .csp file rather than B Machine .mch/.ref/.imp File'),nl,
3045 %% print(' -csp load CSP-M .pl file rather than B Machine File'),nl,
3046
3047 /* Options -cspref, -cspdeadlock, -cspdeterministic, and -csplivelock are deprecated, should be excluded in favor of -csp_assertion */
3048 print(' -cspref Spec [m= Impl File'),nl,
3049 print(' checks a refinement statement,'),nl,
3050 print(' where Spec and Impl are processes from File, and \'m\' the type of the refinement:'),nl,
3051 print(' \'T\' for traces, \'F\' for failures, or \'FD\' for failures-divergences.'),nl,
3052 print(' -cspdeadlock P m File'),nl,
3053 print(' checks a process for deadlock,'),nl,
3054 print(' where \'P\' is a process from File, and \'m\' the type of the model:'),nl,
3055 print(' \'F\' for failures and \'FD\' for failures-divergences.'),nl,
3056 print(' -cspdeterministic P m File'),nl,
3057 print(' checks a process for determinism,'),nl,
3058 print(' where \'P\' is a process from File, and \'m\' the type of the model:'),nl,
3059 print(' \'F\' for failures and \'FD\' for failures-divergences.'),nl,
3060 print(' -csplivelock P File'),nl,
3061 print(' checks a process for divergence,'),nl,
3062 print(' where \'P\' is a process from File.'),nl,
3063 /* Options -cspref, -cspdeadlock, -cspdeterministic, and -csplivelock are deprecated, should be excluded in favor of -csp_assertion */
3064
3065 print(' -csp_assertion \"A\" File'),nl,
3066 print(' checks the CSP assertion \'A\' on file \'File\''),nl,
3067 print(' -csp_eval "E" evaluate CSP-M expression.'),nl,
3068 print(' -csp_guide File CSP||B: Use the CSP File to control the B machine'),nl,
3069 print(' '),nl,
3070 ( \+ option_verbose -> true
3071 ;
3072 print(' -test_mode set random seed to the Prolog\'s current random state'),nl,
3073 print(' -rc runtime checking of types/pre-/post-conditions'),nl,
3074 print(' -state_trace File read a file of B predicates (one per line) and try find a matching trace.'),nl
3075
3076 ),
3077 print(' FILE extensions are: '),nl,
3078 print(' .mch for B abstract machines'),nl,
3079 print(' .ref for B refinement machines'),nl,
3080 print(' .imp for B implementation machines'),nl,
3081 print(' .sys for Event-B abstract machines'),nl,
3082 print(' .rmch for B Rule DSL machines'),nl,
3083 print(' .csp, .cspm for CSP-M files, same format as FDR'),nl,
3084 print(' .eventb for Event-B packages exported from Rodin ProB Plugin'),nl,
3085 print(' .tex, .zed for Z models'),nl,
3086 print(' .tla for TLA+ models'),nl,
3087 print(' .als for Alloy models'),nl,
3088 print(' .P for Prolog XTL models'),nl,
3089 ( option_verbose ->
3090 print(' Preferences PREF are: '),nl,
3091 print_eclipse_prefs
3092 ;
3093 print(' Use --help -v to print available preferences PREF'),nl
3094 ),
3095 print(' Set NO_COLOR environment variable to disable terminal colors'),nl,
3096 print(' More info at: https://prob.hhu.de/w/index.php/ProB_Cli'),nl,
3097 nl.
3098
3099
3100 set_argv(V) :-
3101 debug_println(20,set_argv(V)),
3102 external_functions:set_argv_from_atom(V).
3103
3104 :- use_module(b_global_sets, [set_user_defined_scope/2]).
3105 :- use_module(state_space_exploration_modes,[set_depth_breadth_first_mode/1, get_current_breadth_first_level/1]).
3106 :- use_module(tools_strings, [convert_cli_arg/2]).
3107 set_prefs :-
3108 if_option_set(cli_start_sym_mc_with_lts(_),
3109 preferences:set_preference(try_operation_reuse,false)), % LTSMIN does its own OPERATION_REUSE
3110 if_option_set(socket(_,_), % then we may need the event(.) transition_info for the Java API
3111 preferences:set_preference(store_event_transinfo,true)),
3112 option(set_prefs_from_file(File)),
3113 debug_println(20,load_preferences(File)),
3114 preferences:load_preferences(File),
3115 fail.
3116 set_prefs :-
3117 option(set_preference_group(P,V)),
3118 debug_println(20,set_preference_group(P,V)),
3119 set_preference_group(P,V),
3120 fail.
3121 % eclipse preference or 'normal preference'
3122 set_prefs :-
3123 ? option(set_pref(P,V)),
3124 set_pref(P,V),
3125 fail.
3126 set_prefs :- option(set_card(Set,V)),
3127 debug_println(20,set_card(Set,V)),
3128 convert_cli_arg(V,Value),
3129 set_user_defined_scope(Set,Value),
3130 fail.
3131 set_prefs :-
3132 ( option(breadth_first) -> set_depth_breadth_first_mode(breadth_first)
3133 ; option(depth_first) -> set_depth_breadth_first_mode(depth_first)
3134 ; option(depth_breadth_first_mode(M)) -> set_depth_breadth_first_mode(M)
3135 ; true
3136 ).
3137 :- use_module(tools_matching,[get_possible_preferences_matches_msg/2]).
3138 set_pref(P,V) :-
3139 debug_println(20,set_pref(P,V)),
3140 ? ( eclipse_preference(P,_)
3141 -> set_eclipse_preference(P,V)
3142 ; deprecated_eclipse_preference(P,_,_,_) -> set_eclipse_preference(P,V)
3143 ; obsolete_eclipse_preference(P) -> probcli_add_light_warning('Obsolete preference: ',P)
3144 ; obsolete_preference(P) -> probcli_add_light_warning('Obsolete preference: ',P)
3145 ; % might be a term if its a plugin preference
3146 atom_codes(P,Codes),
3147 append(Codes,".",Codes2), % to make term readable by read_from_codes
3148 read_from_codes(Codes2,Preference),
3149 (nonvar(Preference),preference_val_type(Preference,_)
3150 -> convert_cli_arg(V,Value),
3151 set_preference(Preference,Value)
3152 ; P=timeout ->
3153 add_error(probcli,'Unknown preference timeout. Either set preference TIME_OUT or use -gobal_time_out command','')
3154 ; get_possible_preferences_matches_msg(P,FuzzyMsg) ->
3155 ajoin(['Unknown preference: ',P,'. Did you mean:'],Msg),
3156 add_error(probcli,Msg,FuzzyMsg)
3157 ; get_possible_fuzzy_match_options(P,FuzzyMatches),
3158 % will only give perfect matches as P usually does not have the hyphen in front
3159 FuzzyMatches = [FMC|_] ->
3160 ajoin(['Unknown preference ', P, ' which looks like a probcli command! Did you want to call:'],Msg),
3161 add_error(probcli,Msg,FMC)
3162 ;
3163 add_error(probcli,'Unknown preference:',P)
3164 )
3165 ).
3166
3167 % add non severe warning:
3168 probcli_add_light_warning(Msg,Term) :- option(strict_raise_error),!,
3169 add_warning(probcli,Msg,Term). % does not write on user_error
3170 probcli_add_light_warning(Msg,Term) :- add_message(probcli,Msg,Term).
3171
3172 set_optional_errors :- % register optional/expected errors in the error_manager; avoid printing on stderr
3173 reset_optional_errors_or_warnings,
3174 ? (option(optional_error(Type)) ; option(expect_error(Type)) ; option(expect_error_pos(Type,_Line,_Col))),
3175 register_optional_error_or_warning(Type),
3176 fail.
3177 set_optional_errors.
3178
3179 % explicit state model checking, without LTL/CTL
3180 regular_safety_model_check_now(Nr,Runtime,WallTime,MCRes,NOW) :-
3181 statistics(runtime,[T1,_]),
3182 statistics(walltime,[W1,_]),
3183 (option(timeout(TO)) -> safe_time_out(regular_safety_model_check(Nr,Time,MCRes),TO,Res)
3184 ; regular_safety_model_check(Nr,Time,MCRes), Res=success
3185 ),
3186 statistics(runtime,[T2,_]),
3187 statistics(walltime,[W2,_]),
3188 WallTime is W2-W1,
3189 Runtime is T2-T1,
3190 (Res=time_out
3191 -> add_warning(model_check_incomplete,'Not all states examined due to -global_time_out option set by user: ',TO),
3192 writeln_log(timeout_occurred(NOW,model_check(Nr,Time,MCRes))),
3193 coverage(just_summary),
3194 MCRes=time_out
3195 ; true).
3196
3197 :- use_module(model_checker,[model_checking_is_incomplete/6]).
3198
3199 % TO DO: check for ignored states
3200 % code somewhat redundant also with model_check_incomplete below
3201 add_model_checking_warnings(FindInvViolations,FindDeadlocks,FindGoal,FindAssViolations) :-
3202 %print(check(model_checking_is_incomplete(FindInvViolations,FindDeadlocks,FindGoal,FindAssViolations,Msg,Term))),nl,
3203 model_checking_is_incomplete(FindInvViolations,FindDeadlocks,FindGoal,FindAssViolations,Msg,Term),
3204 add_warning(model_check_incomplete,Msg,Term),
3205 % TO DO: store for accumulate_infos
3206 fail.
3207 add_model_checking_warnings(_,_,_,_).
3208
3209 :- use_module(state_space,[current_state_id/1]).
3210 regular_safety_model_check(Nr,Time,ErrRes) :-
3211 statistics(runtime,[T1,_]),
3212 statistics(walltime,[W1,_]),
3213 catch(model_check_aux(Nr,T1,W1,Time,ErrRes), user_interrupt_signal, (
3214 statistics(walltime,[W2,_]), TotalWT is W2-W1,
3215 format_with_colour_nl(user_error,[red],'~nmodel checking interrupted after ~w ms by user (CTRL-C)',[TotalWT]),
3216 coverage(just_summary),
3217 perform_feedback_options_after_exception,
3218 throw(user_interrupt_signal)
3219 )).
3220
3221 % perform some important options for user feedback after CTRL-C interrupts model checking, execute, ...
3222 perform_feedback_options_after_exception :-
3223 (option(check_op_cache(_)) -> cli_check_op_cache([]) ; true),
3224 if_options_set(csv_table_command(TECommand,TableFormulas,TableOptions,TableCSVFile),
3225 csv_table_command(TECommand,TableFormulas,TableOptions,TableCSVFile)),
3226 (option(get_coverage_information(FCC)) -> pretty_print_coverage_information_to_file(FCC) ; true),
3227 (option(cli_print_statistics(X)), (cli_print_statistics(X) -> fail) ; true).
3228
3229 model_check_aux(Nr,T1,W1,Time,ErrRes) :-
3230 (option(no_deadlocks) -> FindDeadlocks=0 ; FindDeadlocks=1),
3231 (option(no_invariant_violations) -> FindInvViolations=0 ; FindInvViolations=1),
3232 (option(no_goal) -> FindGoal=0 ; FindGoal=1),
3233 (option(no_state_errors) -> FindStateErrors=0 ; FindStateErrors=1),
3234 (option(no_assertion_violations)
3235 -> FindAssViolations=0
3236 ; FindAssViolations=1
3237 ),
3238 get_preference(por,POR),
3239 StopAtFullCoverage=0,
3240 %STOPMCAFTER = 86400000, /* 86400000 = 1 day timeout */
3241 STOPMCAFTER = 1152921504606846975, /* equals 13,343,998,895 days */
3242 InspectExistingNodes = 1,
3243 write_xml_element_to_log(model_checking_options,[find_deadlocks/FindDeadlocks,
3244 find_invariant_violations/FindInvViolations, find_goal/FindGoal,
3245 find_assertion_violations/FindAssViolations,
3246 find_state_errors/FindStateErrors,
3247 partial_order_reduction/POR,
3248 inspect_existing_nodes/InspectExistingNodes]),
3249 (tcltk_interface:do_model_check(Nr,NodesAnalysed,STOPMCAFTER,ErrRes,
3250 FindDeadlocks,FindInvViolations,FindGoal,
3251 FindAssViolations,FindStateErrors,StopAtFullCoverage,POR, InspectExistingNodes)
3252 -> (statistics(runtime,[T2,_]), statistics(walltime,[W2,_]),
3253 Time1 is T2-T1, WTime is W2-W1,
3254 (model_checker: expired_static_analysis_time(AnalysisTime) ->
3255 Time is Time1 - AnalysisTime
3256 ; Time = Time1, AnalysisTime=0),
3257 formatsilent('Model checking time: ~w ms (~w ms walltime)~n',[Time,WTime]),
3258 formatsilent('States analysed: ~w~n',[NodesAnalysed]),
3259 get_state_space_stats(_,NrTransitions,_,_),
3260 printsilent('Transitions fired: '),printsilent(NrTransitions),nls,
3261 (get_current_breadth_first_level(Level)
3262 -> formatsilent('Breadth-first levels: ~w~n',[Level]) % is this the equivalent of TLC's diameter?
3263 ; true),
3264 write_xml_element_to_log(model_checking_statistics,
3265 [result/ErrRes,runtime/Time,walltime/WTime,
3266 states/NodesAnalysed,transitions/NrTransitions,staticAnalysisTime/AnalysisTime]),
3267 (ErrRes = no
3268 -> print('No counter example Found, not all states visited'),nl,
3269 add_warning(model_check_incomplete,'Not all states examined due to limit set by user: ',Nr)
3270 ; ErrRes=all
3271 -> (tcltk_find_max_reached_node
3272 -> (not_interesting(_)
3273 -> print('No counter example found. However, not all transitions were computed (and some states not satisfying SCOPE predicate were ignored) !')
3274 ; print('No counter example found. However, not all transitions were computed !')
3275 )
3276 ; not_interesting(_)
3277 -> print_green('No counter example found. ALL states (satisfying SCOPE predicate) visited.')
3278 % b_get_machine_searchscope(Scope)
3279 ; print_green('No counter example found. ALL states visited.')
3280 ),nl,
3281 add_model_checking_warnings(FindInvViolations,FindDeadlocks,FindGoal,FindAssViolations)
3282 ; % ErrRes is not no or all
3283 print_red('*** COUNTER EXAMPLE FOUND ***'),nl,
3284 debug_println(20,ErrRes),nl,
3285 tcltk_interface:translate_error_for_tclk(ErrRes,TclTkRes),
3286 print(TclTkRes),nl,
3287 print_history_as_counter_example(true),
3288 error_occurred(TclTkRes)
3289 ),nl
3290 )
3291 ; % do_model_check failed
3292 statistics(runtime,[T2,_]), Time1 is T2-T1,
3293 (model_checker: expired_static_analysis_time(AnalysisTime) -> Time is Time1 - AnalysisTime
3294 ; Time = Time1),
3295 printsilent('Model checking time: '), printsilent(Time), printsilent(' ms'),nls,
3296 print_error('*** Model checking FAILED '),nl,
3297 ErrRes=fail,
3298 definite_error_occurred
3299 ).
3300
3301 print_history_as_counter_example(CheckInv) :-
3302 (option(silent) -> true
3303 ; option(no_counter_examples) -> true % -nocounter
3304 ; cli_print_history,
3305 (silent_mode(off), CheckInv=true,
3306 current_state_id(ID),invariant_violated(ID)
3307 -> b_interpreter:analyse_invariant_for_state(ID)
3308 ; true)
3309 ).
3310
3311 cli_print_history :-
3312 tcltk_interface:tcltk_get_history(list(Hist)),
3313 length(Hist,Len),
3314 format('*** TRACE (length=~w):~n',[Len]),
3315 reverse(Hist,Trace),
3316 print_nr_list(Trace).
3317
3318 % perform all cbc checks on current machine
3319 cbc_check(_NOW) :-
3320 option(cbc_deadlock_check(DeadlockGoalPred)),
3321 cbc_deadlock_check(DeadlockGoalPred),
3322 fail.
3323 cbc_check(_NOW) :-
3324 option(constraint_based_check(OpName)),
3325 constraint_based_check(OpName),
3326 fail.
3327 cbc_check(_NOW) :- option(cbc_assertions(AllowEnumWarning,Options)),
3328 cbc_assertions(AllowEnumWarning,Options),
3329 fail.
3330 %cbc_check(NOW) :-
3331 % option(cbc_pred(TargetPredString)),
3332 % check_loaded(cbc_pred),
3333 % print('% Starting Constraint-Based Check for Predicate: '), print(TargetPredString),nl,
3334 % b_set_up_valid_state_with_pred(NormalisedState,Pred) TO DO: add this feature
3335 cbc_check(_NOW) :- option(cbc_sequence(Sequence,TargetPredString,Findall)),
3336 cbc_sequence(Sequence,TargetPredString,Findall),
3337 fail.
3338 cbc_check(_NOW) :- option(cbc_refinement),
3339 cbc_refinement,
3340 fail.
3341 cbc_check(_NOW) :- option(cbc_redundant_invariants(NrExpected)),
3342 cbc_redundant_invariants(NrExpected),
3343 fail.
3344 cbc_check(_).
3345
3346 :- use_module(tcltk_interface,[tcltk_constraint_based_check/2,
3347 tcltk_constraint_based_check_with_timeout/2,
3348 tcltk_constraint_find_deadlock_state_with_goal/3,
3349 tcltk_cbc_find_trace/4,
3350 tcltk_cbc_refinement_check/2]).
3351 :- use_module(probsrc(bmachine),[b_is_operation_name/1]).
3352
3353 constraint_based_check(all) :-
3354 check_loaded_not_empty(constraint_based_check),
3355 print_repl_prompt_s('% Starting Constraint-Based Check for all Operations: '),nl,
3356 start_xml_feature(cbc_operation_check,all_operations,true,FINFO),
3357 (tcltk_constraint_based_check(list(Result),ErrorsWereFound)
3358 -> print('% Constraint-Based Check Result: '),nl,
3359 print(Result),nl,
3360 write_result_to_file(Result),
3361 (ErrorsWereFound=true
3362 -> print_red('*** CONSTRAINT-BASED CHECK FOUND ERRORS ***'),nl, error_occurred(cbc)
3363 ; (ErrorsWereFound=false -> print_green('NO ERRORS FOUND'),nl)
3364 ; print_red('*** TIMEOUT OCCURRED ***'),nl,error_occurred(cbc)
3365 )
3366 ; write_result_to_file(cbc_check_failed), Result=internal_error, ErrorsWereFound=false,
3367 add_internal_error('ConstraintBasedCheck unexpectedly failed. ',cbc_check(all)),definite_error_occurred
3368 ),nl,
3369 write_cbc_check_result(Result,ErrorsWereFound),
3370 stop_xml_feature(cbc_operation_check,FINFO).
3371 constraint_based_check(OpName) :- OpName\=all, % -cbc OpName
3372 check_loaded_not_empty(constraint_based_check),
3373 print_repl_prompt_s('% Starting Constraint-Based Check for Operation: '), print(OpName),nl,
3374 start_xml_feature(cbc_operation_check,operation,OpName,FINFO),
3375 (tcltk_constraint_based_check_with_timeout(OpName,Result)
3376 -> print('% Constraint-Based Check Result: '),nl, print(Result),nl,
3377 write_result_to_file(Result),
3378 (Result=time_out
3379 -> print_red('*** TIMEOUT OCCURRED ***'),nl, error_occurred(cbc)
3380 ; (Result=ok -> print_green('NO ERRORS FOUND'),nl)
3381 ; print_red('*** CONSTRAINT-BASED CHECK FOUND ERRORS ***'),nl,error_occurred(cbc) )
3382 ; write_result_to_file(constraint_based_check_failed), Result=internal_error,
3383 add_error(probcli,'ConstraintBasedCheck unexpectedly failed'),
3384 (b_is_operation_name(OpName) -> true
3385 ; add_error(probcli,'Unknown Operation Name: ',OpName)),
3386 definite_error_occurred
3387 ),nl,
3388 write_cbc_check_result(Result),
3389 stop_xml_feature(cbc_operation_check,FINFO).
3390
3391 write_cbc_check_result(Result) :-
3392 functor(Result,F,_), % example result: no_counterexample_exists(Ids,Prd,Other)
3393 write_xml_element_to_log(cbc_check_result,[result/F]).
3394 write_cbc_check_result(Result,ErrorsWereFound) :- functor(Result,F,_),
3395 write_xml_element_to_log(cbc_check_result,[result/F,errors_were_found/ErrorsWereFound]).
3396
3397 cbc_deadlock_check(DeadlockGoalPred) :-
3398 print_repl_prompt_s('% Starting Constraint-Based DEADLOCK check '),nl,
3399 start_xml_feature(cbc_deadlock_check,FINFO),
3400 (tcltk_constraint_find_deadlock_state_with_goal(DeadlockGoalPred,false,Res)
3401 -> write_result_to_file(Res),
3402 (Res=time_out ->
3403 print_red('*** TIME_OUT occurred ***'),nl,
3404 error_occurred(cbc_deadlock_check_time_out)
3405 ; print_red('*** DEADLOCK state found ***'),nl,
3406 error_occurred(cbc_deadlock_check),
3407 (silent_mode(on) -> true
3408 ; print('*** STATE = '),nl,
3409 current_b_expression(DBState), translate:print_bstate(DBState),nl,
3410 print('*** END DEADLOCKING STATE '),nl
3411 )
3412 )
3413 ; write_result_to_file(no_deadlock_found), Res=no_deadlock_found,
3414 print_green('No DEADLOCK state found'),nl
3415 ),
3416 write_cbc_check_result(Res),
3417 stop_xml_feature(cbc_deadlock_check,FINFO).
3418 cbc_assertions(AllowEnumWarning,Options) :-
3419 findall(OPT,option(cbc_option(OPT)),FullOptions,Options),
3420 check_loaded_not_empty(cbc_assertions),
3421 print_repl_prompt_s('% Starting Constraint-Based static ASSERTIONS check '),nl,
3422 start_xml_feature(cbc_assertion_check,allow_enumeration_warning,AllowEnumWarning,FINFO),
3423 write_prolog_term_as_xml_to_log(options(Options)),
3424 (cbc_constraint_find_static_assertion_violation(Res,FullOptions)
3425 -> process_cbc_assertion_result(Res,AllowEnumWarning)
3426 ; write_result_to_file(cbc_assertions_failed), Res=internal_error,
3427 print_red('CBC Check failed'),nl,
3428 error_occurred(cbc_assertions_failure)
3429 ),
3430 write_cbc_check_result(Res),
3431 stop_xml_feature(cbc_assertion_check,FINFO).
3432 cbc_sequence(Sequence,TargetPredString,Findall) :-
3433 check_loaded_not_empty(cbc_sequence),
3434 print_repl_prompt_s('% Starting Constraint-Based Check for Sequence: '), print_repl_prompt_s(Sequence),
3435 start_xml_feature(cbc_sequence_check,sequence,Sequence,FINFO),
3436 (TargetPredString='' -> true ; print(' with target: '), print(TargetPredString)),
3437 nl,
3438 write_xml_element_to_log(options,[target_predicate/TargetPredString]),
3439 (tcltk_cbc_find_trace(Sequence,TargetPredString,Findall,Res)
3440 -> (Res=ok -> print_green('Sequence found and executed'),nl
3441 ; Res=time_out -> error_occurred(cbc_sequence_time_out)
3442 ; Res=no_solution_found -> print_red('*** NO SOLUTION FOUND '),error_occurred(cbc_sequence_no_solution_found)
3443 ; Res=nr_cbc_sols(NrSols) -> print('*** # SOLUTIONS FOUND: '),print(NrSols),nl
3444 ; print_red('*** Unknown result: '), print(Res),nl,
3445 error_occurred(cbc_sequence)
3446 )
3447 ; print('*** Internal error: Check failed '), error_occurred(cbc_sequence), Res=internal_error
3448 ),
3449 write_cbc_check_result(Res),
3450 stop_xml_feature(cbc_sequence_check,FINFO).
3451 cbc_refinement :-
3452 check_loaded_not_empty(cbc_refinement),
3453 print_repl_prompt_s('% Starting Constraint-Based static refinement check '),nl,
3454 start_xml_feature(cbc_refinement_check,FINFO),
3455 tcltk_cbc_refinement_check(list(Result),ErrorsWereFound),
3456 print('% Constraint-Based Refinement Check Result: '),nl,print(Result),nl,
3457 (ErrorsWereFound = time_out -> print_red('*** TIME_OUT occurred ***'),nl,error_occurred(cbc_refinement_time_out) ;
3458 ErrorsWereFound = true -> print_red('*** Refinement Violation found ***'),nl,error_occurred(cbc_refinement) ;
3459 print_green('No static Refinement Violation found'),nl
3460 ),
3461 write_xml_element_to_log(cbc_check_result,[errors_were_found/ErrorsWereFound]),
3462 stop_xml_feature(cbc_refinement_check,FINFO).
3463 :- use_module(b_state_model_check,[cbc_find_redundant_invariants/2]).
3464 cbc_redundant_invariants(NrExpected) :-
3465 check_loaded_not_empty(cbc_redundant_invariants),
3466 print_repl_prompt_s('% Starting Constraint-Based invariant redundancy check'),nl,
3467 start_xml_feature(cbc_redundant_invariants,FINFO),
3468 cbc_find_redundant_invariants(Res,TimeoutOccured),
3469 length(Res,NrInvs),
3470 (Res = [] -> print_green('No redundant invariants found'),nl
3471 ; format('*** REDUNDANT INVARIANTS (~w) ***~n',[NrInvs]),
3472 prnt(1,Res), nl
3473 ),
3474 (NrExpected = NrInvs -> true
3475 ; format_with_colour_nl(user_error,[red],'*** Expected ~w redundant invariants (instead of ~w).',[NrExpected,NrInvs]),
3476 error_occurred(cbc_redundant_invariants)),
3477 write_xml_element_to_log(cbc_redundant_invariants,[redundant_invariants/NrInvs, timeout_occured/TimeoutOccured]),
3478 stop_xml_feature(cbc_redundant_invariants,FINFO).
3479
3480 prnt(_,[]).
3481 prnt(N,[H|T]) :- format(' ~w : ~w~n',[N,H]), N1 is N+1, prnt(N1,T).
3482
3483 :- use_module(solver_interface,[predicate_uses_unfixed_deferred_set/2, unfixed_typed_id_in_list/3]).
3484 process_cbc_assertion_result(time_out,_) :- !,
3485 write_result_to_file(no_counterexample_found('"TIME_OUT"')),
3486 print_red('*** TIME_OUT occurred ***'),nl,
3487 error_occurred(cbc_assertions_time_out).
3488 process_cbc_assertion_result(no_counterexample_exists(Constants,TotPredicate,OtherInfo),AllowEnumWarning) :- !,
3489 print_green('No counter-example to ASSERTION exists '),(OtherInfo=[] -> true ; print(OtherInfo)),nl,
3490 ? (unfixed_typed_id_in_list(TID,CType,Constants) % TO DO: look only at component
3491 -> write_deferred_set_used(AllowEnumWarning),
3492 get_texpr_id(TID,CID),pretty_type(CType,CTypeS),
3493 format('Warning: Some constants use deferred sets (e.g., ~w:~w) which have only been checked for a single cardinality!~n',[CID,CTypeS])
3494 ; predicate_uses_unfixed_deferred_set(TotPredicate,CType)
3495 -> write_deferred_set_used(AllowEnumWarning),pretty_type(CType,CTypeS),
3496 format('Warning: Some quantified variables use deferred sets (e.g., ~w) which have only been checked for a single cardinality!~n',[CTypeS]) % happens for tests 1173, 1174
3497 ; write_result_to_file(no_counterexample_exists)
3498 %,print('Computing unsat core: '),nl,unsat_cores:unsat_core(TotPredicate,Core),print('CORE: '),translate:print_bexpr(Core),nl
3499 ). % WE HAVE A PROOF
3500 process_cbc_assertion_result(no_counterexample_found,AllowEnumWarning) :- !,
3501 write_result_to_file(no_counterexample_found('"Enumeration Warning"')),
3502 print('No counter-example for ASSERTION found (*enumeration warning occured*)'),nl,
3503 (AllowEnumWarning=true -> true ; error_occurred(cbc_assertions_enumeration_warning)).
3504 process_cbc_assertion_result(counterexample_found,_) :- !,
3505 write_result_to_file(counterexample_found),
3506 print_red('*** Counter-example for ASSERTION found ***'),nl,
3507 error_occurred(cbc_assertions),
3508 (silent_mode(on) -> true
3509 ; print('*** STATE = '),nl,
3510 current_b_expression(DBState), translate:print_bstate(DBState),nl,
3511 print('*** END ASSERTION counter-example STATE '),nl
3512 ),
3513 (get_dot_file('cbc_assertions',DFile) -> generate_dot_from_assertions(DFile) ; true).
3514 process_cbc_assertion_result(Res,A) :-
3515 write_result_to_file(Res),
3516 add_internal_error('Unknown: ',process_cbc_assertion_result(Res,A)).
3517
3518
3519 write_deferred_set_used(AllowEnumWarning) :-
3520 write_result_to_file(no_counterexample_found('"Deferred Sets Used"')),
3521 (AllowEnumWarning=true -> true ; error_occurred(cbc_assertions_enumeration_warning)).
3522
3523 :- use_module(tools_io,[safe_open_file/4]).
3524 write_result_to_file(Result) :- option(cbc_result_file(FILE)),
3525 safe_open_file(FILE,write,Stream,[encoding(utf8)]),
3526 !,
3527 write(Stream,Result),
3528 close(Stream).
3529 write_result_to_file(_).
3530
3531
3532
3533 if_option_set(Option,Call) :-
3534 if_option_set(Option,Call,true).
3535 if_option_set(Option,Then,Else) :-
3536 (option(Option) -> call_for_option(Then) ; call_for_option(Else)).
3537 ifm_option_set(Option,Call) :-
3538 ifm_option_set(Option,Call,true).
3539 ifm_option_set(Option,Then,Else) :- % can perform multiple options
3540 findall(Then,option(Option),As),
3541 (As=[] -> call_for_option(Else) ; perform(As)).
3542 perform([]).
3543 perform([A|T]) :-
3544 call_for_option(A),
3545 perform(T).
3546 ?call_for_option(Call) :- (call(Call) -> true ; add_internal_error('probcli option call failed: ',Call)).
3547 if_option_set_loaded(Option,Action,Call) :-
3548 ( option(Option),check_loaded_not_empty(Action) ->
3549 call_for_option(Call)
3550 ; true).
3551 ifm_option_set_loaded(Option,Action,Call) :- % can perform multiple options
3552 findall(Call,(option(Option),check_loaded_not_empty(Action)),As),
3553 perform(As).
3554
3555
3556
3557 if_options_set(Option,Call) :- % allow multiple solutions for Option
3558 option(Option),call(Call),fail.
3559 if_options_set(_,_).
3560
3561 print_options :- print('CLI OPTIONS: '),nl,
3562 option(Option), print(Option), nl, fail.
3563 print_options :- nl.
3564
3565 :- use_module(cbcsrc(enabling_analysis),[infeasible_operation_cache/1]).
3566 :- use_module(cbcsrc(sap),[explore_and_generate_testcases/7,cbc_gen_test_cases_from_string/5, tcl_get_stored_test_cases/1]).
3567 :- use_module(translate,[print_bexpr/1]).
3568
3569 mcm_test_case_generation(ADepth,AMaxStates,ATarget,Output) :-
3570 arg_is_number(ADepth,MaxDepth),
3571 arg_is_number(AMaxStates,MaxStates),
3572 bmachine:b_parse_machine_predicate(ATarget,Target),!,
3573 get_comma_or_space_separated_options(mcm_cover,Events),
3574 (option(silent) -> true
3575 ; print('mcm test case generation, maximum search depth: '),print(MaxDepth),nl,
3576 print('mcm test case generation, maximum number of states: '),print(MaxStates),nl,
3577 print('mcm test case generation, target state predicate: '),print_bexpr(Target),nl,
3578 print('mcm test case generation, output file: '),print(Output),nl,
3579 print('mcm test case generation, events to cover: '),print_list(Events),nl
3580 ),
3581 explore_and_generate_testcases(Events,Target,MaxDepth,MaxStates,Output,NumTests,Uncovered),
3582 printsilent('mcm test case generation, generated test cases: '),printsilent(NumTests),nls,
3583 print_uncovered('mcm test case generation, ',Uncovered).
3584 mcm_test_case_generation(_ADepth,_AMaxStates,_ATarget,_Output) :-
3585 print_error('MCM Test Case Generation failed'),
3586 error_occurred(mcm_tests).
3587
3588 cbc_test_case_generation(ADepth,TargetString,Output) :-
3589 arg_is_number(ADepth,MaxDepth),
3590 ( option(cbc_cover_all) -> Events=all
3591 ; (get_comma_or_space_separated_options(cbc_cover,Events), Events \= []) -> true
3592 ; Events=all ),
3593 (\+ option(cbc_cover_final) -> FEvents = Events
3594 ; Events=all -> FEvents=all,
3595 add_error(cbc_cover_final,'Option cbc_cover_final not compatible with trying to cover all events')
3596 ; FEvents = final(Events),
3597 println_silent('constraint based test case generation, target events considered final')),
3598 printsilent('constraint based test case generation, maximum search depth: '),printsilent(MaxDepth),nls,
3599 printsilent('constraint based test case generation, target state predicate: '),printsilent(TargetString),nls,
3600 printsilent('constraint based test case generation, output file: '),printsilent(Output),nls,
3601 (TargetString = '#not_invariant' -> BMC=invariant_violation
3602 ; TargetString = '#deadlock' -> BMC=deadlock
3603 ; BMC = 'none'),
3604 (BMC \= 'none' ->
3605 printsilent('constraint based test case generation, performing bounded model checking'),nls
3606 ; option(silent) -> true
3607 ; print('constraint based test case generation, events to cover: '),print_list(Events),nl),
3608 cbc_gen_test_cases_from_string(FEvents,TargetString,MaxDepth,Output,Uncovered),
3609 !,
3610 format('constraint based test case generation finished~n',[]),
3611 (BMC \= 'none'
3612 -> tcl_get_stored_test_cases(list(Tests)), %print(tests(Tests)),nl,
3613 (Tests=[] -> print_green('No counterexample found'),nl
3614 ; Tests = [_|_], BMC=deadlock -> add_error(deadlock,'Deadlock found by bmc')
3615 ; Tests = [_|_] -> add_error(invariant_violation,'Invariant violation found by bmc')
3616 ; add_internal_error('Unexpected bmc result: ',Tests)
3617 )
3618 ; Uncovered=[_|_],option(strict_raise_error)
3619 -> add_error(cbc_tests,'Uncovered events: ',Uncovered)
3620 ; print_uncovered('constraint based test case generation, ',Uncovered)
3621 ).
3622 cbc_test_case_generation(_ADepth,_ATarget,_Output) :-
3623 print_error('Constraint based test case generation failed!'),
3624 error_occurred(cbc_tests).
3625
3626 print_uncovered(Msg,Uncovered) :-
3627 include(enabling_analysis:infeasible_operation_cache,Uncovered,Infeasible),
3628 (Infeasible=[]
3629 -> format('~wuncovered events: ',[Msg]),print_list(Uncovered),nl
3630 ; format('~winfeasible uncovered events: ',[Msg]),print_list(Infeasible),nl,
3631 exclude(enabling_analysis:infeasible_operation_cache,Uncovered,Feasible),
3632 format('~wuncovered events: ',[Msg]),print_list(Feasible),nl
3633 ).
3634
3635 print_list(all) :- print('** all **').
3636 print_list(list(L)) :- print_list(L). % possibly not used
3637 print_list([]) :- print('** none **').
3638 print_list([H|T]) :- length([H|T],Len), format('(~w) ',[Len]),
3639 print(H),print(' '),print_list2(T).
3640 print_list2([]).
3641 print_list2([H|T]) :- print(H),print(' '),print_list2(T).
3642
3643 get_comma_or_space_separated_options(Option,Selection) :-
3644 functor(O,Option,1),
3645 findall(E, (option(O),arg(1,O,CommaSep),
3646 split_by_seperator(CommaSep,Es),
3647 member(E,Es)),
3648 Selection).
3649
3650 split_by_seperator(NonAtomic,Res) :- \+ atomic(NonAtomic),!, Res=[NonAtomic].
3651 split_by_seperator(String,Strings) :-
3652 atom_chars(String,Chars),
3653 split_by_seperator2(Chars,Strings).
3654 split_by_seperator2(Chars,Result) :-
3655 append(AChars,[X|B],Chars),seperator(X),!,
3656 (AChars=[] -> Result=Rest ; atom_chars(A,AChars), Result=[A|Rest]),
3657 split_by_seperator2(B,Rest).
3658 split_by_seperator2(Chars,[String]) :- atom_chars(String,Chars).
3659
3660 seperator(',').
3661 seperator(' ').
3662 seperator(';').
3663
3664 ltl_check_assertions :-
3665 (option(ltl_limit(Limit)) -> true; Limit= -1), % -1 means no limit
3666 formatsilent('Model checking LTL assertions~n',[]),
3667 ltl_check_assertions(Limit,Outcome),!,
3668 ( Outcome = pass -> print_green('LTL check passed'),nl
3669 ; Outcome = fail -> print_red('*** LTL check failed'),nl,error_occurred(ltl)
3670 ; Outcome = no_tests -> print_red('*** No LTL assertions found, test failed'),nl,definite_error_occurred
3671 ; print_red('*** An error occurred in the LTL assertion test'),nl,
3672 definite_error_occurred).
3673 ltl_check_assertions :-
3674 add_internal_error('Call failed:',ltl_check_assertions),definite_error_occurred.
3675
3676 :- use_module(probltlsrc(ltl),[parse_ltlfile/2]).
3677 ltl_check_file(Filename) :-
3678 (option(ltl_limit(Limit)) -> true; Limit= -1), % -1 means no limit
3679 ajoin(['Model checking LTL assertions from file ',Filename],Msg),
3680 print_repl_prompt_s(Msg),nl,
3681 ( parse_ltlfile(Filename, Formulas)
3682 -> ltl_check_formulas(Formulas,Limit)
3683 ; print_red('An error occurred while parsing the LTL file.\n'),
3684 definite_error_occurred
3685 ).
3686
3687 :- use_module(probltlsrc(ltl),[ltl_model_check2/4]).
3688 ltl_check_formulas([],_) :-
3689 print_green('All LTL formulas checked.\n').
3690 ltl_check_formulas([formula(Name,F)|Rest],Limit) :-
3691 print('Checking formula '),print(Name),print(':\n'),
3692 ltl_model_check2(F,Limit,init,Status),
3693 ( Status == no ->
3694 print_red('Counter-example found for formula \"'),print_red(Name),
3695 print_red('\", saving trace file.\n'),
3696 ajoin(['ltlce_', Name, '.trace'], Tracefile),
3697 tcltk_save_history_as_trace_file(prolog,Tracefile),
3698 add_error(ltl_counterexample,'Counter-example was found')
3699 ; Status == ok ->
3700 ltl_check_formulas(Rest,Limit)
3701 ; Status == incomplete ->
3702 ajoin(['Model was not completly model-checked, aborted after ',Limit,' new states'],
3703 Msg),
3704 add_error(ltl,Msg)
3705 ;
3706 ajoin(['Model checker returns unexpected result (',Status,')'],Msg),
3707 add_error(ltl,Msg)).
3708
3709 % Mode = init or specific_node(ID) or starthere
3710 cli_ltl_model_check(Formula,Mode,ExpectedStatus,Status) :-
3711 (option(ltl_limit(Max)) -> true; Max = -1), % -1 means no limit
3712 start_xml_feature(ltl_model_check,formula,Formula,FINFO),
3713 ltl_model_check(Formula,Max,Mode,Status),
3714 write_xml_element_to_log(model_check_result,[status/Status,expected_status/ExpectedStatus,(mode)/Mode]),
3715 check_status(Status,ExpectedStatus,Formula,ltl),
3716 stop_xml_feature(ltl_model_check,FINFO).
3717
3718 % Mode = init or specific_node(ID) or starthere
3719 cli_ctl_model_check(Formula,Mode,ExpectedStatus,Status) :-
3720 (option(ltl_limit(Max)) -> true; Max = -1), % -1 means no limit
3721 start_xml_feature(ctl_model_check,formula,Formula,FINFO),
3722 ctl_model_check(Formula,Max,Mode,Status),
3723 write_xml_element_to_log(model_check_result,[status/Status,expected_status/ExpectedStatus,(mode)/Mode]),
3724 check_status(Status,ExpectedStatus,Formula,ctl),
3725 stop_xml_feature(ctl_model_check,FINFO).
3726
3727 :- use_module(extension('markov/dtmc_model_checking.pl')).
3728 cli_pctl_model_check(Formula,Mode,ExpectedStatus,Status) :-
3729 % use_module(extension('markov/dtmc_model_checking.pl')),
3730 (option(ltl_limit(Max)) -> true; Max = -1), % -1 means no limit
3731 dtmc_model_checking:pctl_model_check(Formula,Max,Mode,Status),
3732 check_status(Status,ExpectedStatus,Formula,pctl).
3733
3734 check_expected(St,Exp,Mode) :-
3735 (St=Exp -> true
3736 ; ajoin(['Unexpected ',Mode,' model checking result ',St,', expected: '],Msg),
3737 add_error(Mode,Msg,Exp)).
3738
3739 check_status(ok,Expected,Formula,ltl) :- !, % TO DO: make uniform ? CTL returns true; LTL returns ok
3740 format_with_colour_nl(user_output,[green],'LTL Formula TRUE.~nNo counter example found for ~w.',[Formula]),
3741 flush_output(user_output),
3742 check_expected(true,Expected,ltl).
3743 check_status(true,Expected,Formula,ctl) :- !,
3744 format_with_colour_nl(user_output,[green],'CTL Formula TRUE.~nNo counter example found for ~w.',[Formula]),
3745 flush_output(user_output),
3746 check_expected(true,Expected,ctl).
3747 check_status(true,Expected,Formula,pctl) :- !,
3748 format_with_colour_nl(user_output,[green],'PCTL Formula TRUE: ~w~n',[Formula]),
3749 flush_output(user_output),
3750 check_expected(true,Expected,pctl).
3751 check_status(solution(Bindings),Expected,Formula,pctl) :- !,
3752 format_with_colour_nl(user_output,[green],'PCTL Formula TRUE: ~w',[Formula]),
3753 format_with_colour_nl(user_output,[green],'PCTL Solutions: ~w~n',[Bindings]),
3754 flush_output(user_output),
3755 check_expected(true,Expected,pctl).
3756 check_status(incomplete,Expected,Formula,LTLorCTL) :- !,
3757 incomplete_warning(LTLorCTL,Warning),
3758 add_warning(Warning, 'Warning: Model Check incomplete for: ', Formula),nl,
3759 format('No counter example found so far for ~w.~n',[Formula]),
3760 check_expected(incomplete,Expected,LTLorCTL).
3761 check_status(NO,Expected,Formula,LTLorCTL) :- (NO=no ; NO=false),!, % TO DO: make uniform
3762 (Expected==false
3763 -> format_with_colour_nl(user_error,[red],'Model Check Counterexample found for: ~w',[Formula])
3764 ; add_error(LTLorCTL, 'Model Check Counterexample found for: ', Formula)
3765 ),
3766 cli_print_history,
3767 print('Formula '), print('FALSE.'),nl,
3768 debug_format(19,'Use -his FILE -his_option show_states to display states of counterexample~n',[]),
3769 nl,
3770 check_expected(false,Expected,LTLorCTL).
3771 check_status(Status,Expected,Formula,LTLorCTL) :-
3772 add_internal_error('Unknown status: ', check_status(Status,Expected,Formula,LTLorCTL)).
3773
3774 incomplete_warning(ltl,ltl_incomplete) :- !.
3775 incomplete_warning(ctl,ctl_incomplete) :- !.
3776 incomplete_warning(X,X).
3777
3778 :- if(environ(prob_release,true)).
3779
3780 run_benchmark(_, _, _) :-
3781 add_message(probcli, 'Command-line argument for benchmarking is not available in release mode.').
3782
3783 :- else.
3784
3785 :- use_module('../tests/smt_solver_benchmarks/alloy2b_benchmarks').
3786 :- use_module('../tests/smt_solver_benchmarks/smt_solver_benchmarks').
3787 run_benchmark(alloy, CmdName, AlloyFilePath) :-
3788 alloy2b_benchmarks:benchmark_alloy_command(CmdName, AlloyFilePath).
3789 run_benchmark(smt, bmc, Path) :-
3790 smt_solver_benchmarks:run_additional_bmc_benchmarks(false, [Path]), halt.
3791 run_benchmark(smt, cbc_deadlock, Path) :-
3792 smt_solver_benchmarks:run_additional_deadlock_benchmarks(false, [Path]), halt.
3793 run_benchmark(smt, cbc_inv, Path) :-
3794 smt_solver_benchmarks:run_additional_inductive_inv_benchmarks(false, [Path]), halt.
3795
3796 :- endif.
3797
3798 evaluate_from_commandline :-
3799 retractall(eval_result(_,_)),
3800 ? option(eval_string_or_file(A,B,Q,E,Rchk)), %print(eval(A,B,Q,E)),nl,
3801 % treat eval_string and eval_file together to ensure proper order of evaluation
3802 % (only possible side-effect at the moment: formula can add new machine_string facts)
3803 eval_string_or_file(A,B,Q,E,Rchk),
3804 fail.
3805 evaluate_from_commandline :- print_eval_results,
3806 % treat -repl option or -replay File option
3807 (option(eval_repl([File1|TF]))
3808 -> (repl_evaluate_expressions([File1|TF]) -> true ; true)
3809 ; start_repl_if_required).
3810 start_repl_if_required :-
3811 (option(eval_repl([]))
3812 -> (repl_evaluate_expressions([]) -> true ; true)
3813 ; true).
3814
3815 :- dynamic eval_result/2.
3816 add_eval_result(R) :- retract(eval_result(R,N)),!,
3817 N1 is N+1, assertz(eval_result(R,N1)).
3818 add_eval_result(R) :- assertz(eval_result(R,1)).
3819 print_eval_results :- findall(R/N, eval_result(R,N), L), sort(L,SL),
3820 (SL=[] -> true ; format('Evaluation results: ~w~n',[SL])).
3821
3822 :- use_module(tools_printing,[print_error/1, format_error_with_nl/2]).
3823 %eval_string_or_file(string,_String,_,'FALSE',_Recheck) :- !. % comment in to skip evalf
3824 eval_string_or_file(string,String,_,Expected,Recheck) :-
3825 set_current_probcli_command(eval_string(String)),
3826 (option(silent),nonvar(Expected) -> true
3827 ; nonvar(Expected) -> format('eval(~w): ~w~n',[Expected,String])
3828 ; format('eval: ~w~n',[String])
3829 ),
3830 reset_error_spans, % avoid underlining previous errors in eval_string
3831 (eval_string_with_time_out(String,StringResult,EnumWarning,_LS) -> true
3832 ; print_error('Eval string failed: '), print_error(String),
3833 error_occurred(eval_string)
3834 ),
3835 add_eval_result(StringResult),
3836 eval_check_result(StringResult,Expected,EnumWarning,eval_string,String),
3837 (Recheck=recheck(Mode) -> recheck_pp_of_last_expression(Mode,_,_) ; true),
3838 unset_current_probcli_command.
3839 eval_string_or_file(file(bench),File,Quantifier,Expected,Recheck) :- !,
3840 ( member(Solver,[prob,kodkod,sat,'sat-z3','z3', 'cdclt',clingo]),
3841 (eval_string_or_file(file(Solver),File,Quantifier,Expected,Recheck) -> fail)
3842 ; true).
3843 eval_string_or_file(file(Solver),File,Quantifier,Expected,_) :-
3844 % evaluate a single formula stored in a file
3845 set_current_probcli_command(eval_file(Solver,File)),
3846 turn_show_error_source_off, % reduce clutter in user feedback; eval_file used in ProB Logic Calculator for example
3847 formatsilent('~nEvaluating file: ~w~n',[File]),
3848 error_manager:reset_error_scopes, % TO DO: avoid that exceptions mess up error scopes in eval_string/file
3849 statistics(runtime,[Start,_]),
3850 statistics(walltime,[W1,_]),
3851 (Expected=='TRUE' -> TypeInfo=predicate(_) % avoids parsing as expression
3852 ; true),
3853 (eval_file(Solver,File,Quantifier,Result,EnumWarning,TypeInfo)
3854 -> statistics(walltime,[W2,_]), WT is W2-W1,
3855 translate_solver_result(Result,Infos),
3856 accumulate_file_infos(File,Solver,[walltime-WT|Infos]),
3857 add_eval_result(Result),
3858 eval_check_result(Result,Expected,EnumWarning,eval_file,File)
3859 ; statistics(walltime,[W2,_]), WT is W2-W1,
3860 accumulate_file_infos(File,Solver,[failure-1,false-0,true-0,unknown-1,walltime-WT]),
3861 add_eval_result(eval_file_failed),
3862 print_error('Eval from file failed: '), print_error(File),
3863 error_occurred(eval_file)
3864 ),
3865 statistics(runtime,[Stop,_]), Time is Stop - Start,
3866 debug_format(19,'Time for ~w : ~w ms (~w ms walltime)~n',[File,Time,WT]),
3867 turn_show_error_source_on,
3868 unset_current_probcli_command.
3869
3870 translate_solver_result('TRUE',I) :- !, I=[false-0,true-1,unknown-0].
3871 translate_solver_result('FALSE',I) :- !, I=[false-1,true-0,unknown-0].
3872 translate_solver_result('UNKNOWN',I) :- !,I=[false-0,true-0,unknown-1].
3873 translate_solver_result('**** TIME-OUT ****',I) :- !,I=[false-0,true-0,unknown-1].
3874 translate_solver_result(_,[false-0,true-0,unknown-1]). % we could record this as error
3875
3876 eval_check_result(StringResult,Expected,_,Origin,File) :- Expected\=StringResult,!,
3877 format_error_with_nl('! Evaluation error, expected result to be: ~w (but was ~w) in ~w',[Expected,StringResult,File]),
3878 error_occurred(Origin).
3879 eval_check_result('NOT-WELL-DEFINED',Expected,_,Origin,File) :- var(Expected),!,
3880 format_error_with_nl('! Evaluation NOT-WELL-DEFINED in ~w',[File]),
3881 error_occurred(Origin).
3882 eval_check_result(_,_,EnumWarning,_,_) :- eval_gen_enum_warning(EnumWarning).
3883
3884 eval_gen_enum_warning(false) :- !.
3885 eval_gen_enum_warning(time_out) :- !,error_occurred(eval_string_time_out).
3886 eval_gen_enum_warning(_) :- print_error('Enumeration warning occurred'),
3887 error_occurred(eval_string_enum_warning,warning).
3888 %repl :- repl_evaluate_expressions([]).
3889 :- use_module(parsercall,[ensure_console_parser_launched/0]).
3890 repl_evaluate_expressions(StartFiles) :-
3891 get_errors, % first clear any errors from earlier commands
3892 nl,
3893 print('ProB Interactive Expression and Predicate Evaluator '), nl,
3894 print('Type ":help" for more information.'),nl,
3895 turn_show_error_source_off, % reduce clutter in user feedback
3896 (option(evaldot(File))
3897 -> print('Solutions written to dot file: '), print(File),nl
3898 ; true
3899 ),
3900 (ensure_console_parser_launched
3901 -> maplist(prob_cli:set_repl_input_file(verbose),StartFiles),
3902 top_level_eval
3903 ; print_repl_prompt, write('ABORTING REPL'),nl),
3904 turn_show_error_source_on.
3905
3906 :- use_module(user_interrupts,[interruptable_call/1]).
3907 top_level_eval :-
3908 catch(top_level_eval1, halt(0), (format('~s', ["Bye."]), nl)).
3909
3910 :- use_module(tools_printing,[reset_terminal_colour/1, print_red/1, print_green/1,
3911 get_repl_prompt/1, get_repl_continuation_prompt/1]).
3912 print_repl_prompt :- get_repl_prompt(Prompt), write(Prompt),reset_terminal_colour(user_output).
3913 print_repl_prompt_s(_) :- option(silent),!.
3914 print_repl_prompt_s(P) :- print_repl_prompt(P).
3915 print_repl_prompt(P) :- reset_terminal_colour(user_output), write(P).
3916 %print_repl_prompt(P) :- tools_printing:start_terminal_colour(dark_gray,user_output), write(P), reset_terminal_colour(user_output).
3917
3918 top_level_eval1 :-
3919 (interruptable_call(eval1) -> true
3920 ; print_red('Evaluation failed or interrupted'),nl,
3921 print_repl_prompt('Use :q to quit REPL'),nl),
3922 reset_errors,
3923 top_level_eval1.
3924 eval0 :- store_last_error_location_for_repl,
3925 reset_errors, % get_errors prints errors again and quits in -strict mode
3926 % However, reset_errors means that in subsequent REPL runs errors are not printed again!!
3927 garbage_collect, eval1.
3928 eval1 :- repl_multi_read_line(Expr), eval_probcli_repl_line(Expr).
3929
3930 :- dynamic last_repl_error/2.
3931 store_last_error_location_for_repl :-
3932 retractall(last_repl_error(_,_)),
3933 check_error_span_file_linecol(_,File,Line,_,_,_),!,
3934 assertz(last_repl_error(File,Line)).
3935 store_last_error_location_for_repl.
3936
3937 :- dynamic current_repl_input_stream/2.
3938 close_repl_input_stream(file_closed) :- retract(current_repl_input_stream(X,File)),!,
3939 format(":replayed ~w~n",[File]),
3940 close(X).
3941 close_repl_input_stream(no_file).
3942 :- use_module(tools_io,[safe_open_file/4]).
3943 set_repl_input_file(_,File) :- current_repl_input_stream(_,File),!,
3944 add_error(set_repl_input_file,'Cyclic file replay: ',File).
3945 set_repl_input_file(Verbose,File) :-
3946 % close_repl_input_stream, % this way we allow one REPL file to call another
3947 safe_open_file(File,read,Stream,[encoding(utf8)]),!,
3948 (Verbose=verbose -> format('Replaying REPL commands in file: ~w~n',[File]) ; true),
3949 asserta(current_repl_input_stream(Stream,File)).
3950 set_repl_input_file(_,_).
3951
3952 repl_multi_read_line(Line) :-
3953 (current_repl_input_stream(Stream,_)
3954 -> repl_multi_read_line(Stream,Line),
3955 format(user_output,'~s~n',[Line])
3956 ; repl_multi_read_line(user_input,Line)
3957 ).
3958 repl_multi_read_line(Stream,Line) :-
3959 get_repl_prompt(Prompt),
3960 repl_multi_read_line_aux(Stream,Prompt,[],Line).
3961 repl_multi_read_line_aux(Stream,Prompt,SoFar,Line) :-
3962 prompt(OldPrompt,Prompt),
3963 call_cleanup(read_line(Stream,L), prompt(_,OldPrompt)),
3964 (L=end_of_file -> close_repl_input_stream(FileC),
3965 (SoFar=[], FileC = file_closed
3966 -> repl_multi_read_line(Line) % last line of file empty; do not process
3967 ; FileC = file_closed -> Line=SoFar
3968 ; Line=end_of_file) % user pressed CTRL-D
3969 ; append(LFront,[92],L) % line ends with slash \
3970 -> append(LFront,[10],LFront2), % insert newline instead;
3971 % note cleanup_newlines in parsercall transforms this into 8232 \x2028 Unicode
3972 append(SoFar,LFront2,NewSoFar),
3973 get_repl_continuation_prompt(NewPrompt),
3974 repl_multi_read_line_aux(Stream,NewPrompt,NewSoFar,Line)
3975 ; append(SoFar,L,Line)).
3976
3977 :- use_module(eval_strings).
3978 :- dynamic trace_eval/0.
3979
3980 generate_atom_list([],[],R) :- !, R=[].
3981 generate_atom_list([],Last,[NewAtom]) :-
3982 reverse(Last,RL),
3983 atom_codes(NewAtom,RL).
3984 generate_atom_list([39|X],[],[QuotedAtom|T]) :- !,
3985 get_quoted_atom(X,[],QuotedAtom,Rest),
3986 strip_leading_ws(Rest,X2),
3987 generate_atom_list(X2,[],T).
3988 generate_atom_list([32|X],Last,[NewAtom|T]) :- !,
3989 reverse(Last,RL),
3990 atom_codes(NewAtom,RL),
3991 strip_leading_ws(X,X2),
3992 generate_atom_list(X2,[],T).
3993 generate_atom_list([H|X],Last,Res) :- generate_atom_list(X,[H|Last],Res).
3994
3995 get_quoted_atom([],Acc,QuotedAtom,[]) :- reverse(Acc,R), atom_codes(QuotedAtom,R).
3996 get_quoted_atom([39|T],Acc,QuotedAtom,T) :- !, reverse(Acc,R), atom_codes(QuotedAtom,R).
3997 get_quoted_atom([H|T],Acc,QuotedAtom,Rest) :- get_quoted_atom(T,[H|Acc],QuotedAtom,Rest).
3998
3999
4000 strip_leading_ws([32|X],R) :- !, strip_leading_ws(X,R).
4001 strip_leading_ws(X,X).
4002
4003 :- meta_predicate call_probcli_option(0).
4004 call_probcli_option(_:Option) :- just_assert_option(Option), !,
4005 (option(Option) -> true ; assert_option(Option)).
4006 call_probcli_option(_:statistics) :- !, % avoid calling SICS version
4007 cli_print_statistics(full).
4008 call_probcli_option(Option) :-
4009 catch(call(Option), error(existence_error(A,B),E), (
4010 treat_existence_error(A,B,E,Option),
4011 nl % ensure that next prompt is printed
4012 )).
4013
4014 % commands that require no execution; just asserting option(.)
4015 just_assert_option(depth_first).
4016 just_assert_option(breadth_first).
4017 just_assert_option(strict_raise_error).
4018 just_assert_option(no_deadlocks).
4019 just_assert_option(no_invariant_violations).
4020 just_assert_option(no_goal).
4021 just_assert_option(no_ltl).
4022 just_assert_option(no_assertion_violations).
4023 just_assert_option(no_state_errors).
4024 just_assert_option(no_counter_examples).
4025
4026 treat_existence_error(source_sink,File,E,Option) :- !,
4027 format_with_colour_nl(user_error,[red],
4028 '* Could not find file ~w~n* for probcli command ~w~n* Detailed error: ~w',[File,Option,E]).
4029 treat_existence_error(_,_,E,Option) :-
4030 format_with_colour_nl(user_error,[red],
4031 '* probcli command not yet supported in REPL: ~w~n* Error: ~w',[Option,E]).
4032
4033 reload_mainfile :-
4034 file_loaded(_,MainFile),
4035 reset_errors,
4036 print_repl_prompt_s('Reloading and initialising file: '), print_repl_prompt_s(MainFile),nl,
4037 clear_loaded_files,
4038 load_main_file(MainFile,0,_),
4039 get_errors,
4040 cli_start_animation(0),
4041 cli_start_initialisation(0).
4042
4043 % REPL EVAL LOOP:
4044 eval_probcli_repl_line(end_of_file) :- !, eval_line(end_of_file).
4045 eval_probcli_repl_line(Line) :- strip_ws(Line,SLine),
4046 catch(eval_line(SLine), E, (
4047 E=halt(_) -> throw(E) % e.g., coming from :quit; will be caught above
4048 ; E='$aborted' -> throw(E) % thrown by SWI-Prolog on abort by user
4049 ; add_error(repl,'Uncaught Exception in REPL: ',E),
4050 nl % ensure that next prompt is printed
4051 )).
4052
4053 % strip whitespace at end and beginning
4054 strip_ws([H|T],Res) :- is_ws(H),!, strip_ws(T,Res).
4055 strip_ws(C,Res) :- reverse(C,CR), strip_ws2(CR,SCR), reverse(SCR,Res).
4056 strip_ws2([H|T],Res) :- is_ws(H),!, strip_ws2(T,Res).
4057 strip_ws2(R,R).
4058
4059 is_ws(32).
4060
4061 :- use_module(performance_messages,[toggle_perfmessages/0]).
4062 eval_line([]) :- !, print_repl_prompt('Type :q or :quit to quit.'),nl,eval0.
4063 eval_line(end_of_file) :- !, halt_exception(0).
4064 % Haskell GHCI like syntax
4065 eval_line(":r") :- !, eval_line("--reload").
4066 eval_line(":reload") :- !, eval_line("--reload").
4067 eval_line("--reload") :- !,
4068 (reload_mainfile -> true ; get_errors,print_repl_prompt('Error(s) occured during reload (use :e to jump to first error)'),nl),
4069 eval0.
4070 % TO DO: other Haskell commands :info E :l FILE , let pattern = expression
4071 eval_line(":prefs") :- !,print_eclipse_prefs, eval0.
4072 eval_line([45|Command]) :- % -command
4073 generate_atom_list([45|Command],[],ArgV),
4074 %print(argv(ArgV)),nl,
4075 % try and parse like commands passed to probcli
4076 get_options(ArgV,recognised_cli_option,Options,[],fail),
4077 print_repl_prompt('Executing probcli command: '),print_repl_prompt(Options),nl,!,
4078 (maplist(prob_cli:call_probcli_option,Options) -> true
4079 ; print_red('Failed to execute probcli arguments'),nl),
4080 eval0.
4081 eval_line("+") :- !, add_last_expression_to_unit_tests, eval0.
4082 eval_line("$+") :- !, preferences:temporary_set_preference(expand_avl_upto,-1,CHNG),
4083 print_last_value,preferences:reset_temporary_preference(expand_avl_upto,CHNG),
4084 eval0.
4085 %eval_line("$$") :- !, print_last_expression, eval0. % now in eval_strings
4086 eval_line("$$$") :- !, % $$0 - $$9 commands to print last expression with indentation
4087 indent_print_last_expression, eval0.
4088 %eval_line("$") :- !, print_last_info, eval0. % now in eval_strings
4089 eval_line("!trace") :- !, eval_line("^").
4090 eval_line("^") :- !,
4091 (retract(trace_eval) -> print_repl_prompt('TRACING OFF'),nl
4092 ; assertz(trace_eval), print_repl_prompt('TRACING ON'),nl), eval0.
4093 eval_line("!observe") :- !, toggle_observe_evaluation.
4094 eval_line("!v") :- !, tcltk_turn_debugging_off.
4095 eval_line("!p") :- !, toggle_perfmessages.
4096 eval_line("!perf") :- !, toggle_perfmessages.
4097 eval_line("!profile") :- !, eval_line("%").
4098 eval_line("!print_profile") :- !, eval_line("%%").
4099 eval_line("%") :- !, print_repl_prompt('PROFILING : '), %spy([avl:avl_size/2]),
4100 (current_prolog_flag(profiling,on)
4101 -> set_prolog_flag(profiling,off), print('OFF') ;
4102 set_prolog_flag(profiling,on), print('ON')),
4103 nl,print_repl_prompt('USE %% to print profile info'),nl,eval0.
4104 eval_line("%%") :- !, nl,print_repl_prompt('PROLOG PROFILE INFORMATION:'), nl,
4105 catch(print_profile,
4106 error(existence_error(_,_),_),
4107 print_red('CAN ONLY BE USED WHEN RUNNING PROB FROM SOURCE')),
4108 nl,
4109 debug:timer_statistics,
4110 eval0.
4111 eval_line("!print_coverage") :- !, nl,print_repl_prompt('PROLOG COVERAGE INFORMATION:'), nl,
4112 (current_prolog_flag(source_info,on) -> true ; print_red('Only useful when current_prolog_flag(source_info,on)!'),nl),
4113 catch(print_coverage,
4114 error(existence_error(_,_),_),
4115 print_red('CAN ONLY BE USED WHEN RUNNING PROB FROM SOURCE')),
4116 nl,
4117 eval0.
4118 eval_line("!profile_reset") :- !, nl,print_repl_prompt('RESETTING PROLOG PROFILE INFORMATION'), nl,
4119 catch(profile_reset,
4120 error(existence_error(_,_),_),
4121 print_red('CAN ONLY BE USED WHEN RUNNING PROB FROM SOURCE')),
4122 eval0.
4123 eval_line("%%%") :- !, nl,print('PROFILE INFORMATION (Starting TK Viewer):'), nl,
4124 catch(
4125 (use_module(library(gauge)), gauge:view),
4126 error(existence_error(_,_),_),
4127 print_red('CAN ONLY BE USED WHEN RUNNING PROB FROM SOURCE')),
4128 nl,
4129 eval0.
4130 eval_line("!debug") :- !,
4131 print_repl_prompt('ENTERING PROLOG DEBUG MODE:'),
4132 catch(
4133 debug,
4134 error(existence_error(_,_),_),
4135 print_red('CAN ONLY BE USED WHEN RUNNING PROB FROM SOURCE')),
4136 nl,
4137 eval0.
4138 eval_line("@") :- !, get_preference(find_abort_values,OldVal),
4139 print_repl_prompt('Try more aggressively to detect ill-defined expressions: '),
4140 (OldVal=true -> Val=false ; Val=true), print(Val),nl,
4141 temporary_set_preference(find_abort_values,Val) , eval0.
4142 eval_line("!") :- !, toggle_eval_det,eval0.
4143 eval_line("!norm") :- !, toggle_normalising,eval0.
4144 eval_line(Codes) :- parse_eval_command(Codes,CommandName,Argument),!,
4145 debug_println(9,executing_eval_command(CommandName,Argument)),
4146 (exec_eval_command(CommandName,Argument) -> eval0
4147 ; format_with_colour_nl(user_error,[red,bold],'Command ~w failed',[CommandName]),
4148 eval0).
4149 eval_line(ExpressionOrPredicate) :- (trace_eval -> trace ; true),
4150 (eval_codes(ExpressionOrPredicate,exists,_,_,_,_)
4151 -> eval0
4152 ; print_red('Evaluation failed'),nl,eval0).
4153
4154 parse_eval_command([C|Rest],CommandName,Argument) :- [C]=":",
4155 eval_command(Cmd,CommandName),
4156 append(Cmd,RestArg,Rest),
4157 (RestArg = [Letter1|_] -> is_ws(Letter1) /* otherwise command name continues */ ; true),
4158 strip_ws(RestArg,Argument),
4159 (eval_command_help(CommandName,[],_), Argument = [_|_]
4160 -> format_with_colour_nl(user_error,[red],'WARNING: Command ~w does not take arguments!',[CommandName])
4161 ; eval_command_help(CommandName,[_|_],_), Argument = []
4162 -> format_with_colour_nl(user_error,[red],'WARNING: Command ~w requires arguments!',[CommandName])
4163 ; true).
4164
4165 % TO DO: some of these commands should also be made available in the Tcl/Tk Console
4166 eval_command("q",quit).
4167 eval_command("quit",quit).
4168 eval_command("halt",quit).
4169 eval_command("x",exit).
4170 eval_command("exit",exit).
4171 eval_command("f",find).
4172 eval_command("find",find).
4173 eval_command("*",apropos).
4174 eval_command("apropos",apropos).
4175 eval_command("help",help).
4176 eval_command("h",help).
4177 eval_command("?",help).
4178 eval_command("ctl",ctl(init)). % :ctl
4179 eval_command("ctlh",ctl(starthere)). % :ctlh
4180 eval_command("ltl",ltl(init)). % :ltl
4181 eval_command("ltlh",ltl(starthere)). % :ltlh
4182 eval_command("pctl",pctl(init)). % :pctl
4183 eval_command("pctlh",pctl(starthere)). % :pctlh
4184 eval_command("reset",reset_animator(hard)). % :reset
4185 eval_command("reset-history",reset_animator(history_only)). % :reset
4186 eval_command("statistics",statistics).
4187 eval_command("stats",statistics). % :stats
4188 eval_command("states",state_space_stats). % :states
4189 eval_command("state",show_state_info(2000)). % :state
4190 eval_command("statespace",state_space_display). % :statespace
4191 eval_command("u",unsat_core).
4192 %eval_command("core",unsat_core).
4193 eval_command("show",show_last_as_table). % :show
4194 eval_command("dot",show_last_as_dot(no_dot_viewing)). % :dot
4195 eval_command("dotty",show_last_as_dot(dotty)).
4196 eval_command("dotpdf",show_last_as_dot(dot)).
4197 eval_command("sfdp",show_last_as_dot(sfdp)).
4198 eval_command("browse",browse). % :browse
4199 eval_command("abstract_constants",check_abstract_constants). % :abstract_constants
4200 eval_command("det_check_constants",det_check_constants). % :det_check_constants
4201 eval_command("b",browse).
4202 eval_command("hbrowse",hbrowse). % :hbrowse browse hiearchy
4203 eval_command("hshow",hshow). % show inclusion hieararchy
4204 eval_command("comp",show_components). % :comp
4205 eval_command("replay",replay_repl_file). % :replay
4206 eval_command("trim",trimcore). % :trim
4207 eval_command("src",show_source). %:src
4208 eval_command("source",show_source). %:source
4209 eval_command("origin",show_origin). %:origin
4210 eval_command("edit",edit_main_file).
4211 eval_command("e",edit_main_file). % :e
4212 eval_command("comment",comment).
4213 eval_command("machine",show_machine_info(statistics)). %:machine
4214 eval_command("machine-stats",show_machine_info(statistics)). %:machine
4215 eval_command("files",show_machine_info(files)). %:files
4216 eval_command("syntax",syntax_help). % :syntax
4217 eval_command("open",open_file). % :open
4218
4219 available_commands(SLC) :-
4220 findall(Cmd,(eval_command(Cs,_),atom_codes(Cmd,[58|Cs])), LC),
4221 sort(LC,SLC).
4222
4223 eval_command_help(exit,[],'Exit ProB').
4224 eval_command_help(find,['P'],'Find state in state-space which makes LTL atomic proposition P true; LTL Propositions: {B-Pred}, e(Op), [Op], true, false, sink').
4225 eval_command_help(ltl(starthere),['F'],'Check LTL formula F starting from current state').
4226 eval_command_help(ltl,['F'],'Check LTL formula F; LTL Operators: G,F,X,U,W,R,not,&,or,=>; LTL Propositions: {B-Pred}, e(Op), [Op], true, false, sink; Past-LTL Operators: Y,H,O,S,T (dual to X,G,F,U,R)').
4227 eval_command_help(ctl(starthere),['F'],'Check CTL formula F starting from current state').
4228 eval_command_help(ctl(_),['F'],'Check CTL formula F in all initial states; CTL Syntax: ExUy,EXx,AXx,EFx,AGx,EX[Op]x,e(Op),{B-Pred}').
4229 eval_command_help(pctl(starthere),['F'],'Check PCTL formula F starting from current state').
4230 eval_command_help(pctl(_),['F'],'Check PCTL formula F; PCTL Operators: not, &, or, =>, {B-Pred}, e(Op), [Op], true, false, sink, P op {Exp} [PathFormula] with op in {<,<=,>=,>,=}; Path operators: X, U, F, G, U<=Bound, F<=Bound, G<=Bound').
4231 eval_command_help(browse,opt('PAT'),'Browse available constants, variables, sets and lets introduced in REPL').
4232 eval_command_help(apropos,['PAT'],'Find constant or variable whose names contains PAT').
4233 eval_command_help(hbrowse,['PAT'],'Browse machine hierarchy for all identifiers whose names contains PAT').
4234 eval_command_help(hshow,[],'Show machine inclusion hierarchy using topological sorting').
4235 eval_command_help(show_components,[],'Show components of PROPERTIES').
4236 eval_command_help(abstract_constants,[],'Show ABSTRACT_CONSTANTS and check if can be fully evaluated').
4237 eval_command_help(det_check_constants,[],'Check if values of CONSTANTS are forced and explain if they are').
4238 eval_command_help(show_last_as_table,[],'Show last evaluated expression in tabular form').
4239 eval_command_help(show_last_as_dot(_),['F'],'Show expression or predicate F as dot graph').
4240 eval_command_help(unsat_core,[],'Compute Unsatisfiable Core of last evaluated predicate').
4241 eval_command_help(help,opt('CMD'),'Provide help about REPL command CMD').
4242 eval_command_help(replay_repl_file,['FILE'],'Replay FILE of REPL commands').
4243 eval_command_help(reset_animator(_),[],'Reset history and statespace of animator').
4244 eval_command_help(show_source,['ID'],'Show origin and source code definition of identifier ID').
4245 eval_command_help(show_origin,['ID'],'Show origin of identifier ID and try opening in EDITOR').
4246 eval_command_help(show_machine_info(_),[],'Show statistics about loaded machine and files').
4247 eval_command_help(state_space_stats,[],'Show statistics about state space').
4248 eval_command_help(state_space_display,[],'Show complete state space transitions (could be very big !)').
4249 eval_command_help(show_state_info(_),[],'Show current state').
4250 eval_command_help(statistics,[],'Show statistics about last evaluation').
4251 % -machine_stats : cli_print_machine_info(statistics) -machine_files : cli_print_machine_info(files)
4252 eval_command_help(trim,[],'Trim memory usage of probcli (try and give memory back to the OS)').
4253 % implemented in eval_strings:
4254 eval_command_help(type,['E'],'Show type of expression E').
4255 eval_command_help(cvc4,['P'],'Solve predicate P using CVC4 solver').
4256 eval_command_help(kodkod,['P'],'Solve predicate P using SAT solver via Kodkod').
4257 eval_command_help(z3,['P'],'Solve predicate P using Z3 solver').
4258 eval_command_help('z3-free',['P'],'Solve predicate P using Z3 solver (ignoring current state)').
4259 eval_command_help('z3-file',['F'],'Solve predicate in File F using Z3 solver').
4260 eval_command_help('z3-free-file',['F'],'Solve predicate in File F using Z3 solver (ignoring current state)').
4261 eval_command_help(cdclt,['P'],'Solve predicate P using Prolog CDCL(T) solver').
4262 eval_command_help(cdclt-free,['P'],'Solve predicate P using Prolog CDCL(T) solver (ignoring current state)').
4263 eval_command_help(prob,['P'],'Solve predicate P using ProB solver (ignoring current state)').
4264 eval_command_help('prob-file',['F'],'Solve predicate in File F using ProB solver (ignoring current state)').
4265 eval_command_help(edit_main_file,opt('ID'),'Edit main file (or origin of identifier ID) using EDITOR (path_to_text_editor preference)').
4266 eval_command_help(comment,['STRING'],'provide STRING as a comment (mainly useful for :replay files)').
4267 eval_command_help(syntax_help,[],'Show a summary of the B syntax accepted by the REPL').
4268 eval_command_help(open_file,['FILE'],'Open FILE in preferred application.').
4269
4270 print_eval_command_help(Codes) :-
4271 eval_command(Codes,Cmd),
4272 eval_command_help(Cmd,Args,Descr),
4273 (Args = []
4274 -> format('Command ~w~n Syntax :~s~n ~w~n',[Cmd,Codes,Descr])
4275 ; Args=[Arg] -> format('Command ~w~n Syntax :~s ~w~n ~w~n',[Cmd,Codes,Arg,Descr])
4276 ; Args=opt(Arg) -> format('Command ~w~n Syntax :~s [~w]~n ~w~n',[Cmd,Codes,Arg,Descr])
4277 ; format('Command ~w~n Syntax :~s ~w~n ~w~n',[Cmd,Codes,Args,Descr])).
4278
4279 :- use_module(tools_commands,[show_dot_file/1, show_pdf_file/1, gen_dot_output/4]).
4280 :- use_module(state_space,[transition/4]).
4281 :- use_module(b_machine_hierarchy,[print_machine_topological_order/0]).
4282 exec_eval_command(quit,_) :- !, halt_exception(0).
4283 exec_eval_command(exit,_) :- !,halt.
4284 exec_eval_command(browse,CodesToMatch) :- !,
4285 (CodesToMatch=[] -> browse % maybe merge with apropos functionality
4286 ; exec_eval_command(apropos,CodesToMatch)).
4287 exec_eval_command(find,FORMULA) :-
4288 atom_codes(APF,FORMULA),cli_find_ltl_ap(APF).
4289 exec_eval_command(apropos,CodesToMatch) :- /* :* Pattern (apropos command) */
4290 browse_machine(CodesToMatch).
4291 exec_eval_command(hbrowse,CodesToMatch) :- /* :* Pattern (hbrowse command) */
4292 browse_all_machines(CodesToMatch).
4293 exec_eval_command(hshow,_) :- /* show inclusion hierarhcy */
4294 print_machine_topological_order.
4295 exec_eval_command(show_components,_) :-
4296 print_property_partitions.
4297 exec_eval_command(check_abstract_constants,_) :-
4298 check_abstract_constants.
4299 exec_eval_command(det_check_constants,_) :-
4300 det_check_constants.
4301 exec_eval_command(help,Arg) :-
4302 (Arg=[] -> eval_help
4303 ; print_eval_command_help(Arg) -> true
4304 ; (Arg=[58|RA],print_eval_command_help(RA)) -> true % remove : at front
4305 ; format('Cannot provide help about ~s~n',[Arg]),
4306 available_commands(LC), format('Available commands: ~w~n',[LC])
4307 ).
4308 exec_eval_command(ctl(Mode),FORMULA) :- % :ctl or :ctlh for ctl here
4309 atom_codes(F,FORMULA),
4310 (cli_ctl_model_check(F,Mode,_,Status)
4311 -> (Status=false -> write_history_to_user_output([show_init,show_states]) ; true)
4312 ; print('CTL Syntax: ExUy,EXx,AXx,EFx,AGx,EX[Op]x,e(Op),{B-Pred}'),nl).
4313 exec_eval_command(ltl(Mode),FORMULA) :- % :ltl or :ltlh with Mode = init or starthere
4314 atom_codes(F,FORMULA),
4315 (cli_ltl_model_check(F,Mode,_,Status)
4316 -> (Status=no -> write_history_to_user_output([show_init,show_states]) ; true)
4317 ; print('LTL Operators: G,F,X,U,W,R,not,&,or,=>,<=>'),nl,
4318 print('LTL Propositions: {B-Pred}, e(Op), [Op], true, false, sink'),nl,
4319 print('Past-LTL Operators: Y,H,O,S,T (dual to X,G,F,U,R)'),nl
4320 ).
4321 exec_eval_command(pctl(Mode),FORMULA) :- % :pctl or :pctlh with Mode = init or starthere
4322 atom_codes(F,FORMULA),
4323 (cli_pctl_model_check(F,Mode,_,Status)
4324 -> (Status=no -> write_history_to_user_output([show_init,show_states]) ; true)
4325 ; print('PCTL Propositional Operators: not, &, or, =>'),nl,
4326 print('PCTL State Formula: P op {Exp} [PathFormula] with op in {<,<=,>=,>,=}'),nl,
4327 print('PCTL Path Formulas: X phi, phi1 U phi2, F phi, G phi'),nl,
4328 print('PCTL Bounded Path Formulas: phi1 U<=Bound phi2, F<=Bound phi, G<=Bound phi'),nl,
4329 print('PCTL Propositions: {B-Pred}, e(Op), [Op], true, false, sink'),nl
4330 ).
4331 exec_eval_command(reset_animator(Hard),_) :- !,
4332 get_state_space_stats(TotalNodeSum,TotalTransSum,_,_),
4333 (Hard=hard ->
4334 format('Resetting statespace (~w states, ~w transitions)~n',[TotalNodeSum,TotalTransSum]),
4335 reset_animator
4336 ; format('Resetting animation history (keeping statespace: ~w states, ~w transitions)~n',[TotalNodeSum,TotalTransSum]),
4337 tcltk_reset % only resets animation history,...
4338 ).
4339 exec_eval_command(statistics,_) :- !, print_last_info.
4340 exec_eval_command(state_space_stats,_) :- !, % :states
4341 get_state_space_stats(TotalNodeSum,TotalTransSum,Processed,Ignored),
4342 (Ignored>0
4343 -> format('Statespace: ~w states (~w processed, ~w ignored) and ~w transitions.~n',
4344 [TotalNodeSum,Processed,Ignored,TotalTransSum])
4345 ; format('Statespace: ~w states (~w processed) and ~w transitions.~n',[TotalNodeSum,Processed,TotalTransSum])).
4346 exec_eval_command(state_space_display,_) :- !, % :statespace
4347 ( visited_expression(ID,State),
4348 functor(State,F,N),
4349 format('State ID ~w (~w/~w)~n',[ID,F,N]),
4350 transition(ID,OperationTerm,_OpID,ToID),
4351 get_operation_name(OperationTerm,OpName),
4352 format(' -> ~w (~w)~n',[ToID,OpName]),
4353 fail
4354 ;
4355 current_state_id(ID),
4356 format('Current State ID ~w~n',[ID])
4357 ).
4358 exec_eval_command(show_state_info(Limit),_) :- !, % :state
4359 (current_expression(ID,CurState)
4360 ->
4361 expand_const_and_vars_to_full_store(CurState,EState),
4362 format('Current state id ~w : ~n',[ID]), % MAX_DISPLAY_SET
4363 translate:print_bstate_limited(EState,Limit,-1),nl,
4364 (\+ not_all_transitions_added(ID),
4365 format('Outgoing transitions of state id ~w:~n',[ID]),
4366 transition(ID,OperationTerm,_OpID,ToID),
4367 get_operation_name(OperationTerm,OpName),
4368 format(' -> ~w (~w)~n',[ToID,OpName]),
4369 fail
4370 ; true)
4371 ; print_red('No current state available!'),nl
4372 ).
4373 exec_eval_command(unsat_core,_) :- !, % :core :u
4374 unsat_core_last_expression.
4375 exec_eval_command(trimcore,_) :- !, % :trim
4376 prob_trimcore_verbose.
4377 exec_eval_command(show_last_as_table,_) :- !, % :show
4378 show_last_expression_as_table.
4379 exec_eval_command(syntax_help,_) :- !, % :syntax
4380 syntax_help.
4381 exec_eval_command(show_last_as_dot(Show),Arg) :- !,
4382 (Arg = [] -> print('*** :dot requires an expression or predicate as argument.'),nl
4383 ; safe_absolute_file_name('~/probcli_repl.dot',AFile),
4384 set_eval_dot_file(AFile),
4385 format('Displaying evaluation result in: ~w~n',[AFile]),
4386 (eval_codes(Arg,exists,_,_,_,_) -> true ; true), unset_eval_dot_file,
4387 ( Show=no_dot_viewing -> true
4388 ; Show=dotty -> show_dot_file(AFile)
4389 ; safe_absolute_file_name('~/probcli_repl.pdf',PDFFile),
4390 gen_dot_output(AFile,Show,pdf,PDFFile),
4391 show_pdf_file(PDFFile)
4392 )).
4393 exec_eval_command(replay_repl_file,FILEC) :- !, % :replay
4394 atom_codes(File,FILEC),
4395 set_repl_input_file(not_verbose,File).
4396 exec_eval_command(show_source,IDC) :- !, % :src
4397 trim_id_back_quotes(IDC,TIDC),atom_codes(ID,TIDC),
4398 show_source(ID).
4399 exec_eval_command(show_origin,IDC) :- !, % :origin
4400 trim_id_back_quotes(IDC,TIDC),atom_codes(ID,TIDC),
4401 show_origin(ID).
4402 exec_eval_command(show_machine_info(X),_) :- !, % :machine
4403 cli_print_machine_info(X).
4404 exec_eval_command(edit_main_file,Arg) :- !, % :e
4405 (Arg=[] -> edit_main_file
4406 ; trim_quotes(Arg,FC), atom_codes(File,FC), file_exists(File) -> edit_file(File,unknown)
4407 ; exec_eval_command(show_origin,Arg)).
4408 exec_eval_command(open_file,FILEC) :- !, % :open
4409 (FILEC=[] -> open_file('.')
4410 ; atom_codes(File,FILEC),
4411 open_file(File)
4412 ).
4413 exec_eval_command(comment,_Arg) :- !. % do nothing; argument was a comment; mainly useful for :replay files
4414
4415
4416 trim_id_back_quotes([96|T],Res) :- append(Res,[96],T),!.
4417 trim_id_back_quotes(R,R).
4418
4419 trim_quotes([34|T],Res) :- append(Res,[34],T),!. % double quotes
4420 trim_quotes([39|T],Res) :- append(Res,[39],T),!. % single quotes
4421 trim_quotes(R,R).
4422
4423 :- use_module(tools_commands,[edit_file/2, open_file/1]).
4424 edit_main_file :- last_repl_error(File,Line),
4425 \+ functor(File,unknown,_), % File \= unknown(_),
4426 !,
4427 format('Showing first error from last command~n',[]),
4428 edit_file(File,Line).
4429 % Note: for the bbedit command we can also specify line numbers bbedit +LINE FILE
4430 edit_main_file :- file_loaded(_,MainFile), \+ empty_machine_loaded,
4431 !,edit_file(MainFile,unknown).
4432 edit_main_file :- format_with_colour_nl(user_error,[red],'No file loaded, cannot open EDITOR!',[]).
4433
4434
4435
4436 :- use_module(probsrc(error_manager),[extract_file_line_col/6]).
4437 open_file_at_position(OriginTerm) :-
4438 extract_file_line_col(OriginTerm,FILE,LINE,_COL,_Erow,_Ecol),
4439 edit_file(FILE,LINE).
4440
4441
4442 :- use_module(probsrc(bmachine),[source_code_for_identifier/6]).
4443 show_source(ID) :- source_code_for_identifier(ID,Kind,_Type,OriginStr,OriginTerm,Source),!,
4444 translate:translate_subst_or_bexpr(Source,PPS),
4445 %format('~w: ~w (Type: ~w)~norigin: ~w~nsource: ~w~n',[Kind,ID,_Type,Origin,PPS]).
4446 format('~w: ~w~norigin: ~w~nsource: ~w~n',[Kind,ID,OriginStr,PPS]),
4447 (OriginTerm=b(_,_,_),get_texpr_description(OriginTerm,Description)
4448 -> format('description: ~w~n',[Description]) ; true).
4449 show_source(ID) :- format_error_with_nl('! Could not find source for ~w',[ID]).
4450
4451 show_origin('') :- last_repl_error(_,_),!, % error occured: show error in editor like :e would
4452 edit_main_file.
4453 show_origin('') :- !,format_error_with_nl('! You need to provided an identifier',[]).
4454 show_origin(ID) :- source_code_for_identifier(ID,Kind,_Type,OriginStr,OriginTerm,_Source),!,
4455 format('~w: ~w~norigin: ~w~n',[Kind,ID,OriginStr]),
4456 open_file_at_position(OriginTerm).
4457 show_origin(ID) :- format_error_with_nl('! Could not find origin for ~w',[ID]).
4458
4459 profiling_on :- set_prolog_flag(profiling,on), print('% PROFILING ON'),nl.
4460 profiling_off :- set_prolog_flag(profiling,off), print('% PROFILING OFF'),nl.
4461
4462 % find a state satisfying LTL atomic property
4463 cli_find_ltl_ap(APF) :-
4464 if(ltl:find_atomic_property_formula(APF,ID),
4465 (format('Found state (id = ~w) satisfying LTL atomic property.~n',[ID]),
4466 tcltk_goto_state('LTL FIND',ID)),
4467 format('No explored state satsifies LTL atomic property.~n',[])).
4468
4469 eval_help :-
4470 print('ProB Interactive Expression and Predicate Evaluator '), nl,
4471 print('Type a valid B expressions or predicates, followed by RETURN or ENTER.'),nl,
4472 print('You can spread input over multiple lines by ending lines with "\\".'),nl,
4473 browse_machine([]),
4474 print('You can also type one of the following commands: '),nl,
4475 (option_verbose ->
4476 print(' + to save last expression to ProB unit tests.'),nl,
4477 print(' ! to go to deterministic propagation only mode.'),nl,
4478 print(' $ to print evaluation time for last expression.'),nl,
4479 print(' $$ to pretty-print last expression and its type.'),nl,
4480 print(' $$$ to pretty-print last expression in nested fashion.'),nl,
4481 print(' !p to toggle performance messages.'),nl,
4482 print(' !norm to toggle normalisation of results.'),nl,
4483 print(' :col to toggle colorizing of results.'),nl
4484 ; true),
4485 print(' :let x = E to define a new local variable x'),nl, % : optional for let
4486 print(' :unlet x to un-define a local variable'),nl,
4487 print(' #file=MYFILE to evaluate the formula in MYFILE'),nl,
4488 print(' @INVARIANT to evaluate or obtain invariant predicate'),nl,
4489 print(' @PROPERTIES, @GUARD-OpName ditto for properties and guards'),nl, % @FUZZ, @RANDOMISE also exist
4490 print(' :b or :b Prefix to browse the available identifiers'),nl,
4491 print(' :t E to get the type of an expression'),nl,
4492 print(' :r to reload the machine'),nl,
4493 print(' :show to display the last result as a table (if possible)'),nl,
4494 print(' :list CAT to display information with CAT : {files,variables,help,...}'),nl,
4495 print(' :* P to display constants/variables containing pattern P'),nl,
4496 print(' :core Pred to compute the unsat core for Pred'),nl,
4497 print(' :u to compute the unsat core for last evaluated result'),nl,
4498 print(' :stats to print the type and evaluation time for last query'),nl,
4499 print(' -PROBCLIARGS to pass command-line probcli arguments to the REPL'),nl,
4500 print(' (e.g., -v to switch to verbose mode or -p PREF VAL to set a preference)'),nl,
4501 print(' :ctl F or :ltl F to check a CTL or LTL formula.'),nl,
4502 print(' :f F to find a state satisfying LTL atomic property.'),nl,
4503 print(' :find-value PAT to find a value in current state matching PAT.'),nl,
4504 print(' :exec S to execute an operation or substitution S.'),nl,
4505 print(' :replay FILE to replay a file of commands.'),nl,
4506 print(' :z3 P, :cvc4 P, :kodkod P to solve predicate P using alternate solver'),nl,
4507 print(' :forall P to prove predicate P as universally quantified with default solver'),nl,
4508 print(' :prove P to prove predicate P using ProB\'s own WD prover'),nl,
4509 (option_verbose ->
4510 print(' :krt P, :pp P, :ml P to prove predicate P using Atelier-B provers if installed'),nl
4511 ; true),
4512 print(' :print P to pretty print predicate in a nested fashion'),nl,
4513 print(' :min P, :max P to find a minimal/maximal model for predicate P or %x.(P|E)'),nl,
4514 print(' :prefs to print current value of preferences'),nl,
4515 print(' :reset to reset the state space of the animator.'),nl, % :reset-history only resets history
4516 print(' :help CMD to obtain more help about a command.'),nl,
4517 print(' :state, :statespace, :states,'),nl,
4518 print(' :machine, :files, :source, :orgin, :machine-stats,'),nl,
4519 print(' :apropos, :hbrowse, :abstract_constants, :det_check_constants,'),nl,
4520 print(' :dot, :dotty, :sfdp, :trim, :comp - use :help CMD for more info'),nl,
4521 print(' :syntax to show a summary of the B syntax accepted by the REPL'),nl,
4522 print(' :q to exit.'),nl.
4523
4524 :- use_module(tools,[read_atom_from_file/3]).
4525 :- dynamic prob_summary/1.
4526
4527 :- read_atom_from_file(tclsrc('prob_summary.txt'),utf8,T), assertz(prob_summary(T)).
4528 % TODO: we could just include a shorter version with predicates and expressions
4529 % TODO: provide :syntax LTL or :syntax CTL help commands
4530 syntax_help :- prob_summary(S),
4531 format(user_output,'~w',S).
4532
4533
4534 browse :- browse_machine([]), browse_repl_lets.
4535
4536 :- use_module(bmachine,[get_machine_identifiers/2]).
4537 % the CodesToMatch parameters mimics the apropos command of the Clojure-REPL
4538 browse_machine(CodesToMatch) :-
4539 get_machine_identifiers(machines,MN), display_match('MACHINES',CodesToMatch,MN),
4540 (CodesToMatch =[] -> print_sets
4541 ; get_machine_identifiers(sets,SN), display_match('SETS',CodesToMatch,SN),
4542 get_machine_identifiers(set_constants,SCN), display_match('SETS-ELEMENTS',CodesToMatch,SCN)
4543 ),
4544 get_machine_identifiers(definition_files,DFN),
4545 (DFN=[] -> true ; display_match('DEFINITIONS FILES',CodesToMatch,DFN)),
4546 get_machine_identifiers(definitions,DN),
4547 (DN=[] -> true ; display_match('DEFINITIONS',CodesToMatch,DN)),
4548 get_machine_identifiers(constants,CN),
4549 display_match('CONSTANTS',CodesToMatch,CN),
4550 get_machine_identifiers(variables,VN),
4551 display_match('VARIABLES',CodesToMatch,VN),
4552 get_machine_identifiers(operations,Ops),
4553 display_match('OPERATIONS',CodesToMatch,Ops).
4554
4555 display_match(KIND,CodesToMatch,Ids) :- display_match(KIND,CodesToMatch,Ids,show_empty).
4556 display_match(KIND,CodesToMatch,Ids,ShowEmpty) :-
4557 include(prob_cli:atom_contains_codes(CodesToMatch),Ids,MatchingIds),
4558 length(MatchingIds,LenMIds),
4559 (LenMIds=0, ShowEmpty=show_only_if_match -> true
4560 ; sort(MatchingIds,SMatchingIds),
4561 (CodesToMatch=[]
4562 -> format(' ~w: ~w ~w~n',[KIND,LenMIds,SMatchingIds])
4563 ; length(Ids,LenIds),
4564 format('Matching ~w: ~w/~w ~w~n',[KIND,LenMIds,LenIds,SMatchingIds]))
4565 ).
4566
4567 % check if an atom contains a list of codes in its name
4568 atom_contains_codes([],_) :- !.
4569 atom_contains_codes(Codes,Name) :- atom_codes(Name,NC),
4570 append([_,Codes,_],NC).
4571
4572 :- use_module(b_global_sets,[b_global_set/1]).
4573 print_sets :- print('Available SETS: '), b_global_set(GS), print_set(GS),fail.
4574 print_sets :- nl.
4575
4576 :- use_module(probsrc(b_global_sets),[is_b_global_constant/3]).
4577 print_set(GS) :- print(GS), \+ is_b_global_constant(GS,_,_),!, print(' ').
4578 print_set(GS) :- print(' = {'), is_b_global_constant(GS,_,Cst), print(Cst), print(' '),fail.
4579 print_set(_) :- print(' } ').
4580
4581 :- use_module(b_machine_hierarchy,[get_machine_identifier_names/7]).
4582 % browse all machines, shows identifiers maybe not visible at top-level
4583 browse_all_machines(CodesToMatch) :-
4584 format('Searching machine hierarchy for identifiers matching ~s~n',[CodesToMatch]),
4585 get_machine_identifier_names(Name,Params,Sets,AVars,CVars,AConsts,CConsts),
4586 format('~nMACHINE ~w~n',[Name]),
4587 display_match('PARAMS',CodesToMatch,Params,show_only_if_match),
4588 display_match('SETS',CodesToMatch,Sets,show_only_if_match),
4589 display_match('ABSTRACT_VARIABLES',CodesToMatch,AVars,show_only_if_match),
4590 display_match('CONCRETE_VARIABLES',CodesToMatch,CVars,show_only_if_match),
4591 display_match('ABSTRACT_CONSTANTS',CodesToMatch,AConsts,show_only_if_match),
4592 display_match('CONCRETE_CONSTANTS',CodesToMatch,CConsts,show_only_if_match),
4593 fail.
4594 browse_all_machines(_).
4595
4596
4597 :- use_module(bmachine,[b_get_properties_from_machine/1]).
4598 print_property_partitions :- print('PARTITIONS OF PROPERTIES'),nl,
4599 b_get_properties_from_machine(Properties),
4600 predicate_components(Properties,Comp),
4601 length(Comp,Len), print(Len), print(' components found in PROPERTIES'),nl,
4602 nth1(Nr,Comp,component(P,Vars)),
4603 format('~n& // Component ~w/~w over identifiers ~w~n',[Nr,Len,Vars]),
4604 translate:print_bexpr(P),nl,fail.
4605 print_property_partitions :- nl, print(' ============== '),nl.
4606
4607 :- use_module(store,[lookup_value_for_existing_id/3]).
4608 :- use_module(b_machine_hierarchy,[abstract_constant/2]).
4609 check_abstract_constants :-
4610 format('Checking whether abstract constants can be expanded:~n',[]),
4611 current_expression(_ID,CurState),
4612 expand_const_and_vars_to_full_store(CurState,EState),
4613 abstract_constant(AID,_),
4614 lookup_value_for_existing_id(AID,EState,Val),
4615 get_value_type(Val,VF),
4616 format(user_output,'~n*** Evaluating ABSTRACT_CONSTANT (stored value: ~w):~n',[VF]),
4617 format_with_colour_nl(user_output,[blue],' ~w',[AID]),
4618 (debug_mode(off) -> true
4619 ; translate:translate_bvalue(Val,VS), format_with_colour_nl(user_output,[blue],' Stored value = ~w',[VS])),
4620 atom_codes(AID,C),
4621 % TO DO: provide info if value symbolic and can be expanded fully + add timing
4622 % term_size, unique in state space
4623 % this command is deprecated compared to -csv constants_analysis (i.e., tcltk_analyse_constants)
4624 eval_codes(C,exists,_,_EnumWarning,_LS,_),nl, % TO DO: call try_expand_and_convert_to_avl_with_check(Val)
4625 fail.
4626 check_abstract_constants.
4627
4628 :- use_module(probsrc(custom_explicit_sets),[is_interval_closure/3]).
4629 get_value_type(CS, Res) :- is_interval_closure(CS,_,_),!, Res = 'interval closure'.
4630 get_value_type(closure(_,_,_),Res) :- !, Res= 'symbolic closure'.
4631 get_value_type(avl_set(_), Res) :- !, Res= 'explicit AVL set'.
4632 get_value_type(Val,VF) :- functor(Val,VF,_).
4633
4634 :- use_module(b_state_model_check,[cbc_constants_det_check/1]).
4635 det_check_constants :- \+ current_state_corresponds_to_setup_constants_b_machine, !,
4636 format_with_colour_nl(user_error,[red],'This command requires to setup the constants first!',[]).
4637 det_check_constants :-
4638 current_state_id(ID),
4639 %format('Checking whether constants are forced in state ~w:~n',[ID]),
4640 cbc_constants_det_check(ID).
4641
4642 % showing relations as tables:
4643
4644 :- use_module(extrasrc(table_tools),[print_value_as_table/2]).
4645 show_last_expression_as_table :- \+ last_expression(_,_Expr),!,
4646 print_red('Please evaluate an expression or predicate first.'),nl.
4647 show_last_expression_as_table :-
4648 get_last_result_value(Expr,_,Value),
4649 print_value_as_table(Expr,Value).
4650
4651
4652 % a few definitions so that probcli commands work in REPL:
4653 :- use_module(specfile,[get_internal_representation/1]).
4654 :- use_module(tools_files,[write_to_utf8_file_or_user_output/2]).
4655 :- use_module(translate,[set_unicode_mode/0, unset_unicode_mode/0, set_atelierb_mode/1, unset_atelierb_mode/0, with_translation_mode/2]).
4656 :- public pretty_print_internal_rep/4, pretty_print_internal_rep_to_B/1.
4657 pretty_print_internal_rep(PPFILE,MachName,TYPES,TransMode) :-
4658 b_or_z_mode, !,
4659 pretty_print_internal_rep_b(PPFILE,MachName,TYPES,TransMode).
4660 pretty_print_internal_rep(PPFILE,_MachName,_TYPES,TransMode) :-
4661 with_translation_mode(TransMode,get_internal_representation(PP)),
4662 write_to_utf8_file_or_user_output(PPFILE,PP).
4663
4664 pretty_print_internal_rep_b(PPFILE,MachName,TYPES,unicode) :- !,
4665 set_unicode_mode,
4666 call_cleanup(b_write_machine_representation_to_file(MachName,TYPES,PPFILE),unset_unicode_mode).
4667 pretty_print_internal_rep_b(PPFILE,'$auto',_TYPES,atelierb) :- animation_minor_mode(eventb),!,
4668 b_write_eventb_machine_to_classicalb_to_file(PPFILE). % old -ppB option:
4669 pretty_print_internal_rep_b(PPFILE,MachName,TYPES,atelierb) :- !,
4670 set_atelierb_mode(native),
4671 call_cleanup(b_write_machine_representation_to_file(MachName,TYPES,PPFILE),unset_atelierb_mode).
4672 pretty_print_internal_rep_b(PPFILE,MachName,TYPES,_) :- b_write_machine_representation_to_file(MachName,TYPES,PPFILE).
4673
4674 % -ppB option:
4675 pretty_print_internal_rep_to_B(PPFILE) :- b_write_eventb_machine_to_classicalb_to_file(PPFILE).
4676
4677 :- use_module(tools_printing,[tcltk_nested_read_prolog_file_as_codes/2]).
4678 % -pppl option: internal developer utility to pretty-print a Prolog file in nested fashion
4679 % can be useful to inspecting .prob AST files or .P XTL files
4680 pretty_print_prolog_file(PPFILE) :-
4681 file_loaded(_,MainFile),
4682 (loaded_main_file(Ext,_), \+( (Ext='P' ; Ext='prob' ; Ext= 'pl') )
4683 -> add_warning(probcli,'The -pppl command is designed to work with Prolog files (.P, .prob or .pl), not with: ',Ext) ; true),
4684 pretty_print_prolog_file(MainFile,PPFILE).
4685
4686 pretty_print_prolog_file(File,File) :- !,
4687 add_error(probcli,'Output file must be different from input Prolog file:',File).
4688 pretty_print_prolog_file(MainFile,PPFILE) :-
4689 format('Pretty-Printing Prolog file ~w to ~w~n',[MainFile,PPFILE]),
4690 tcltk_nested_read_prolog_file_as_codes(MainFile,list(Codes)),
4691 safe_intelligent_open_file(PPFILE,write,Stream),
4692 format(Stream,'~s~n',[Codes]),
4693 close(Stream).
4694
4695 :- use_module(extrasrc(source_indenter),[indent_b_file/3]).
4696 indent_main_b_file(PPFILE) :-
4697 file_loaded(_,MainFile),
4698 indent_b_file_to_file(MainFile,PPFILE,[]).
4699
4700 indent_b_file_to_file(File,File,_) :- !,
4701 add_error(probcli,'Output file must be different from input B file:',File).
4702 indent_b_file_to_file(MainFile,PPFILE,Options) :-
4703 format('Indenting B file ~w to ~w~n',[MainFile,PPFILE]), flush_output,
4704 safe_intelligent_open_file(PPFILE,write,OutStream),
4705 call_cleanup(indent_b_file(MainFile,OutStream,Options),close(OutStream)).
4706
4707
4708 % Simple Animator
4709
4710 interactive_animate_machine :-
4711 nl,print('IMPORTANT: Do not use this mode for automatic tools.'),nl,
4712 print('The output format can change arbitrarily in future versions.'),nl,
4713 print('Please terminate your input with a dot (.) and then type return.'),nl,nl,
4714 animate_machine2.
4715 animate_machine2 :-
4716 print_current_state,
4717 cli_computeOperations(Ops),
4718 length(Ops,Max),
4719 print('Enabled Operations: '),nl,
4720 print_options(Ops,1),
4721 print(' ==> '),!,
4722 read(Nr),
4723 (number(Nr),Nr>0,Nr=<Max
4724 -> cli_animateOperationNr(Nr,Ops,0)
4725 ; fail
4726 ),!,
4727 animate_machine2.
4728 animate_machine2.
4729
4730 print_current_state :- current_state_id(CurID), print('ID ==> '), print(CurID),nl,
4731 getStateValues(CurID,State),
4732 print_bindings(State),
4733 (specfile:b_or_z_mode,\+is_initialised_state(CurID)
4734 -> print_red(' Not yet initialised.'),print_mode_info, debug_println(10,state(State)) ; nl).
4735
4736 print_mode_info :- animation_mode(M), (animation_minor_mode(MM) -> true ; MM=''),
4737 format('Animation Mode = ~w [~w]~n',[M,MM]).
4738
4739 cli_computeOperations(Ops) :- option(animate_stats),!, % provide statistics about the animation
4740 nl,
4741 start_probcli_timer(Timer),
4742 current_state_id(CurID),
4743 tcltk_get_options(list(Ops)),
4744 ajoin(['Time to compute all operations in state ',CurID,': '],Msg),
4745 stop_probcli_timer(Timer,Msg).
4746 cli_computeOperations(Ops) :- tcltk_get_options(list(Ops)).
4747
4748 cli_animateOperationNr(Nr,Options,StepNr) :-
4749 (option(animate_stats)
4750 -> nth1(Nr,Options,Action),
4751 truncate_animate_action(Action,TA),
4752 (StepNr>1 -> format('performing step ~w : ~w~n',[StepNr,TA])
4753 ; format('performing ~w~n',[TA]))
4754 ; true),
4755 tcltk_perform_nr(Nr).
4756
4757 :- use_module(tools_strings,[truncate_atom/3]).
4758 % optionally truncate animation action atom for printing:
4759 truncate_animate_action(Action,TA) :-
4760 (option_verbose -> TA = Action
4761 ; \+ atom(Action) -> TA = Action
4762 ; truncate_atom(Action,100,TA)).
4763
4764 perform_random_step(StepNr) :- perform_random_step(_Ops,_Len,_RanChoice,StepNr).
4765 perform_random_step(Ops,Len,RanChoice,StepNr) :-
4766 cli_computeOperations(Ops),
4767 current_state_id(CurID), check_for_errors(CurID,StepNr),
4768 length(Ops,Len), Len>0,
4769 debug_println(20,perform_random_step(Len,StepNr)),
4770 L1 is Len+1,
4771 (do_det_checking, Len>1
4772 -> print_error('Non-deterministic step in animate or init'),
4773 print_error('State:'),
4774 print_current_state, print_error('Enabled Operations: '), print_options(Ops,1),
4775 error_occurred(det_check)
4776 ; true),
4777 random(1,L1,RanChoice),
4778 debug_println(20,random(L1,RanChoice)),
4779 cli_animateOperationNr(RanChoice,Ops,StepNr).
4780
4781 :- use_module(state_space,[visited_expression/2]).
4782 check_for_errors(CurID,StepNr) :- invariant_violated(CurID),
4783 \+ option(no_invariant_violations),
4784 get_preference(do_invariant_checking,true),
4785 ajoin(['INVARIANT VIOLATED after ',StepNr,' steps (state id ',CurID,').'],ErrMsg),
4786 format('~w~n',[ErrMsg]),
4787 visited_expression(CurID,CurState), print_state_silent(CurState),
4788 error_occurred_with_msg(invariant_violation,ErrMsg),
4789 fail.
4790 check_for_errors(CurID,_) :- get_state_errors(CurID).
4791 % TO DO: also check for assertion errors, goal, state_errors with abort
4792
4793 :- use_module(bmachine,[b_machine_has_constants_or_properties/0]).
4794 do_det_checking :- option(det_check),!.
4795 do_det_checking :- option(det_constants_check),current_state_id(root),
4796 b_or_z_mode, b_machine_has_constants_or_properties.
4797
4798 perform_random_steps(Nr,_) :- \+ number(Nr),!,
4799 print_error('Argument to animate not a number'), print_error(Nr),error_occurred(animate).
4800 perform_random_steps(Nr,_) :- Nr<0, !,
4801 print_error('Argument to animate is a negative number'), print_error(Nr),error_occurred(animate).
4802 perform_random_steps(0,_) :- !.
4803 perform_random_steps(Nr,ErrorOnDeadlock) :-
4804 (perform_random_initialisation_if_necessary(Steps) % if Nr=1 we currently will also execute the INITIALISATION ! TO DO: fix
4805 -> perform_random_steps_aux(Steps,Nr,ErrorOnDeadlock)
4806 ; % we have setup_constants_fails or initialisation_fails
4807 print_error('Could not initialise model for animation')
4808 ).
4809
4810 perform_random_steps_aux(Nr,Max,_) :- Nr >= Max,!, debug_println(9,performed_random_steps(Nr)).
4811 perform_random_steps_aux(Nr,Max,ErrorOnDeadlock) :-
4812 N1 is Nr+1,
4813 (perform_random_step(N1)
4814 -> perform_random_steps_aux(N1,Max,ErrorOnDeadlock)
4815 ; /* deadlock */
4816 write_xml_element_to_log(deadlock_found,[step/Nr]),
4817 (ErrorOnDeadlock=true, \+ option(no_deadlocks)) ->
4818 print_error('Deadlock occurred during -animate, at step number:'), print_error(Nr),
4819 error_occurred(animate)
4820 ; print('% Deadlock occurred during -animate, at step number:'), print(Nr),nl
4821 ).
4822
4823 perform_random_initialisation_if_necessary(Steps) :-
4824 b_or_z_mode, current_state_id(State), State=root,!, perform_random_initialisation(Steps).
4825 perform_random_initialisation_if_necessary(0).
4826
4827 perform_random_initialisation :- perform_random_initialisation(_).
4828 perform_random_initialisation(Steps) :- current_state_id(State), State \= root, !,
4829 print_error('init can only be used in initial state'), print_error(State),error_occurred(initialisation),
4830 Steps=0.
4831 ?perform_random_initialisation(Steps) :- b_mode, b_machine_has_constants_or_properties,!,
4832 (perform_random_step(Ops,_Len,RanChoice,1)
4833 -> nth1(RanChoice,Ops,Choice), %print(Choice),nl,
4834 (Choice = 'PARTIAL_SETUP_CONSTANTS'
4835 -> error_occurred(setup_constants_inconsistent)
4836 ; true)
4837 ; error_occurred(setup_constants_fails),fail), % $setup_constants TODO: properties unknown or unsat
4838 perform_random_init_after_setup_constants, Steps=2. % $initialise_machine
4839 perform_random_initialisation(Steps) :- (perform_random_step(1) -> Steps=1 ; error_occurred(initialisation_fails),fail).
4840
4841
4842 perform_random_init_after_setup_constants :- \+ option(initialise), we_need_only_static_assertions(_),!,
4843 printsilent('% NOT INITIALISING MACHINE (not required)'),nls.
4844 % debug_println(20,'% NOT INITIALISING MACHINE (not required)').
4845 perform_random_init_after_setup_constants :-
4846 (perform_random_step(2) % 2 is the step nr not the number of steps
4847 -> true
4848 ; error_occurred(initialisation_fails),
4849 fail).
4850
4851 :- use_module(cbcsrc(enabling_analysis),[tcltk_cbc_enabling_analysis/1, print_enable_table/1, is_timeout_enabling_result/1]).
4852 do_enabling_analysis_csv(EnablingCsvFile,NOW) :-
4853 start_probcli_timer(Timer1),
4854 start_xml_feature(enabling_analysis,file,EnablingCsvFile,FINFO),
4855 tcltk_cbc_enabling_analysis(list(R)),
4856 stop_probcli_timer(Timer1,'% Finished CBC Enabling Analysis',_TotWallTime),
4857 print_cbc_stats(R,NOW),
4858 debug_println(9,writing_to_file(EnablingCsvFile)),
4859 my_tell(EnablingCsvFile),
4860 print_enable_table(R),
4861 told,!,
4862 stop_xml_feature(enabling_analysis,FINFO).
4863 do_enabling_analysis_csv(EnablingCsvFile,_) :-
4864 add_error(enabling_analysis,'Enabling analysis failed',EnablingCsvFile),
4865 stop_xml_group_in_log(enabling_analysis).
4866
4867 print_cbc_stats(Res,_NOW) :- length(Res,Len), Ops is Len-2, % Header + Init
4868 CBC_Calls is Ops*(Ops+1), % +1 for INITIALISATION
4869 findall(TO,(member(list([_|T]),Res), member(TO,T),is_timeout_enabling_result(TO)),TOS),
4870 length(TOS,NrTOS),
4871 format('% CBC Enabling Stats:~n% Nr of events: ~w~n% Nr of cbc calls: ~w, Timeout results: ~w~n',[Ops,CBC_Calls,NrTOS]),
4872 write_xml_element_to_log(cbc_enabling_stats,[nr_events/Ops,cbc_calls/CBC_Calls,nr_timeouts/NrTOS]).
4873
4874
4875 :- use_module(cbcsrc(enabling_analysis),[feasible_operation_with_timeout/3]).
4876 do_feasibility_analysis(ATimeOut,EnablingCsvFile) :-
4877 arg_is_number(ATimeOut,TimeOut),
4878 start_xml_feature(feasibility_analysis,file,EnablingCsvFile,FINFO),
4879 findall(list([Op,Res]),feasible_operation_with_timeout(Op,TimeOut,Res),R),
4880 debug_println(9,writing_to_file(EnablingCsvFile)),
4881 my_tell(EnablingCsvFile),
4882 print_enable_table([list(['Event','Feasibility'])|R]),
4883 told,!,
4884 stop_xml_feature(feasibility_analysis,FINFO).
4885 do_feasibility_analysis(_,EnablingCsvFile) :-
4886 add_error(feasibility_analysis,'Feasibility analysis failed',EnablingCsvFile),
4887 stop_xml_group_in_log(feasibility_analysis).
4888
4889 :- use_module(b_read_write_info,[tcltk_read_write_matrix/1]).
4890 generate_read_write_matrix(CsvFile) :-
4891 tcltk_read_write_matrix(list(Matrix)),
4892 my_tell(CsvFile),
4893 print_enable_table(Matrix),
4894 told,!.
4895 generate_read_write_matrix(CsvFile) :-
4896 add_error(read_write_matrix,'Generating Read-Write-Matrix failed',CsvFile).
4897
4898
4899 my_tell(File) :-
4900 catch(
4901 tell(File),
4902 error(_E,_), % existence_error(_,_)
4903 add_error_fail(tell,'File cannot be written to: ',File)).
4904
4905 print_options([],_).
4906 print_options([H|T],N) :-
4907 print(' '), print(N), print(':'), print(H),nl,
4908 N1 is N+1,
4909 print_options(T,N1).
4910
4911 print_nr_list(List) :- print_nr_list(List,0,1,no_repeats).
4912
4913 print_nr_list([],NM1,_,Repeats) :- !, print_repeats(NM1,Repeats).
4914 print_nr_list([H|T],_,N,repeated(H,SinceN)) :- !, N1 is N+1,
4915 print_nr_list(T,N,N1,repeated(H,SinceN)).
4916 print_nr_list([H|T],NM1,N,Repeats) :- !,
4917 print_repeats(NM1,Repeats),
4918 N1 is N+1,
4919 print_nr_list(T,N,N1,repeated(H,N)).
4920 print_nr_list(X,_,_,_) :- print('### not a list: '), print(X),nl.
4921
4922 print_repeats(N,repeated(H,N)) :- !,
4923 format(' ~w: ~w~n',[N,H]).
4924 print_repeats(N,repeated(H,Since)) :- !, Repeats is 1+N-Since,
4925 format(' ~w - ~w: ~w (~w repetitions)~n',[Since,N,H,Repeats]).
4926 print_repeats(_,_).
4927
4928 print_bindings([]) :- !.
4929 print_bindings([binding(Var,_,PPV)|T]) :- !, print(Var),print('='),print(PPV),
4930 (T=[] -> true ; print(', '), print_bindings(T)).
4931 print_bindings([binding(Var,_,PPV,_Tag)|T]) :- !, print(Var),print('='),print(PPV),
4932 (T=[] -> true ; print(', '), print_bindings(T)).
4933 print_bindings(X) :- print('### Internal Error: illegal binding list: '), print(X),nl.
4934
4935 :- dynamic expected_error_occurred/1.
4936 :- dynamic error_did_not_occur/1.
4937 reset_expected_error_occurred :- retractall(expected_error_occurred(_)).
4938 check_all_expected_errors_occurred(NOW) :-
4939 %error_manager:display_error_statistics,
4940 get_errors, get_state_space_errors,
4941 retractall(error_did_not_occur(_)),
4942 ? expected_error(Type),
4943 ? \+ expected_error_occurred(Type),
4944 format_with_colour_nl(user_error,[red],'*** Expected Error of following type to occur: ~w',[Type]),
4945 writeln_log_time(expected_error_did_not_occur(NOW,Type)),
4946 assertz(error_did_not_occur(Type)),
4947 (option(strict_raise_error) -> definite_error_occurred ; fail).
4948 check_all_expected_errors_occurred(_NOW) :-
4949 findall(1,expected_error(_),EE), length(EE,NrExpected),
4950 (NrExpected>0
4951 -> findall(1,error_did_not_occur(_),EDNO), length(EDNO,NrNotOcc),
4952 (NrNotOcc>0
4953 -> format_with_colour_nl(user_error,[red],'*** Some expected errors (~w/~w) did NOT occur!',[NrNotOcc,NrExpected])
4954 ; format_with_colour_nl(user_output,[green],'All expected errors (~w) occurred.',[NrExpected])
4955 )
4956 ; true).
4957
4958 ?expected_error(Type) :- option(expect_error(Type)).
4959 expected_error(Type) :- option(expect_error_pos(Type,_Line,_Col)).
4960
4961 error_occurred(warning(Type)) :- !, error_occurred(Type,warning).
4962 error_occurred(Type) :- error_occurred(Type,error).
4963
4964 get_error_category_and_type(warning(Cat),Category,Type) :- !, Category=Cat,Type=warning.
4965 get_error_category_and_type(C,C,error).
4966
4967 error_occurred_with_msg(Type,Msg) :- error_occurred_with_msg(Type,Msg,not_yet_extracted).
4968 error_occurred_with_msg(warning(Type),Msg,Span) :- !, error_occurred(Type,warning,Span,Msg).
4969 error_occurred_with_msg(Type,Msg,Span) :- error_occurred(Type,error,Span,Msg).
4970
4971 error_occurred(Type,ErrOrWarn) :- error_occurred(Type,ErrOrWarn,not_yet_extracted,'').
4972
4973 error_occurred(Type,ErrOrWarning,ExtractedSpan,Msg) :-
4974 option(expect_error_pos(Type,Line,Col)),!,
4975 write_xml_element_to_log(expected_error_occurred,[category/Type, (type)/ErrOrWarning, message/Msg]),
4976 assertz(expected_error_occurred(Type)),
4977 (get_error_or_warning_span(ExtractedSpan,Type,EL,EC)
4978 -> (option(expect_error_pos(Type,EL,EC))
4979 -> debug_println(9,expect_error_pos_ok(Type,EL,EC))
4980 ; format('*** Unexpected line ~w and column ~w for error ~w!~n*** Expected line ~w and column ~w.~n',[EL,EC,Type,Line,Col]),
4981 definite_error_occurred
4982 )
4983 ; format('*** Could not obtain position information for error ~w! Expected line ~w and column ~w.~n',[Type,Line,Col]),
4984 %display_error_statistics,
4985 definite_error_occurred).
4986 error_occurred(Type,ErrOrWarning,ExtractedSpan,Msg) :-
4987 ? option(expect_error(Type)),!,
4988 inc_counter(cli_expected_errors),
4989 get_xml_span(ExtractedSpan,XML),
4990 write_xml_element_to_log(expected_error_occurred,[category/Type, (type)/ErrOrWarning, message/Msg|XML]),
4991 assertz(expected_error_occurred(Type)).
4992 error_occurred(Type,ErrOrWarning,ExtractedSpan,Msg) :-
4993 (probcli_time_stamp(NOW) -> true ; NOW=unknown),
4994 writeln_log(error_occurred(NOW,Type)),
4995 get_xml_span(ExtractedSpan,XML),
4996 (option(optional_error(Type)) ->
4997 write_xml_element_to_log(optional_error_occurred,[category/Type, (type)/ErrOrWarning, message/Msg|XML]),
4998 formatsilent('% Optional error occured: ~w~n',[Type])
4999 ;
5000 write_xml_element_to_log(error_occurred,[category/Type, (type)/ErrOrWarning, message/Msg|XML]),
5001 (ErrOrWarning = warning -> safe_inc_counter(cli_warnings) ; safe_inc_counter(cli_errors)),
5002 flush_output, % ensure we can later associate position of error message
5003 (option(strict_raise_error) ->
5004 print_error('*** Unexpected error occurred ***'),
5005 print_error(Type),
5006 findall(Err,option(expect_error(Err)),Ls), (Ls=[] -> true ; print_error(expected(Ls))),
5007 definite_error_occurred
5008 ; ErrOrWarning=error,serious_error(Type)
5009 -> print_error('*** Serious error occurred ***'),
5010 print_error(Type),
5011 definite_error_occurred
5012 ; print_probcli_error_non_strict(Type,ErrOrWarning)
5013 )
5014 ).
5015
5016 safe_inc_counter(Counter) :-
5017 catch(inc_counter(Counter), E,
5018 format(user_error,'~n*** Exception in counter library, probably not yet initialized: ~w.~n~n',[E])).
5019
5020
5021 get_xml_span(Span,XML) :- extract_file_line_col(Span,FullFilename,Line,Col,EndLine,EndCol),!,
5022 XML = [file/FullFilename,start_line/Line,end_line/EndLine,start_col/Col,end_col/EndCol|XT],
5023 get_xml_add_description(Span,XT).
5024 get_xml_span(Span,XML) :- get_xml_add_description(Span,XML).
5025
5026 get_xml_add_description(Span,XML) :-
5027 extract_additional_description(Span,Msg),!,
5028 XML = [additional_description/Msg].
5029 get_xml_add_description(_,[]).
5030
5031 get_error_or_warning_span(not_yet_extracted,Type,EL,EC) :- check_error_span_file_linecol(Type,_File,EL,EC,_,_).
5032 get_error_or_warning_span(not_yet_extracted,Type,EL,EC) :- check_error_span_file_linecol(warning(Type),_File,EL,EC,_,_).
5033 get_error_or_warning_span(Span,_,EL,EC) :- Span \= not_yet_extracted, extract_line_col(Span,EL,EC,_,_).
5034
5035
5036 % a list of serious errors: if these occur; then return code different from 0 even in non-strict mode
5037 serious_error(get_java_command_path).
5038 serious_error(internal_error(_)).
5039
5040 print_probcli_error_non_strict(parse_machine_predicate_error,_) :-
5041 !. % have already been reported
5042 print_probcli_error_non_strict(Type,ErrOrWarning) :-
5043 (ErrOrWarning=warning -> print_error('*** warning occurred ***')
5044 ; print_error('*** error occurred ***')),
5045 print_error(Type).
5046
5047 definite_error_occurred :- print_error('*** Abnormal termination of probcli !'),
5048 (file_loaded(_,File) -> print_error('*** for_file'(File)) ; true),
5049 (current_probcli_command(Cmd) -> print_error('*** for_command'(Cmd)) ; true),
5050 (probcli_time_stamp(NOW) -> halt_prob(NOW,1)
5051 ; writeln_log(halt(1)),
5052 halt_exception(1)
5053 ).
5054
5055 :- dynamic current_probcli_command/1.
5056 set_current_probcli_command(X) :- retractall(current_probcli_command(_)),
5057 assertz(current_probcli_command(X)).
5058 unset_current_probcli_command :- retractall(current_probcli_command(_)).
5059
5060 halt_prob(ExitCode) :-
5061 (probcli_time_stamp(NOW) -> halt_prob(NOW,ExitCode) ; halt_prob(0,ExitCode)).
5062 halt_prob(NOW,ExitCode) :-
5063 write_xml_element_to_log(probcli_halted_prematurely,[now/NOW]),
5064 close_all_xml_groups_in_log_until('probcli-run'),
5065 stop_xml_probcli_run(NOW),
5066 halt_exception(ExitCode).
5067
5068
5069 :- dynamic accumulated_infos/3, individual_file_infos/3, merged_individual_file_infos/3.
5070 accumulate_infos(Context,Infos) :- option(benchmark_info_csv_output(_,_,_)), % -bench_csv
5071 file_loaded(_,File),
5072 get_additional_infos(Infos,Infos2), % additional infos if -machine_stats provided
5073 sort(Infos2,SInfos), % infos is a list of the form Info-Value
5074 debug_println(19,assert_file_infos(File,Context,SInfos)),
5075 assertz(individual_file_infos(File,Context,SInfos)), % store for later csv summary printing
5076 fail.
5077 ?accumulate_infos(Context,Infos) :- accumulate_infos_2(Context,Infos).
5078
5079 % useful if this is not related to a loaded file, like -eval_file:
5080 accumulate_file_infos(File,Context,Infos) :-
5081 get_additional_stats(Infos,Infos2),
5082 sort(Infos2,SInfos), % infos is a list of the form Info-Value
5083 assertz(individual_file_infos(File,Context,SInfos)).
5084
5085 % join/merge accumulated infos for multiple runs (benchmarking) for a particular context/category
5086 % currently we support this for model-checking
5087 merge_accumulated_infos(Context) :- individual_file_infos(File,Context,_),!,
5088 findall(Infos,individual_file_infos(File,Context,Infos),[Infos1|RestInfos]),
5089 merge_acc(Infos1,RestInfos,1,Result),
5090 assertz(merged_individual_file_infos(File,Context,Result)).
5091
5092 merge_acc(Cur,[],_,Cur).
5093 merge_acc(Cur,[Next|T],Nr,Res) :-
5094 N1 is Nr+1,
5095 merge_acc_infos(Cur,Next,N1,NextCur),
5096 merge_acc(NextCur,T,N1,Res).
5097
5098 % merge two accumulated infos lists
5099 merge_acc_infos([],S,_,Res) :- !, Res=S.
5100 merge_acc_infos(S,[],_,Res) :- !, Res=S.
5101 merge_acc_infos([C1|T1],[C2|T2],Nr,[Cat-ResVal|MT]) :-
5102 get_info(C1,Cat,Val1), get_info(C2,Cat,Val2),
5103 merge_value(Cat,Val1,Val2,Nr,ResVal),!,
5104 merge_acc_infos(T1,T2,Nr,MT).
5105 merge_acc_infos([C1|T1],T2,Nr,[C1|MT]) :-
5106 add_warning(merge_acc_infos,'Missing value: ',C1),
5107 merge_acc_infos(T1,T2,Nr,MT).
5108
5109 % merge individual values
5110 merge_value(Cat,Val1,_Val2,_,ResVal) :- keep_first_value(Cat),!, ResVal=Val1.
5111 merge_value(_,Val,Val,_,ResVal) :- !, ResVal=Val.
5112 merge_value(Cat,Val1,Val2,Nr,ResVal) :- compute_average(Cat),!, ResVal is (Val1*(Nr-1)/Nr) + (Val2 / Nr).
5113 merge_value(Cat,Val1,Val2,Nr,ResVal) :-
5114 add_warning(merge_value,'Differing values: ',val(Cat,Val1,Val2)),
5115 ResVal is (Val1*(Nr-1)/Nr) + (Val2 / Nr).
5116
5117 compute_average(runtime).
5118 compute_average(total_runtime).
5119 compute_average(walltime).
5120
5121 keep_first_value(memory_used). % memory consumption of the first run is relevant
5122
5123
5124 % also store additional infos if -machine_stats provided; useful for benchmarking/articles
5125 :- use_module(covsrc(hit_profiler),[retract_profile_stats/2]).
5126 get_additional_infos(I,Res) :- option(cli_print_machine_info(statistics)),!,
5127 findall(Key-Nr,b_machine_statistics(Key,Nr),I2,I),
5128 get_additional_stats(I2,Res).
5129 get_additional_infos(I,Res) :- get_additional_stats(I,Res).
5130 get_additional_stats(I,Res) :-
5131 findall(Key-Nr,retract_profile_stats(Key,Nr),Res,I). % include additional profiling stats and retract/reset them
5132
5133 accumulate_infos_2(_,[]).
5134 accumulate_infos_2(Context,[Info|T]) :- get_info(Info,FF,Nr),
5135 (number(Nr) -> Nr>0 ; add_internal_error('Can only accumulate numbers:',FF-Nr),fail), !,
5136 (retract(accumulated_infos(Context,FF,OldNr)) ->true ; OldNr=0),
5137 N1 is OldNr+Nr,
5138 assertz(accumulated_infos(Context,FF,N1)),
5139 ? accumulate_infos_2(Context,T).
5140 ?accumulate_infos_2(Context,[_|T]) :- accumulate_infos_2(Context,T).
5141 get_info(FF-Nr,FF,Nr).
5142 get_info(FF/Nr,FF,Nr).
5143
5144 :- use_module(tools_io,[safe_intelligent_open_file/3]).
5145 print_accumulated_infos(NrFilesProcessed) :-
5146 (option(benchmark_info_csv_output(File,FileMode,CSVMode)) % TODO: allow multiple entries
5147 -> safe_intelligent_open_file(File,FileMode,Stream) % FileMode is write or append
5148 ; Stream=user_output, CSVMode=csv
5149 ),
5150 call_cleanup(pr_acc_infos_aux(Stream,NrFilesProcessed,FileMode,CSVMode),
5151 close(Stream)), !.
5152 print_accumulated_infos(NrFilesProcessed) :-
5153 add_internal_error('Call failed:',print_accumulated_infos(NrFilesProcessed)).
5154
5155 get_csv_mode(csv,csv).
5156 get_csv_mode(tex,latex).
5157 get_csv_mode(latex,latex).
5158
5159 %:- use_module(library(system),[ datime/1]).
5160 pr_acc_infos_aux(Stream,NrFilesProcessed,FileMode,CSVMode) :-
5161 ? (NrFilesProcessed>1,accumulated_infos(_,_,_) -> true ; option(benchmark_info_csv_output(_,_,_))),!,
5162 print_individual_file_infos_csv(Stream,FileMode,CSVMode),
5163 start_xml_group_in_log(summary,files_processed,NrFilesProcessed),
5164 ((FileMode = append ; NrFilesProcessed = 1)
5165 -> true % do not print accumulated info line
5166 ; format(Stream,'Analysis summary (~w files processed): ',[NrFilesProcessed]),
5167 findall(Context-F-Nr,accumulated_infos(Context,F,Nr),L), sort(L,SL),
5168 maplist(prob_cli:pracc(Stream),SL),nl(Stream)
5169 ),
5170 % TO DO: write infos to XML log
5171 (option(print_version(VERSIONKIND)) ->
5172 datime(datime(Year,Month,Day,Hour,Min,_Sec)),
5173 format(Stream,'CSV file generated at ~w:~w on the date ~w/~w/~w using probcli:~n',[Hour,Min,Year,Month,Day]),
5174 print_version(VERSIONKIND,Stream),
5175 print_csv_prefs(Stream)
5176 ; true),
5177 (option(cli_print_statistics(memory)) -> print_memory_statistics(Stream) ; true),
5178 stop_xml_group_in_log_no_statistics(summary).
5179 pr_acc_infos_aux(_,_NrFilesProcessed,_Mode,_).
5180
5181 print_csv_prefs(Stream) :- \+ \+ option(set_preference_group(_,_)),
5182 format(Stream,'PREFERENCE GROUP,Setting~n',[]),
5183 option(set_preference_group(P,V)),
5184 format(Stream,'~w,~w~n',[P,V]),
5185 fail.
5186 print_csv_prefs(Stream) :- \+ \+ option(set_pref(_,_)),
5187 format(Stream,'PREFERENCE,Value~n',[]),
5188 option(set_pref(P,V)),
5189 format(Stream,'~w,~w~n',[P,V]),
5190 fail.
5191 print_csv_prefs(_).
5192
5193 pracc(Stream,Context-F-Nr) :- format(Stream,'~w:~w:~w ',[Context,F,Nr]).
5194 :- use_module(probsrc(tools),[gen_relative_path_to_cur_dir/2]).
5195 % print CSV summary of run
5196 print_individual_file_infos_csv(Stream,FileMode,CSVMode) :-
5197 findall(C,individual_file_infos(_,C,_),All), sort(All,AllContexts),
5198 member(Context,AllContexts), % iterate over all Contexts
5199 (individual_file_infos(_,Context,HInfos) -> true), % pick one as header
5200 (FileMode=append
5201 -> true % do not print header line, we append to an existing table
5202 ; format(Stream,'~nFILE,ANALYSIS,',[]),
5203 print_titles(HInfos,CSVMode,Stream),nl(Stream)
5204 ),
5205 % TO DO: ensure Infos and SHInfos identical, else add 0 for missing categories
5206 (merged_individual_file_infos(File,Context,Infos)
5207 -> true % just print averages
5208 ; individual_file_infos(File,Context,Infos)
5209 ),
5210 gen_relative_path_to_cur_dir(File,RelFile),
5211 format(Stream,'~w,~w,',[RelFile,Context]),
5212 print_vals(Infos,HInfos,CSVMode,Stream),nl(Stream),
5213 fail.
5214 print_individual_file_infos_csv(_,_,_).
5215
5216
5217
5218 print_vals(_,[],_,_) :- !.
5219 print_vals([H|T],[Header|HT],Mode,Stream) :- get_info(Header,Title,_),
5220 get_info(H,Title,Nr), !,
5221 write_atom(Mode,Stream,Nr),
5222 (T=[] -> write_csv_terminator(Mode,Stream) ; write_csv_sep(Mode,Stream), print_vals(T,HT,Mode,Stream)).
5223 print_vals(Vals,[_|HT],Mode,Stream) :- % a value is missing for this file
5224 write(Stream,'-'),
5225 (HT=[] -> write_csv_terminator(Mode,Stream) ; write_csv_sep(Mode,Stream), print_vals(Vals,HT,Mode,Stream)).
5226 print_titles([],_,_).
5227 print_titles([H|T],Mode,Stream) :- get_info(H,FF,_),
5228 write_atom(Mode,Stream,FF),
5229 (T=[] -> write_csv_terminator(Mode,Stream) ; write_csv_sep(Mode,Stream), print_titles(T,Mode,Stream)).
5230
5231 :- use_module(probsrc(tools),[latex_escape_atom/2]).
5232 write_atom(latex,Stream,Atom) :- atom(Atom), latex_escape_atom(Atom,EAtom),!,
5233 write(Stream,EAtom).
5234 write_atom(_,Stream,Term) :- write(Stream,Term).
5235
5236 write_csv_sep(latex,Stream) :- !,write(Stream,' & ').
5237 write_csv_sep(_,Stream) :- write(Stream,',').
5238 write_csv_terminator(latex,Stream) :- !,write(Stream,' \\\\').
5239 write_csv_terminator(_,_).
5240
5241 write_important_xml_element_to_log(Category,Infos) :-
5242 include(prob_cli:important_info,Infos,II),
5243 write_xml_element_to_log(Category,II).
5244 important_info(FF/Nr) :-
5245 \+ irrelevant_xml_info(FF),
5246 (Nr=0 -> \+ irrelevant_xml_if_zero(FF) ; true).
5247 irrelevant_xml_info(true_after_expansion).
5248 irrelevant_xml_info(false_after_expansion).
5249 irrelevant_xml_info(unknown_after_expansion).
5250 irrelevant_xml_info(total_after_expansion).
5251 irrelevant_xml_if_zero(timeout).
5252 irrelevant_xml_if_zero(enum_warning).
5253
5254
5255 % check_required_infos(ExpectedInfos,ActualInfos,ErrType)
5256 check_required_infos([],_,_).
5257 check_required_infos([H|T],Infos,ErrType) :-
5258 ? (check_single_info(H,Infos)
5259 -> check_required_infos(T,Infos,ErrType)
5260 ; translate_err_type(ErrType,ES),
5261 format_with_colour_nl(user_error,[red],
5262 '*** Unexpected result while checking: ~w~n*** expected : ~w~n*** in : ~w',
5263 [ES,H,Infos]),
5264 error_occurred(ErrType)).
5265 translate_err_type(check_assertions,'ASSERTIONS') :- !.
5266 translate_err_type(cli_check_assertions,'ASSERTIONS') :- !.
5267 translate_err_type(check_goal,'GOAL') :- !.
5268 translate_err_type(load_po_file,'PROOF OBLIGATIONS') :- !.
5269 translate_err_type(cli_wd_check,'WD PROOF OBLIGATIONS') :- !.
5270 translate_err_type(check_cache_stats,'CACHE STATISTICS') :- !.
5271 translate_err_type(X,X).
5272
5273 check_single_info(Label-Nr,Infos) :- !, member(Label-ActualNr,Infos),
5274 match_info(Nr,ActualNr).
5275 ?check_single_info(H,List) :- member(H,List).
5276 match_info(X,X).
5277 match_info(comparison_operator(Comp,Nr),ActualNr) :-
5278 number(Nr), number(ActualNr),call(Comp,ActualNr,Nr).
5279
5280 :- use_module(tools_platform, [max_tagged_integer/1]).
5281 :- public mc_ok_arg/2.
5282 mc_ok_arg(Arg,X) :- Arg==all,!,max_tagged_integer(X).
5283 mc_ok_arg(Arg,N) :- arg_is_number(Arg,N).
5284
5285
5286 :- dynamic option/1.
5287 assert_all_options([]).
5288 assert_all_options([Opt|T]) :- assert_option(Opt),
5289 assert_all_options(T).
5290
5291 :- use_module(pathes_extensions_db,[probcli_command_requires_extension/2]).
5292 cli_option_not_available(Opt,ProBExtension,Reason) :-
5293 probcli_command_requires_extension(Opt,ProBExtension),
5294 unavailable_extension(ProBExtension,Reason).
5295
5296 check_unavailable_options :-
5297 ? option(Opt),
5298 cli_option_not_available(Opt,ProBExtension,Reason),
5299 (recognised_option(Name,Opt,_,_) -> true ; Name=Opt),
5300 ajoin(['probcli command ', Name,' cannot be performed because extension not available (',Reason,'):'],Msg),
5301 add_error(probcli,Msg,ProBExtension),
5302 fail.
5303 check_unavailable_options.
5304
5305 assert_option(silent) :- option(force_no_silent),!. % ignoring silent flag
5306 assert_option(Opt) :- assertz(option(Opt)), treat_option(Opt).
5307
5308 :- use_module(tools_printing,[set_no_color/1, reset_no_color_to_default/0]).
5309 treat_option(silent) :- !, set_silent_mode(on),set_error_manager_silent_mode(on).
5310 treat_option(force_no_silent) :- !, set_silent_mode(off),set_error_manager_silent_mode(off).
5311 treat_option(no_color) :- !, set_no_color(true).
5312 treat_option(_).
5313
5314 reset_options :- retractall(option(_)),
5315 set_silent_mode(off), set_error_manager_silent_mode(off),
5316 reset_no_color_to_default.
5317
5318 % replace a leading double-dash -- by a single dash and replace inner dashes by underscores
5319 normalise_option_atom(X,RX) :- atom(X),!,
5320 atom_codes(X,CodesX),
5321 % remove leading dash
5322 (CodesX=[45,45,H|T], H\=45 % Double dash --Option
5323 -> maplist(prob_cli:convert_dash_to_underscore,[H|T],HT2),
5324 RXCodes=[45|HT2]
5325 ; CodesX = [Dash|T], is_dash(Dash) % single dash
5326 -> maplist(prob_cli:convert_dash_to_underscore,T,T2),
5327 RXCodes=[45|T2]
5328 ; maplist(prob_cli:convert_dash_to_underscore,CodesX,RXCodes)
5329 ),
5330 atom_codes(RX,RXCodes).
5331 normalise_option_atom(T,T).
5332
5333 is_dash(45). % regular dash
5334 is_dash(8212). % Unicode double dash; sometimes automatically generated from -- by e.g., macOS Mail program
5335
5336 :- public normalise_pref_name/2. % called via recognised_option
5337 % replace dashes by underscores
5338 normalise_pref_name(X,RX) :- atom(X),!,
5339 atom_codes(X,CodesX),
5340 maplist(prob_cli:convert_dash_to_underscore,CodesX,C2),
5341 atom_codes(RX,C2).
5342 normalise_pref_name(T,T).
5343
5344 convert_dash_to_underscore(45,R) :- !, R=95.
5345 convert_dash_to_underscore(X,X).
5346
5347 recognised_cli_option(X,Opt,Args,Condition) :- normalise_option_atom(X,RX),
5348 ? recognised_option(RX,Opt,Args,Condition).
5349
5350 % get a list of all options
5351 get_all_options(SOpts) :-
5352 findall(O, recognised_option(O,_,_,_), Opts),
5353 sort(Opts,SOpts).
5354
5355 :- use_module(tools_matching,[fuzzy_match_codes_lower_case/2]).
5356 % compute a set of possible fuzzy matches
5357 get_possible_fuzzy_match_options(Option,FuzzyMatches) :-
5358 normalise_option_atom(Option,RX),
5359 atom_codes(RX,OCodes),
5360 get_all_options(SOpts),
5361 findall(Target,(member(Target,SOpts),atom_codes(Target,TargetCodes),
5362 fuzzy_match_codes_lower_case(OCodes,TargetCodes)),FuzzyMatches).
5363
5364 :- use_module(tools_matching,[get_possible_completions_msg/3]).
5365 get_possible_options_completion_msg(Option,Msg) :-
5366 normalise_option_atom(Option,RX),
5367 get_all_options(SOpts),
5368 get_possible_completions_msg(RX,SOpts,Msg).
5369
5370 recognised_option(X,Opt,[],true) :- recognised_option(X,Opt). % options without arguments
5371 recognised_option(X,Opt,Args,true) :- recognised_option(X,Opt,Args). % options with arguments but no code needed to check arguments
5372
5373 recognised_option('-mc',cli_mc(N,[]),[Arg],prob_cli:mc_ok_arg(Arg,N)).
5374 recognised_option('-bench_model_check',cli_mc(LimitNr,[reset_state_space,repeat(Rep)]),[Arg],tools:arg_is_number(Arg,Rep)) :- max_tagged_integer(LimitNr).
5375 recognised_option('-model_check',cli_mc(LimitNr,[]),[],true) :- max_tagged_integer(LimitNr).
5376 recognised_option('-timeout',timeout(N),[Arg],tools:arg_is_number(Arg,N)). % for model checking, refinement checking and for disprover per PO
5377 recognised_option('-time_out',timeout(N),[Arg],tools:arg_is_number(Arg,N)).
5378 recognised_option('-global_time_out',timeout(N),[Arg],tools:arg_is_number(Arg,N)). % better name, to avoid conflict with -p timeout N which also works
5379 recognised_option('-s',socket(S,true),[Arg],tools:arg_is_number(Arg,S)).
5380 recognised_option('-cc',coverage(N,N2,just_check_stats),[Arg,Arg2],
5381 (arg_is_number_or_wildcard(Arg,N),arg_is_number_or_wildcard(Arg2,N2))).
5382 recognised_option('-csp_guide',add_csp_guide(File),[File],
5383 prob_cli:check_file_arg(File,'csp_guide')).
5384 recognised_option('-prologOut',csp_translate_to_file(PlFile),[PlFile],
5385 prob_cli:check_file_arg(PlFile,'prologOut')).
5386 recognised_option('-load_state',load_state(Filename),[Filename],
5387 prob_cli:check_file_arg(Filename,'load_state')).
5388 recognised_option('-refchk',refinement_check(Filename,trace,100000),[Filename],
5389 prob_cli:check_file_arg(Filename,'refchk')).
5390 recognised_option('-ref_check',refinement_check(Filename,FailuresModel,100000),[Shortcut,Filename],
5391 (prob_cli:check_file_arg(Filename,'ref_check'),
5392 prob_cli:check_failures_mode(Shortcut,FailuresModel))).
5393 recognised_option('-refinement_check',Option,Args,Code) :- recognised_option('-refchk',Option,Args,Code).
5394 recognised_option('-hash',check_statespace_hash(H,_),[Arg],tools:arg_is_number(Arg,H)).
5395 recognised_option('-hash64',check_statespace_hash(H,'64bit'),[Arg],tools:arg_is_number(Arg,H)).
5396 recognised_option('-hash32',check_statespace_hash(H,'32bit'),[Arg],tools:arg_is_number(Arg,H)).
5397 recognised_option('-check_op_cache_stats',
5398 check_op_cache([next_state_calls-H1,inv_check_calls-H2,
5399 operations_cached-H3,invariants_cached-H4]),[Arg1,Arg2,Arg3,Arg4],
5400 (tools:arg_is_number_or_wildcard(Arg1,H1), tools:arg_is_number_or_wildcard(Arg2,H2),
5401 tools:arg_is_number_or_wildcard(Arg3,H3), tools:arg_is_number_or_wildcard(Arg4,H4))).
5402 recognised_option('-ltllimit',ltl_limit(Nr),[Arg], tools:arg_is_number(Arg,Nr)).
5403 recognised_option('-ltlfile',ltl_file(Filename),[Filename],
5404 prob_cli:check_file_arg(Filename,'ltlfile')).
5405 recognised_option('-check_disprover_result',cli_check_disprover_result([true-TNr,false-FNr,unknown-UNr,failure-0]),[T,F,U],
5406 (arg_is_number_or_wildcard(T,TNr),arg_is_number_or_wildcard(F,FNr),arg_is_number_or_wildcard(U,UNr))).
5407 recognised_option('-aa',cli_check_assertions(all,[true/TNr,false/FNr,unknown/UNr]),[T,F,U],
5408 (arg_is_number_or_wildcard(T,TNr),arg_is_number_or_wildcard(F,FNr),arg_is_number_or_wildcard(U,UNr))).
5409 recognised_option('-ma',cli_check_assertions(main,[true/TNr,false/FNr,unknown/UNr]),[T,F,U],
5410 (arg_is_number_or_wildcard(T,TNr),arg_is_number_or_wildcard(F,FNr),arg_is_number_or_wildcard(U,UNr))).
5411 recognised_option('-wd',cli_wd_check(DNr,TNr),[D,T],
5412 (arg_is_number_or_wildcard(T,TNr),arg_is_number_or_wildcard(D,DNr))).
5413 recognised_option('-check_cache_stats',cli_cache_stats_check([value_persistance_reused_transitions-RNr,
5414 value_persistance_stored_transitions-SNr]),[R,S],
5415 (arg_is_number_or_wildcard(S,SNr),arg_is_number_or_wildcard(R,RNr))).
5416 recognised_option('-kodkod_comparision',kodkod_comparision(Nr),[Arg],tools:arg_is_number(Arg,Nr)).
5417 recognised_option('-kodkod_performance',kodkod_performance(File,Nr),[File,Arg],tools:arg_is_number(Arg,Nr)).
5418 recognised_option('-animate',cli_random_animate(N,true),[Steps],tools:arg_is_number(Steps,N)).
5419 recognised_option('-execute',execute(N,true,current_state(1)),[Steps],tools:arg_is_number(Steps,N)).
5420 recognised_option('-execute_repeat',execute(N,true,current_state(R)),[Steps,Rep],
5421 (tools:arg_is_number(Steps,N),tools:arg_is_number(Rep,R))).
5422 recognised_option('-execute_expect_steps',execute_expect_steps(N),[Steps],tools:arg_is_number(Steps,N)).
5423 recognised_option('-logxml_write_vars',logxml_write_ids(variables,Prefix),[Prefix],true).
5424 recognised_option('-logxml_write_ids',logxml_write_ids(all,Prefix),[Prefix],true).
5425 recognised_option('-zmq_master',zmq_master(Identifier),[Identifier], true).
5426 recognised_option('-cbc_tests', cbc_tests(Depth,EndPred,Output),[Depth,EndPred,Output],
5427 prob_cli:check_file_arg(Output,'cbc_tests')).
5428 recognised_option('-mcm_tests', mcm_tests(Depth,MaxStates,EndPred,Output),[Depth,MaxStates,EndPred,Output],
5429 prob_cli:check_file_arg(Output,'mcm_tests')).
5430 recognised_option('-test_description', test_description(File), [File],
5431 prob_cli:check_file_arg(File,'test_description')).
5432 recognised_option('-all_paths', all_deadlocking_paths(File), [File],
5433 prob_cli:check_file_arg(File,'all_paths')).
5434 recognised_option('-dot',dot_command(Category,File,default),[Category,File],
5435 prob_cli:check_file_arg(File,'dot')).
5436 recognised_option('-spdot',dot_command(state_space,File,default),[File], prob_cli:check_file_arg(File,'spdot')). % we keep this : it is shown in Wiki
5437 % recognised_option('-spmdot',dot_command(signature_merge,File,default),[File], prob_cli:check_file_arg(File,'spmdot')).
5438 % recognised_option('-spddot',dot_command(dfa_merge,File,default),[File], prob_cli:check_file_arg(File,'spddot')).
5439 % recognised_option('-sgdot',dot_command(state_as_graph,File,default),[File], prob_cli:check_file_arg(File,'sgdot')).
5440 recognised_option('-dotexpr',dot_command_for_expr(Category,Expr,File,[],default),[Category,Expr,File],
5441 prob_cli:check_file_arg(File,'dotexpr')).
5442 recognised_option('-dot_expr',Opt,Args,Call) :- recognised_option('-dotexpr',Opt,Args,Call).
5443 %recognised_option('-sgedot',dot_command_for_expr(expr_as_graph,Expr,File,[],default),[Expr,File], prob_cli:check_file_arg(File,'sgedot')).
5444 % recognised_option('-sptdot',dot_command_for_expr(transition_diagram,Expr,File,[],default),[Expr,File],prob_cli:check_file_arg(File,'sptdot')).
5445 %recognised_option('-invdot',dot_command(invariant,File,default),[File], prob_cli:check_file_arg(File,'invdot')).
5446 %recognised_option('-propdot',dot_command(properties,File,default),[File], prob_cli:check_file_arg(File,'propdot')).
5447 %recognised_option('-assdot',dot_command(assertions,File,default),[File], prob_cli:check_file_arg(File,'assdot')).
5448 %recognised_option('-deaddot',dot_command(deadlock,File,default)(File),[File], prob_cli:check_file_arg(File,'deaddot')).
5449 recognised_option('-puml',plantuml_command(Category,File),[Category,File],
5450 prob_cli:check_file_arg(File,'plantuml')).
5451 recognised_option('-pumlexpr',plantuml_command(Category,File,[Expr]),[Category,Expr,File],
5452 prob_cli:check_file_arg(File,'plantuml')).
5453 recognised_option('-puml_expr',Opt,Args,Call) :- recognised_option('-pumlexpr',Opt,Args,Call).
5454 recognised_option('-csv',csv_table_command(Category,[],[],File),[Category,File],
5455 prob_cli:check_file_arg(File,'csv')).
5456 recognised_option('-csvexpr',csv_table_command(Category,[Expr],[],File),[Category,Expr,File],
5457 prob_cli:check_file_arg(File,'csvexpr')).
5458 recognised_option('-csv_expr',Opt,Args,Call) :- recognised_option('-csvexpr',Opt,Args,Call).
5459 recognised_option('-csv_hist',Opt,Args,Call) :- recognised_option('-csvhist',Opt,Args,Call).
5460 recognised_option('-csvhist',evaluate_expression_over_history_to_csv_file(Expr,File),[Expr,File],
5461 prob_cli:check_file_arg(File,'csvhist')).
5462 %recognised_option('-get_min_max_coverage',csv_table_command(minmax_table,[],[text_output],File),[File]). % deprecated
5463 recognised_option('-min_max_coverage',csv_table_command(minmax_table,[],[text_output],File),[File],
5464 prob_cli:check_file_arg(File,'min_max_coverage')).
5465 recognised_option('-get_coverage_information',get_coverage_information(File),[File],
5466 prob_cli:check_file_arg(File,'get_coverage_information')).
5467 %recognised_option('-vc',csv_table_command(minmax_table,[],[text_output],user_output)).
5468 recognised_option('-read_write_matrix_csv',generate_read_write_matrix_csv(CsvFile),
5469 [CsvFile],
5470 prob_cli:check_file_arg(CsvFile,'read_write_matrix_csv')).
5471 recognised_option('-feasibility_analysis_csv',feasibility_analysis_csv(TimeOut,EnablingCsvFile),
5472 [TimeOut,EnablingCsvFile],
5473 prob_cli:check_file_arg(EnablingCsvFile,'feasibility_analysis_csv')).
5474 recognised_option('-l',log(Log,prolog),[Log],
5475 prob_cli:check_file_arg(Log,'l')).
5476 recognised_option('-log',log(Log,prolog),[Log],
5477 prob_cli:check_file_arg(Log,'log')).
5478 recognised_option('-logxml',log(Log,xml),[Log],
5479 prob_cli:check_file_arg(Log,'logxml')). % see cli_start_logging
5480 recognised_option('-logtlc',logtlc(Log),[Log],
5481 prob_cli:check_file_arg(Log,'logtlc')).
5482 recognised_option('-pp',pretty_print_internal_rep(File,'$auto',needed,ascii),[File],
5483 prob_cli:check_file_arg(File,'pp')).
5484 recognised_option('-ppunicode',pretty_print_internal_rep(File,'$auto',needed,unicode),[File],
5485 prob_cli:check_file_arg(File,'pp')).
5486 recognised_option('-ppf',pretty_print_internal_rep(File,'$auto',all,ascii),[File],
5487 prob_cli:check_file_arg(File,'ppf')).
5488 recognised_option('-ppAB',pretty_print_internal_rep(File,'$auto',all,atelierb),[File],
5489 prob_cli:check_file_arg(File,'ppAB')).
5490 recognised_option('-pp_with_name',pretty_print_internal_rep(File,MachName,all,ascii),[MachName,File],
5491 prob_cli:check_file_arg(File,'pp_with_name')). % provide explicit machine name
5492 recognised_option('-ppB',pretty_print_internal_rep_to_B(File),[File],
5493 prob_cli:check_file_arg(File,'ppB')). % deprecated; is now superseded by ppAB for Event-B machines
5494 recognised_option('-pppl',pretty_print_prolog_file(File),[File],
5495 prob_cli:check_file_arg(File,'pppl')).
5496 recognised_option('-pp_pl_file',pretty_print_prolog_file(File,OutFile),[File,OutFile],
5497 (prob_cli:check_file_arg(File,'pp_pl_file'),prob_cli:check_file_arg(OutFile,'pp_pl_file'))).
5498 recognised_option('-ppi',indent_main_b_file(File),[File],
5499 prob_cli:check_file_arg(File,'ppi')).
5500 recognised_option('-indent_b_file',indent_b_file_to_file(BFile,OutFile,[]),[BFile,OutFile], % indent some other file
5501 (prob_cli:check_file_arg(BFile,'indent_b_file'),prob_cli:check_file_arg(OutFile,'indent_b_file'))).
5502 recognised_option('-reformat_b_file',indent_b_file_to_file(BFile,OutFile,
5503 [insert_new_lines_before_keywords,insert_new_lines_after_keywords]),[BFile,OutFile], % reformat some other file
5504 (prob_cli:check_file_arg(BFile,'indent_b_file'),prob_cli:check_file_arg(OutFile,'indent_b_file'))).
5505 recognised_option('-save_state',save_state_space(Filename),[Filename],
5506 prob_cli:check_file_arg(Filename,'save_state')). % possibly save_state_space would be a better name
5507 recognised_option('-save',save_state_for_refinement(Filename),[Filename],
5508 prob_cli:check_file_arg(Filename,'save')).
5509 recognised_option('-sptxt',print_values(Filename),[Filename],
5510 prob_cli:check_file_arg(Filename,'sptxt')).
5511 recognised_option('-sstxt',print_all_values(Dirname),[Dirname],
5512 prob_cli:check_file_arg(Dirname,'sstxt')).
5513 recognised_option('-latex',process_latex_file(In,Out),[In,Out],
5514 (prob_cli:check_file_arg(In,'latex'),prob_cli:check_file_arg(Out,'latex'))).
5515 recognised_option('-bench_csv',benchmark_info_csv_output(File,write,csv),[File],prob_cli:check_file_arg(File,'bench_csv')).
5516 recognised_option('-bench_csv_append',benchmark_info_csv_output(File,append,csv),[File],prob_cli:check_file_arg(File,'bench_csv')).
5517 recognised_option('-bench_tex',benchmark_info_csv_output(File,write,latex),[File],prob_cli:check_file_arg(File,'bench_tex')).
5518 recognised_option('-trace_replay',trace_check(Style,File,default_trace_replay),[Style,File],prob_cli:check_file_arg(File,'trace_replay')). % Style can be json, prolog or B
5519 recognised_option('-det_trace_replay',trace_check(Style,File,deterministic_trace_replay),[Style,File],prob_cli:check_file_arg(File,'det_trace_replay')).
5520 recognised_option('-replay',eval_repl([File]),[File],prob_cli:check_file_arg(File,'replay')). % used to be -eval
5521 recognised_option('-state_trace',state_trace(File),[File],prob_cli:check_file_arg(File,'state_trace')).
5522 recognised_option('-typecheckertest',typechecker_test(File),[File],prob_cli:check_file_arg(File,'typecheckertest')).
5523 recognised_option('-enabling_analysis_csv',enabling_analysis_csv(EnablingCsvFile),[EnablingCsvFile],
5524 prob_cli:check_file_arg(EnablingCsvFile,'enabling_analysis_csv')).
5525 recognised_option('-dot_output',dot_analyse_output_prefix(Path),[Path],prob_cli:check_file_arg(Path,'dot_output')).
5526 recognised_option('-evaldot',evaldot(File),[File],prob_cli:check_file_arg(File,'evaldot')).
5527 recognised_option('-his',history(File),[File],prob_cli:check_file_arg(File,'his')).
5528 recognised_option('-visb_click',visb_click(SVGID),[SVGID],true).
5529 recognised_option('-visb',visb_history(JSONFile,HTMLFile,[]),[JSONFile,HTMLFile],
5530 (prob_cli:check_file_arg(JSONFile,'visb'),prob_cli:check_file_arg(HTMLFile,'visb'))).
5531 recognised_option('-visb_with_vars',
5532 visb_history(JSONFile,HTMLFile,[show_constants(all),show_sets(all),show_variables(all)]),
5533 [JSONFile,HTMLFile],
5534 (prob_cli:check_file_arg(JSONFile,'visb_with_vars'),prob_cli:check_file_arg(HTMLFile,'visb_with_vars'))).
5535 recognised_option('-rule_report',rule_report(File), [File], prob_cli:check_file_arg(File,'rule_report')).
5536 recognised_option('-proof_export',proof_export(Style,File), [Style,File], prob_cli:check_file_arg(File,'proof_export')). % Style can be html, bpr or a dot output format
5537 recognised_option('-bench_alloy_cmd',run_benchmark(alloy,CmdNames,AlloyFilePath),[CmdNames,AlloyFilePath],prob_cli:check_file_arg(AlloyFilePath,'bench_alloy_cmd')).
5538 recognised_option('-bench_smt_cbc_inv',run_benchmark(smt,cbc_inv,Folder),[Folder],prob_cli:check_file_arg(Folder,'bench_smt_cbc_inv')).
5539 recognised_option('-bench_smt_cbc_deadlock',run_benchmark(smt,cbc_deadlock,Folder),[Folder],prob_cli:check_file_arg(Folder,'bench_smt_cbc_deadlock')).
5540 recognised_option('-bench_smt_bmc',run_benchmark(smt,bmc,Folder),[Folder],prob_cli:check_file_arg(Folder,'bench_smt_bmc')).
5541 recognised_option('-eval_file',eval_string_or_file(file(default),F,exists,_ANY,norecheck),[F],prob_cli:check_file_arg(F,'eval_file')).
5542 recognised_option('-evalt_file',eval_string_or_file(file(default),F,exists,'TRUE',norecheck),[F],prob_cli:check_file_arg(F,'evalt_file')).
5543 recognised_option('-eval_rule_file',eval_string_or_file(file(default),F,forall,_ANY,norecheck),[F],prob_cli:check_file_arg(F,'eval_rule_file')).
5544 recognised_option('-solve_file',eval_string_or_file(file(Solver),F,exists,_ANY,norecheck),[Solver,F],prob_cli:check_file_arg(F,'eval_file')).
5545
5546 recognised_option('-zmq_assertions',zmq_assertion(Identifier),[Identifier],true).
5547 recognised_option('-zmq_worker',zmq_worker(Identifier),[Identifier], true).
5548 %recognised_option('-zmq_worker2',zmq_worker2(MasterIP, Port, ProxyID, Logfile),[MasterIP, SPort, SProxyID, Logfile],
5549 % tools:(arg_is_number(SPort,Port), arg_is_number(SProxyID, ProxyID))).
5550 recognised_option('-p',set_pref(NPREF,PREFVAL),[PREF,PREFVAL],prob_cli:normalise_pref_name(PREF,NPREF)).
5551 recognised_option('-pref',set_pref(NPREF,PREFVAL),[PREF,PREFVAL],prob_cli:normalise_pref_name(PREF,NPREF)).
5552 recognised_option('-prob_application_type',set_application_type(T),[T],true).
5553 recognised_option('-cbc_redundant_invariants',cbc_redundant_invariants(Nr),[X],tools:arg_is_number(X,Nr)).
5554 recognised_option('-expcterrpos',expect_error_pos(Type,LNr,CNr),[Type,Line,Col],
5555 (tools:arg_is_number(Line,LNr),tools:arg_is_number(Col,CNr))).
5556 recognised_option('-pref_group',set_preference_group(NGroup,Val),[Group,Val],
5557 (prob_cli:normalise_option_atom(Group,NGroup))).
5558 recognised_option('-save_all_traces_until',generate_all_traces_until(Formula,FilePrefix),
5559 [Formula,FilePrefix],
5560 true). % we could check LTL formula and FilePrefix
5561 recognised_option('-check_machine_file_sha',check_machine_file_sha(FILE,SHA1),[FILE,SHA1],
5562 prob_cli:check_file_arg(FILE,'check_machine_file_sha')).
5563 recognised_option('-sha1sum',Command,Args,Call) :-
5564 recognised_option('-check_machine_file_sha',Command,Args,Call).
5565 recognised_option('-animate_until_ltl_steps',animate_until_ltl(Formula,no_loop,ltl_found,Steps),[Formula,A],
5566 tools:arg_is_number(A,Steps)).
5567 recognised_option('-gc_margin',set_gc_margin(Nr),[X], tools:arg_is_number(X,Nr)).
5568
5569 % recognised_option/3
5570 recognised_option('-prefs',set_prefs_from_file(PREFFILE),[PREFFILE]).
5571 %recognised_option('-plugin',plugin(Plugin), [Plugin]).
5572 recognised_option('-card',set_card(SET,SCOPE),[SET,SCOPE]).
5573 recognised_option('-argv',set_argv(ARGV),[ARGV]).
5574 recognised_option('-goal',set_goal(GOAL),[GOAL]).
5575 recognised_option('-property',add_additional_property(PRED),[PRED]).
5576 recognised_option('-scope',set_searchscope(GOAL),[GOAL]).
5577 recognised_option('-searchscope',set_searchscope(GOAL),[GOAL]).
5578 recognised_option('-search_scope',set_searchscope(GOAL),[GOAL]).
5579 recognised_option('-eval',eval_string_or_file(string,E,exists,_,norecheck),[E]).
5580 recognised_option('-evalt',eval_string_or_file(string,E,exists,'TRUE',norecheck),[E]).
5581 recognised_option('-evalf',eval_string_or_file(string,E,exists,'FALSE',norecheck),[E]).
5582 recognised_option('-evalt_rc',eval_string_or_file(string,E,exists,'TRUE',recheck(ascii)),[E]).
5583 recognised_option('-evalf_rc',eval_string_or_file(string,E,exists,'FALSE',recheck(ascii)),[E]).
5584 recognised_option('-evalu',eval_string_or_file(string,E,exists,'UNKNOWN',norecheck),[E]).
5585 recognised_option('-evalnwd',eval_string_or_file(string,E,exists,'NOT-WELL-DEFINED',norecheck),[E]).
5586 recognised_option('-parsercp',parsercp(L),[L]). % deprecated
5587 recognised_option('-parserport',parserport(L),[L]).
5588 recognised_option('-expcterr',expect_error(Type),[Type]).
5589 recognised_option('-expecterr',expect_error(Type),[Type]).
5590 recognised_option('-expect',expect_error(Type),[Type]).
5591 recognised_option('-opterr',optional_error(Type),[Type]).
5592 recognised_option('-his_option',history_option(Option),[Option]). % trace_file, json, show_init, show_states
5593 recognised_option('-cache',cache_storage(D,strict),[D]). % for value_persistance caching
5594 recognised_option('-ccache',cache_storage(D,create_if_needed),[D]). % ditto
5595 recognised_option('-show_cache',show_cache(default),[]).
5596 recognised_option('-show_cache_verbose',show_cache(verbose),[]).
5597 recognised_option('-cache_statistics',cli_print_statistics(value_persistance_stats),[]).
5598 recognised_option('-cache_stats',cli_print_statistics(value_persistance_stats),[]). % synonym
5599 % see also -check_cache_stats
5600 recognised_option('-clear_cache',clear_value_persistance_cache,[]).
5601 recognised_option('-clear_cache_for',clear_value_persistance_cache(Machine),[Machine]).
5602 recognised_option('-hshow',cli_print_statistics(hshow),[]). % machine inclusion hierarchy
5603 recognised_option('-show_inclusion_hierarchy',cli_print_statistics(hshow),[]). % machine inclusion hierarchy
5604
5605 recognised_option('-MAIN',csp_main(ProcessName),[ProcessName]).
5606
5607 recognised_option('-ltlformula',ltl_formula_model_check(Formula,_),[Formula]).
5608 recognised_option('-ltlformulat',ltl_formula_model_check(Formula,true),[Formula]).
5609 recognised_option('-ltlformulaf',ltl_formula_model_check(Formula,false),[Formula]).
5610 recognised_option('-ctlformula',ctl_formula_model_check(Formula,_),[Formula]).
5611 recognised_option('-ctlformulat',ctl_formula_model_check(Formula,true),[Formula]).
5612 recognised_option('-ctlformulaf',ctl_formula_model_check(Formula,false),[Formula]).
5613 recognised_option('-pctlformula',pctl_formula_model_check(Formula,_),[Formula]).
5614 recognised_option('-pctlformulat',pctl_formula_model_check(Formula,true),[Formula]).
5615 recognised_option('-pctlformulaf',pctl_formula_model_check(Formula,false),[Formula]).
5616 recognised_option('-animate_until_ltl',animate_until_ltl(Formula,no_loop,_,_),[Formula]).
5617 recognised_option('-animate_until_ltl_state_property',animate_until_ltl(Formula,ltl_state_property,_,_),[Formula]).
5618
5619
5620 %recognised_option('-cspref',csp_in_situ_refinement_check(assertRef('False',val_of(AbsP1,no_loc_info_available),Type,val_of(ImplP2,no_loc_info_available),no_loc_info_available),'False'),[AbsP1,Type,ImplP2]).
5621 recognised_option('-cspref',csp_in_situ_refinement_check(AbsP1,Type,ImplP2),[AbsP1,Type,ImplP2]).
5622 % -cspref R [F= Q
5623 recognised_option('-cspdeadlock',csp_checkAssertion(Proc,Model,'deadlock free'),[Proc,Model]).
5624 % -cspdeadlock R F
5625 recognised_option('-cspdeterministic',csp_checkAssertion(Proc,Model,'deterministic'),[Proc,Model]).
5626 % -cspdeterministic R F
5627 recognised_option('-csplivelock',csp_checkAssertion(Proc,'FD','livelock free'),[Proc]).
5628 % -csplivelock R
5629 % -csp_assertion "P [F= Q"
5630 recognised_option('-csp_assertion',check_csp_assertion(Assertion),[Assertion]).
5631 recognised_option('-csp_eval', eval_csp_expression(Expr),[Expr]).
5632 recognised_option('-get_csp_assertions_as_string',csp_get_assertions,[]).
5633
5634 recognised_option('-variable_coverage',csv_table_command(variable_coverage,[],[text_output],user_output),[]).
5635 recognised_option('-vacuity_check',vacuity_check,[]).
5636 recognised_option('-wd_check',cli_wd_check(_,_),[]).
5637 recognised_option('-wd_check_all',cli_wd_check(X,X),[]).
5638 recognised_option('-well_definedness_check',cli_wd_check(_,_),[]).
5639 recognised_option('-wd_inv_proof',cli_wd_inv_proof(_,_,_),[]).
5640 recognised_option('-lint',cli_lint,[]). % extended static check (ESC, esc)
5641 recognised_option('-lint_operations',cli_lint(operations),[]).
5642 recognised_option('-lint_variables',cli_lint(variables),[]).
5643 recognised_option('-cbc',constraint_based_check(OpName),[OpName]). % cbc invariant checking
5644 recognised_option('-cbc_invariant',constraint_based_check(OpName),[OpName]).
5645 recognised_option('-cbc_deadlock',cbc_deadlock_check(true),[]).
5646 recognised_option('-cbc_assertions',cbc_assertions(true,[]),[]).
5647 recognised_option('-cbc_main_assertions',cbc_assertions(true,[main_assertions]),[]).
5648 recognised_option('-cbc_assertions_proof',cbc_assertions(false,[]),[]). % do not allow enumeration warnings
5649 recognised_option('-cbc_assertions_tautology_proof',cbc_assertions(false,[tautology_check]),[]). % do not allow enumeration warnings + disregard PROPERTIES, used for Atelier-B proof/disproof; TO DO: also call WD prover
5650 recognised_option('-cbc_assertions_tautology_proof_check',cbc_assertions(false,[tautology_check,contradiction_check]),[]).
5651 recognised_option('-cbc_option',cbc_option(OPT),[OPT]). % should be tautology_check,contradiction_check, unsat_core
5652 recognised_option('-cbc_result_file',cbc_result_file(FILE),[FILE]). % write result to FILE
5653 recognised_option('-cbc_refinement',cbc_refinement,[]).
5654 recognised_option('-cbc_deadlock_pred',cbc_deadlock_check(GoalPred),[GoalPred]).
5655 recognised_option('-cbc_sequence',cbc_sequence(OpSequence,'',single_solution),[OpSequence]).
5656 recognised_option('-cbc_sequence_all',cbc_sequence(OpSequence,'',findall),[OpSequence]).
5657 recognised_option('-cbc_sequence_with_target',cbc_sequence(OpSequence,TargetPredString,single_solution),[OpSequence,TargetPredString]).
5658 recognised_option('-cbc_sequence_with_target_all',cbc_sequence(OpSequence,TargetPredString,findall),[OpSequence,TargetPredString]).
5659 recognised_option('-comment',comment(UserComment),[UserComment]). % not processed by tool, but will be stored in log-file and used by log_analyser
5660 recognised_option('-junit',junit(Dir),[Dir]).
5661 recognised_option('-mcm_cover', mcm_cover(Event),[Event]).
5662 recognised_option('-cbc_cover', cbc_cover(Event),[Event]).
5663 recognised_option('-cbc_cover_match', cbc_cover(match_event(Event)),[Event]). % find events which have Event String occuring somewhere in name
5664 recognised_option('-cbc_cover_all', cbc_cover_all,[]). % is now default if no cbc_cover provided
5665 recognised_option('-cbc_cover_final', cbc_cover_final,[]).
5666 recognised_option('-bmc', cbc_tests(Depth,'#not_invariant',''),[Depth]).
5667 recognised_option('-bdc', cbc_tests(Depth,'#deadlock',''),[Depth]).
5668 recognised_option('-enabling_analysis',enabling_analysis_csv(user_output),[]).
5669 recognised_option('-feasibility_analysis',feasibility_analysis_csv(1000,user_output),[]).
5670 recognised_option('-read_write_matrix',generate_read_write_matrix_csv(user_output),[]).
5671 recognised_option('-scc_trace',check_scc_for_ltl_formula(LtlFormula,SCC),[LtlFormula,SCC]).
5672 recognised_option('-selfcheck_module',selfcheck(M,[]),[M]).
5673 recognised_option('-mc_mode',depth_breadth_first_mode(M),[M]). % can be mixed, hash, heuristic
5674 recognised_option('-assertion',cli_check_assertions(specific(X),[false/0,unknown/0]),[X]).
5675 recognised_option('-cbc_assertion',cbc_assertions(true,[specific(X)]),[X]). % check only a specific assertion
5676 recognised_option('-symbolic_model_check', cli_symbolic_model_check(Algorithm), [Algorithm]).
5677 recognised_option('-ltsmin2',ltsmin2(EndpointPath), [EndpointPath]).
5678 recognised_option('-ltsmin_ltl_output',ltsmin_ltl_output(Path), [Path]).
5679 recognised_option('-ltsmin_option', ltsmin_option(X),[X]).
5680 recognised_option('-machine_hash_check',cli_print_machine_info(hash(X)),[X]).
5681 recognised_option('-install',install_prob_lib(X,[]),[X]).
5682 recognised_option('-install_dry_run',install_prob_lib(X,[dryrun]),[X]).
5683
5684
5685 recognised_option('-dot_all',dot_generate_for_all_formulas). % generate dot also for true formulas
5686 recognised_option('-animate_all',cli_random_animate(2147483647,false)).
5687 recognised_option('-execute_all',execute(2147483647,false,current_state(1))).
5688 recognised_option('-execute_all_inits',execute(2147483647,false,from_all_initial_states)).
5689 recognised_option('-animate_stats',animate_stats).
5690 recognised_option('-execute_monitor',execute_monitoring).
5691 recognised_option('-check_goal',check_goal).
5692 recognised_option('-ltlassertions',ltl_assertions).
5693 recognised_option('-assertions',cli_check_assertions(all,[false/0,unknown/0])).
5694 recognised_option('-main_assertions',cli_check_assertions(main,[false/0,unknown/0])).
5695 recognised_option('-properties',cli_check_properties).
5696 recognised_option('-properties_core',cli_core_properties(_)). % variable as arg: try various algorithms in order
5697 recognised_option('-properties_core_wd',cli_core_properties(wd_prover)).
5698 recognised_option('-properties_core_z2',cli_core_properties(z3_bup(2))).
5699 recognised_option('-properties_core_z3',cli_core_properties(z3_bup(3))).
5700 recognised_option('-selfcheck',selfcheck(_,[])).
5701 recognised_option('-pacheck',pa_check). % predicate analysis for Kodkod
5702 recognised_option('-det_check',det_check). % check if animation is deterministic
5703 recognised_option('-det_constants',det_constants_check). % check if animation for setup_constants is deterministic
5704 recognised_option('-bf',breadth_first).
5705 recognised_option('-breadth',breadth_first).
5706 recognised_option('-df',depth_first).
5707 recognised_option('-depth',depth_first).
5708 recognised_option('-strict',strict_raise_error).
5709 recognised_option('-silent',silent).
5710 recognised_option('-quiet',silent).
5711 recognised_option('-q',silent).
5712 recognised_option('-force_no_silent',force_no_silent). % override provided silent flag; useful for gitlab test debugging
5713 recognised_option('-statistics',cli_print_statistics(full)).
5714 recognised_option('-stats',cli_print_statistics(full)).
5715 recognised_option('-memory_stats',cli_print_statistics(memory)).
5716 recognised_option('-memory_statistics',cli_print_statistics(memory)).
5717 recognised_option('-memory',cli_print_statistics(memory)).
5718 recognised_option('-profile_stats',cli_print_statistics(sicstus_profile)).
5719 recognised_option('-profile_statistics',cli_print_statistics(sicstus_profile)).
5720 recognised_option('-op_cache_profile',cli_print_statistics(op_cache_profile)).
5721 recognised_option('-hit_profile',cli_print_statistics(hit_profile)). % mainly for ProB developers
5722 recognised_option('-reset_profile_statistics',reset_profiler). % mainly for use in REPL
5723 recognised_option('-nodead',no_deadlocks).
5724 recognised_option('-no_dead',no_deadlocks).
5725 recognised_option('-no_deadlocks',no_deadlocks).
5726 recognised_option('-noinv',no_invariant_violations).
5727 recognised_option('-no_inv',no_invariant_violations).
5728 recognised_option('-no_invariant_violations',no_invariant_violations).
5729 recognised_option('-nogoal',no_goal).
5730 recognised_option('-no_goal',no_goal).
5731 recognised_option('-noltl',no_ltl). % just used for TLC at the moment
5732 recognised_option('-no_ltl',no_ltl).
5733 recognised_option('-noass',no_assertion_violations).
5734 recognised_option('-no_ass',no_assertion_violations).
5735 recognised_option('-no_assertion_violations',no_assertion_violations).
5736 recognised_option('-no_state_errors',no_state_errors). % disable checking for general_errors and transition related state_errors
5737 recognised_option('-nocounter',no_counter_examples).
5738 recognised_option('-no_counter_examples',no_counter_examples).
5739 recognised_option('-nocolor',no_color).
5740 recognised_option('-no_color',no_color).
5741 recognised_option('-no_colour',no_color).
5742 recognised_option('-disable_time_out',set_preference_group(time_out,disable_time_out)).
5743 recognised_option('-disable_timeout',set_preference_group(time_out,disable_time_out)).
5744 %recognised_option('-POR',with_reduction).
5745 recognised_option('-i',animate).
5746 recognised_option('-repl',eval_repl([])). % used to be -eval
5747 recognised_option('-c',coverage(false)).
5748 recognised_option('-cs',coverage(just_summary)).
5749 recognised_option('-coverage',coverage(false)).
5750 recognised_option('-coverage_summary',coverage(just_summary)).
5751 recognised_option('-machine_stats',cli_print_machine_info(statistics)).
5752 recognised_option('-machine_statistics',cli_print_machine_info(statistics)).
5753 recognised_option('-machine_files',cli_print_machine_info(files(no_sha))).
5754 recognised_option('-machine_files_sha',cli_print_machine_info(files(with_sha))).
5755 recognised_option('-machine_hash',cli_print_machine_info(hash(_))).
5756 recognised_option('-check_abstract_constants',check_abstract_constants).
5757 recognised_option('-op_cache_stats',check_op_cache([])).
5758 recognised_option('-op_cache_statistics',check_op_cache([])).
5759 recognised_option('-cv',coverage(true)).
5760 recognised_option('-v',verbose(19)).
5761 recognised_option('-vv',verbose(5)).
5762 recognised_option('-vvv',verbose(1)).
5763 recognised_option('-verbose',verbose(19)).
5764 recognised_option('-debug',verbose(19)).
5765 recognised_option('-verbose_off',verbose_off). % mainly useful in REPL
5766 recognised_option('-voff',verbose_off). % mainly useful in REPL
5767 recognised_option('-very_verbose',verbose(5)).
5768 recognised_option('-gc_trace',set_gc_trace(verbose)).
5769 recognised_option('-gc_off',set_gc_on_off(off)).
5770 recognised_option('-gc_on',set_gc_on_off(on)).
5771 recognised_option('-profiling_on',profiling_on). % Prolog profiling
5772 recognised_option('-profile',cli_print_statistics(prob_profile)). % ProB Operation profiling
5773 recognised_option('-prob_profile',cli_print_statistics(prob_profile)). % ProB Operation profiling
5774 recognised_option('-prob_statistics',cli_print_statistics(prob_profile)). % synonym
5775 recognised_option('-prob_stats',cli_print_statistics(prob_profile)). % synonym
5776 recognised_option('-version',print_version(full)).
5777 recognised_option('-cpp_version',print_version(cpp)).
5778 recognised_option('-V',print_version(full)).
5779 recognised_option('-svers',print_version(short)).
5780 recognised_option('-short_version',print_version(short)).
5781 recognised_option('-check_lib',print_version(lib)).
5782 recognised_option('-check_java_version',check_java_version).
5783 recognised_option('-java_version',print_version(java)).
5784 recognised_option('-release_java_parser',release_java_parser).
5785 recognised_option('-fast_read_prob',fast_read_prob).
5786 recognised_option('-file_info',file_info).
5787 recognised_option('-t',default_trace_check).
5788 recognised_option('-init',initialise).
5789 recognised_option('-initialise',initialise).
5790 recognised_option('-ll',log('/tmp/prob_cli_debug.log',prolog)). % see cli_start_logging
5791 recognised_option('-ss',socket(9000,true)). % standard socket 9000
5792 recognised_option('-sf',socket(_,true)). % free socket
5793 recognised_option('-local_socketserver',socket(_,true)). % do not allow remote socket connections
5794 recognised_option('-remote_socketserver',socket(_,false)). % allow remote socket connections
5795 recognised_option('-help',help).
5796 recognised_option('-h',help).
5797 recognised_option('-rc',runtimechecking).
5798 recognised_option('-test_mode',test_mode).
5799 recognised_option('-check_complete',check_complete).
5800 recognised_option('-check_complete_operation_coverage', check_complete_operation_coverage).
5801 recognised_option('-mc_with_tlc', cli_start_mc_with_tlc).
5802 recognised_option('-mc_with_lts_sym', cli_start_sym_mc_with_lts(symbolic)).
5803 recognised_option('-mc_with_lts_seq', cli_start_sym_mc_with_lts(sequential)).
5804 recognised_option('-core',disprover_options([disprover_option(unsat_core),unsat_core_algorithm/linear])).
5805 recognised_option('-export_po',disprover_options([disprover_option(export_po_as_machine(user_output))])).
5806 recognised_option('-ltsmin',ltsmin).
5807 recognised_option('-trace',prolog_trace). % enter Prolog debugger on development system after starting up ProB
5808
5809 % some utilities to be able to call the above options directly from repl:
5810 :- public silent/0, coverage/1, help/0.
5811 % predicate to set_verbose_mode
5812 %verbose :- tcltk_turn_debugging_on(19).
5813 %very_verbose :- tcltk_turn_debugging_on(5).
5814 verbose(Nr) :- tcltk_turn_debugging_on(Nr),
5815 (Nr<10 -> set_gc_trace(verbose) ; true). % terse is another option for gc_trace
5816 verbose_off :- set_gc_trace(off), tcltk_turn_debugging_off.
5817 file_info :- file_loaded(true,MainFile), print_file_info(MainFile).
5818 coverage(ShowEnabledInfo) :- probcli_time_stamp(NOW), cli_show_coverage(ShowEnabledInfo,NOW).
5819
5820 % Governs global stack garbage collection trace messages
5821 set_gc_trace(X) :- member(X,[off,terse,verbose]),!,set_prolog_flag(gc_trace,X).
5822 set_gc_trace(X) :- add_error(prob_cli,'Illegal value for gc_trace:',X).
5823
5824 % At least Margin kilobytes of free global stack space are guaranteed to exist after a garbage collection
5825 set_gc_margin(Margin) :- set_prolog_flag(gc_margin,Margin).
5826 set_gc_on_off(OnOff) :- set_prolog_flag(gc,OnOff).
5827
5828 silent :- (option(silent) -> true ; assert_option(silent)).
5829 help :- eval_help.
5830 dot_command(DCommand,DotFile,DotEngine) :- call_dot_command_with_engine(DCommand,DotFile,[],DotEngine).
5831 dot_command_for_expr(DECommand,Expr,DotFile,Opts,DotEngine) :-
5832 call_dot_command_with_engine_for_expr(DECommand,Expr,DotFile,Opts,DotEngine).
5833
5834 plantuml_command(PCommand,UmlFile) :- call_plantuml_command(PCommand,UmlFile).
5835 plantuml_command_for_expr(PECommand,Expr,UmlFile,Opts) :-
5836 call_plantuml_command_for_expr(PECommand,Expr,UmlFile,Opts).
5837
5838 :- use_module(tools_io,[safe_intelligent_open_file/3]).
5839 csv_table_command(TCommand,Formulas,Options,CSVFile) :-
5840 append(Formulas,[TableResult],ActualArgs),
5841 OptionalArgs=[],
5842 format_with_colour_nl(user_output,[blue],'Calling table command ~w',[TCommand]),
5843 call_command(table,TCommand,_,ActualArgs,OptionalArgs),
5844 write_table_to_csv_file(CSVFile,Options,TableResult),
5845 format_with_colour_nl(user_output,[blue],'Finished exporting ~w to ~w',[TCommand,CSVFile]).
5846
5847
5848 save_state_space(StateFile) :- debug_println(20,'% Saving state space to file'),
5849 state_space:tcltk_save_state_space(StateFile).
5850 :- public load_state/1. % for REPL
5851 load_state(StateFile) :- debug_println(20,'% Loading state space from file'),
5852 state_space:tcltk_load_state(StateFile).
5853 :- public execute/3. % for REPL
5854 execute(ESteps,ErrOnDeadlock,From) :- cli_execute(ESteps,ErrOnDeadlock,From).
5855
5856 option_verbose :- option(verbose(_)).
5857 option_very_verbose :- debug_level_active_for(5).
5858
5859 set_random_seed_to_deterministic_start_seed :-
5860 % in test_mode we do not change the random number generator's initial seed
5861 true. %getrand(CurrState),setrand(CurrState). % this seems to be a no-op
5862
5863 :- if(predicate_property(set_random(_), _)).
5864 % SWI-Prolog's native API for reinitializing the RNG state.
5865 % The equivalent of this call is also performed automatically by SWI
5866 % when a random number is requested for the first time.
5867 set_new_random_seed :- set_random(seed(random)).
5868 :- else.
5869 % SICStus way of (re)initializing the RNG state.
5870 % Note that on SICStus, the initial RNG state after startup is always the same,
5871 % so it *must* be manually reinitialized like this to get actually random results!
5872 %:- use_module(library(random),[setrand/1]).
5873 set_new_random_seed :-
5874 now(TimeStamp), % getting the unix time
5875 setrand(TimeStamp). % setting new random seed by every execution of probcli
5876 :- endif.
5877
5878 halt_exception :- halt_exception(0).
5879 halt_exception(Code) :- throw(halt(Code)).
5880
5881 % -----------------
5882
5883 start_xml_feature(FeatureName,[CErrs1,CWarns1,CEErrs1]) :-
5884 debug_format(20,'% Starting ~w~n',[FeatureName]),
5885 get_counter(cli_errors,CErrs1), get_counter(cli_warnings,CWarns1), get_counter(cli_expected_errors,CEErrs1),
5886 start_xml_group_in_log(FeatureName).
5887
5888 start_xml_feature(FeatureName,Attr,Value,[CErrs1,CWarns1,CEErrs1]) :-
5889 debug_format(20,'% Starting ~w (~w=~w)~n',[FeatureName,Attr,Value]),
5890 get_counter(cli_errors,CErrs1), get_counter(cli_warnings,CWarns1), get_counter(cli_expected_errors,CEErrs1),
5891 start_xml_group_in_log(FeatureName,Attr,Value).
5892
5893 stop_xml_feature(FeatureName,[CErrs1,CWarns1,CEErrs1]) :-
5894 get_counter(cli_errors,CErrs2), get_counter(cli_warnings,CWarns2), get_counter(cli_expected_errors,CEErrs2),
5895 CErrs is CErrs2-CErrs1, CWarns is CWarns2-CWarns1, CEErrs is CEErrs2-CEErrs1,
5896 (CEErrs>0
5897 -> write_xml_element_to_log('probcli-errors',[errors/CErrs,warnings/CWarns,expected_errors/CEErrs])
5898 ; write_xml_element_to_log('probcli-errors',[errors/CErrs,warnings/CWarns])
5899 ),
5900 debug_format(20,'% Finished ~w (errors=~w, warnings=~w, expected_errors=~w)~n',[FeatureName,CErrs,CWarns,CEErrs]),
5901 stop_xml_group_in_log(FeatureName),
5902 !.
5903 stop_xml_feature(FeatureName,L) :-
5904 add_internal_error('Illegal or failed call:',stop_xml_feature(FeatureName,L)).
5905
5906 %(CErrs>0 -> (file_loaded(_,MainFile) -> true ; MainFile=unknown), Time=unknown, % TO DO: determine time
5907 % create_and_print_junit_result(['Feature',MainFile], FeatureName, Time, error) ; true).
5908 % Note: call stop_xml_group_in_log if the feature stops unexpectedly and you do not have the Info list available
5909
5910 % -----------------
5911
5912 :- public user:runtime_entry/1.
5913 user:runtime_entry(start) :- go_cli.
5914
5915 %save :- save_program('probcli.sav').
5916
5917 :- use_module(eventhandling,[announce_event/1]).
5918 :- announce_event(compile_prob).