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