%---------------------------------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%---------------------------------------------------------------------------%
%
% Regression test for higher-order function call in code with common
% subexpression; mercury 0.7 failed this test, reporting
% "Software Error: modecheck fails when repeated",
% due to confusion between h.o. _function_ call and h.o. _predicate_ call.

:- module ho_func_call_1.

:- interface.
:- import_module io.

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

%---------------------------------------------------------------------------%

:- implementation.

:- import_module string.

main(IO, put_stocks(get_stocks(IO))).

:- type maybe(T)
    --->    yes(T)
    ;       no.

:- type code == int.
:- type qty == int.

:- type stock
    --->    stock(code, qty).

:- type iostocks
    --->    ios(io, stocks).

:- type stocks
    --->    []
    ;       [stock  | stocks]
    ;       closure(func(io) = iostocks).

:- inst iostocks == unique(ios(unique, stocks)).
:- inst stocks ==
    bound( [] ; [ground | stocks] ; closure(func(di) = is_out is det)).

:- mode is_in  == di(iostocks).
:- mode is_out == out(iostocks).

:- func put_stocks(iostocks) = io.
:- mode put_stocks(is_in) = uo is det.

put_stocks(ios(IO, [])) = IO.
put_stocks(ios(IO, [S | T])) = put_stocks(ios(IO1, T)) :-
    out_stock(S, IO, IO1).
put_stocks(ios(IO, closure(Func))) = put_stocks(apply(Func, IO)).

:- pred out_stock(stock::in, io::di, io::uo) is det.

out_stock(stock(C, Q), !IO) :-
%   io.format("%i %i\n", [i(C), i(Q)]).
    io.write_int(C, !IO),
    io.write_char(' ', !IO),
    io.write_int(Q, !IO),
    io.nl(!IO).

:- func get_stocks(io) = iostocks.
:- mode get_stocks(di) = is_out is det.

get_stocks(S0) = ios(S, Stocks) :-
    tokenize(MStock, S0, S),
    ( MStock = no, Stocks = []
    ; MStock = yes(Stock), Stocks = [Stock | closure(get_stocks)]
    ).

:- pred tokenize(maybe(stock)::out, io::di, io::uo) is det.

tokenize(S, !IO) :-
    io.read_line(CL0, !IO),
    ( if
        CL0 = ok(CL),
        string.from_char_list(CL, Line),
        string.sub_string_search(Line, " ", Index),
        string.split(Line, Index, Left, Right0),
        string.first_char(Right0, _, Right),
        string.to_int(Left, Code),
        string.to_int(Right, Qty)
    then
        S = yes(stock(Code, Qty))
    else
        S = no
    ).
