%---------------------------------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%---------------------------------------------------------------------------%

:- module exceptions.

:- interface.

:- import_module io.

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

:- implementation.

:- import_module exception.
:- import_module int.
:- import_module list.
:- import_module maybe.
:- import_module univ.

main(!IO) :-
    % Test finding wrong answer children with a try_all.
    q(MaybeExcp, Solutions),
    ( if
        % Test finding missing answer children with a try_all.
        r(_)
    then
        io.write_string("yes\n", !IO)
    else
        io.write_string("no\n", !IO)
    ),
    ( if
        % Test finding exception children when there is backtracking.
        v(X)
    then
        io.write_int(X, !IO)
    else
        io.write_string("no\n", !IO)
    ),
    io.write({MaybeExcp, Solutions}, !IO),
    io.nl(!IO).

:- pred p(int::out) is multi.

p(X) :-
    ( X = 1
    ; X = 2
    ; X = 3
    ; throw("Error")
    ).

:- pred q(maybe(univ)::out, list(int)::out) is cc_multi.

q(MaybeExcp, Solutions) :-
    try_all(p, MaybeExcp, Solutions).

:- pred r({maybe(univ), list(int)}::out) is semidet.

r(Sols) :-
    % This is a lie, but is the only way I seem to be able to call try_all
    % in a failing context.
    promise_equivalent_solutions [Sols] (
        t(Sols)
    ),
    semidet_fail.

:- pred s(int::out) is multi.

s(X) :-
    ( X = 4
    ; X = 5
    ; X = 6
    ; throw("Error")
    ).

:- pred t({maybe(univ), list(int)}::out) is cc_multi.

t(S) :-
    try_all(s, MaybeExcp, Solutions),
    S = {MaybeExcp, Solutions}.

:- pred u(int::out) is multi.

u(X) :-
    ( X = 7
    ; X = 8
    ; X = 9
    ; throw("Error")
    ).

:- pred v(int::out) is nondet.

v(X) :-
    y(Z),
    u(Y),
    x(Y),
    add(Y, Z, X).

:- pred x(int::in) is semidet.

x(1).

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

add(X, Y, X + Y).

:- pred y(int::out) is det.

y(1).
