% Check that initialisers that terminate with an uncaught exception
% cause the program to abort rather than keep running.
%
:- module init_excp.
:- interface.

:- import_module io.

:- pred main(io::di, io::uo) is det.

:- implementation.

:- import_module exception.

:- initialise init_pred_a/2.	% Should be called first and succeed.
:- initialise init_pred_b/2.	% Should be called second and abort.
:- initialise init_pred_c/2.	% Should *not* be called.
:- finalise final_pred/2.	% Should *not* be called.

   % Catching an exception within an initialiser is okay.
   %
:- pred init_pred_a(io::di, io::uo) is cc_multi.

init_pred_a(!IO) :-
	io.write_string("This is init_pred_a/2\n", !IO),
	try(get_string(561), Result),
	(
		Result = succeeded(_),
		io.write_string("SUCCEEDED\n", !IO)
	;
		Result = exception(_),
		io.write_string("EXCEPTION\n", !IO)
	),
	io.flush_output(!IO).

:- pred get_string(int::in, string::out) is det.

get_string(X, Str) :-
	( X = 561 ->
		throw(magic_number_exception)
	;
		Str = "not 561"
	).	

   % Not catching one should cause the program to abort.
   %
:- pred init_pred_b(io::di, io::uo) is det.

init_pred_b(!IO) :- 
	get_magic_number(X, !IO),
	( X = 3 ->
		throw(magic_number_exception)
	;
		io.write_string("This is init_pred_b/2\n", !IO)
	).

:- type magic_number_exception ---> magic_number_exception.

:- pred get_magic_number(int::out, io::di, io::uo) is det.

get_magic_number(3, !IO).

   % Subsequent initialisers should not be run if this happens.
   %
:- pred init_pred_c(io::di, io::uo) is det.

init_pred_c(!IO) :-
	io.write_string("I should not be running.\n", !IO). 

   % Nor should main/2.
   %
main(!IO) :-
	io.write_string("This is main/2\n", !IO).

   % No finalisers should be run.
   %
:- pred final_pred(io::di, io::uo) is det.

final_pred(!IO) :-
	io.write_string("I should not be running either.\n", !IO). 
