:- module temp.

:- interface.

:- import_module io.

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

:- type bool ---> yes ; no.

% exp ::= true | false | and(exp, exp) | or(exp, exp)
:- type exp --->
   truth ;
   falsehood ;
   and(exp, exp) ;
   or(exp, exp).

:- type expression --->
   integer(int) ;
   negate(expression) ;
   plus(expression, expression) ;
   times(expression, expression).

%% :- type expression --->
%%    integer(int) ;
%%    unop(unaryOperation, expression) ;
%%    binop(expression, binaryOperation, expression).
%% :- type unaryOperation ---> negate.
%% :- type binaryOperation ---> plus ; times.


:- implementation.

:- import_module int.
:- import_module solutions.
:- import_module list.

:- pred foo(int).
:- mode foo(in) is semidet.
:- mode foo(out) is multi.
foo(1).
foo(2).
foo(3).

:- pred between(int, int, int).
:- mode between(in, in, out) is nondet.
:- mode between(in, in, in) is semidet.
between(Start, End, Start) :-
    Start =< End.
between(Start, End, X) :-
    Start < End,
    %NewStart is Start + 1,
    between(Start + 1, End, X).

:- pred first(list(T), T).
:- mode first(in, out) is semidet.
first([Head|_], Head).

:- pred sumList(list(int), int).
:- mode sumList(in, out) is det.
sumList([], 0).
sumList([Head|Tail], TempSum + Head) :-
    sumList(Tail, TempSum).
    %% Sum is TempSum + Head.

:- pred andHelper(bool, bool, bool).
:- mode andHelper(in, in, out) is det.
andHelper(yes, yes, yes).
andHelper(no, yes, no).
andHelper(yes, no, no).
andHelper(no, no, no).

:- pred orHelper(bool, bool, bool).
:- mode orHelper(in, in, out) is det.
orHelper(no, no, no).
orHelper(yes, no, yes).
orHelper(yes, yes, yes).
orHelper(no, yes, yes).

:- pred evaluate(exp, bool).
:- mode evaluate(in, out) is det.
evaluate(truth, yes).
evaluate(falsehood, no).
evaluate(and(E1, E2), Result) :-
    evaluate(E1, Left),
    evaluate(E2, Right),
    andHelper(Left, Right, Result).
evaluate(or(E1, E2), Result) :-
    evaluate(E1, Left),
    evaluate(E2, Right),
    orHelper(Left, Right, Result).

main(!IO) :-
    % true && (false || false)
    evaluate(and(truth, or(falsehood, falsehood)), Result),
    io.write(Result, !IO),
    io.write_string("\n", !IO).
