% -----------------------------------------------------------------------------
%  (C) Altran Praxis Limited
% -----------------------------------------------------------------------------
% 
%  The SPARK toolset is free software; you can redistribute it and/or modify it
%  under terms of the GNU General Public License as published by the Free
%  Software Foundation; either version 3, or (at your option) any later
%  version. The SPARK toolset is distributed in the hope that it will be
%  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
%  Public License for more details. You should have received a copy of the GNU
%  General Public License distributed with the SPARK toolset; see file
%  COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
%  the license.
% 
% =============================================================================



/*** Normalize_negative_literals/2                        ***/
/*** This clause transforms all negative integer literals ***/
/*** in A into application of the unart - operator in B   ***/
/*** This is called from read_term_and_layout/1           ***/

/* Special base case - negative literal */
normalize_negative_literals(A, B) :-
        integer(A),
        A < 0,
        NA is -A,
        B = -(NA),
        !.

/* Base case - any other atom */
normalize_negative_literals(A, A) :-
    atomic(A),
    !.

/* Base case - any variable */
normalize_negative_literals(A, A) :-
    var(A),
    !.

/* General case */
normalize_negative_literals(A, B) :-
        A =.. [F|ARGS],
        normalize_arg_list(ARGS, BARGS),
        B =.. [F|BARGS],
        !.

normalize_arg_list([X], [Y]) :-
        normalize_negative_literals(X, Y),
        !.
normalize_arg_list([X|XL], [Y|YL]) :-
        normalize_negative_literals(X, Y),
        !,
        normalize_arg_list(XL, YL),
        !.
normalize_arg_list([], []) :- !.

/*** It isn't possible to backtrack over printq, so this stops the interpreter from
     trying to. ***/
backtrack_printq(X) :- printq(X), !.

/*** Renumber all variables in X from 1 (if there are any) and printq ***/
renumber_and_print(X) :-
        (
            novars(X),
            printq(X)
        ;
            \+ novars(X),
            mynumbervars(X, 1, _),
            backtrack_printq(X),
            fail
        ;
            true
        ).

rread(X) :-
        repeat,
           (
              seeing(F),                                        /* CFR015 */
              read_term_and_layout(XX),                         /* CFR015 */
              (
                 XX==end_of_file,                               /* CFR015 */
                 (                                              /* CFR015 */
                    F = user                                    /* CFR015 */
                 ;                                              /* CFR015 */
                    write('<<< End of command script '),        /* CFR015 */
                    print(F),                                   /* CFR015 */
                    write(' reached >>>'),                      /* CFR015 */
                    nl,                                         /* CFR015 */
                    retract(perform_script_file(F))             /* CFR015 */
                 ),                                             /* CFR015 */
                 !,                                             /* CFR015 */
                 seen,                                          /* CFR015 */
                 (                                              /* CFR015 */
                    perform_script_file(S),                     /* CFR015 */
                    write('<<< Resuming command script '),      /* CFR015 */
                    print(S),                                   /* CFR015 */
                    write(' >>>'),                              /* CFR015 */
                    nl,                                         /* CFR015 */
                    see(S)                                      /* CFR015 */
                 ;                                              /* CFR015 */
                    write('<<< Returning to interactive input >>>'), /*15 */
                    nl,                                         /* CFR015 */
                    see(user),                                  /* CFR015 */
                    prompt_user('CHECK|:')
                 ),                                             /* CFR015 */
                 /* Check to see whether command logging should be switched back on */
                 findall(X, perform_script_file(X), B),
                 length(B, DEPTH),
                 toplevel_execute(SOURCE, ORIGLOG),
                 (
                    DEPTH = 0,
                    SOURCE = user,
                    retractall(command_logging(_)),
                    assertz(command_logging(ORIGLOG))
                 ;
                    DEPTH = 1,
                    SOURCE = script,
                    retractall(command_logging(_)),
                    assertz(command_logging(ORIGLOG))
                 ;
                    true
                 ),
                 rread(X)                                       /* CFR015 */
              ;
                 XX == '.',
                 seen,
                 write('Error on input stream - returning to interactive input'),  /* CFR015 */
                 nl,                                            /* CFR015 */
                 retractall(perform_script_file(_)),            /* CFR015 */
                 see(user),                                     /* CFR015 */
                 rread(X)                                       /* CFR015 */
              ;
                 X = XX,                                        /* CFR015 */
                 (                                              /* CFR015 */
                    F = user                                    /* CFR015 */
                 ;                                              /* CFR015 */
                    renumber_and_print(X),                      /* CFR015 */
                    write('.')                                  /* CFR015 */
                 ),                                             /* CFR015 */
                 !,                                             /* CFR015 */
                 (                                              /* CFR014 */
                    command_logging(on),                        /* CFR014 */
                    command_log_filename(L),                    /* CFR014 */
                    telling(T),                                 /* CFR014 */
                    /* halt if file can't be written to */
                    (
                       file_can_be_written(L)
                    ;
                       \+ file_can_be_written(L),
                       write('Aborted: '),
                       print(L),
                       write(' cannot be written.'),
                       nl,
                       !,
                       close_all_streams,
                       halt
                    ),
                    tell(L),                                    /* CFR014 */
                    renumber_and_print(X),
                    write('.'),                                 /* CFR014 */
                    nl,                                         /* CFR014 */
                    tell(T)                                     /* CFR014 */
                 ;                                              /* CFR014 */
                    command_logging(off)                        /* CFR014 */
                 )                                              /* CFR014 */
              )                                                 /* CFR014 */
           ;
              write('READ ERROR: garbage on input stream mandates reset.'),
              nl,
              nl,
              write('Please type CONTROL-C to resume use of the checker...'),
              nl,
              retractall(perform_script_file(_)),               /* CFR015 */
              repeat,
              fail
           ),
        !.

/*** ADD_NEW_HYP(H,N) - adds formula H as the first free hypothesis number
     after N ***/
add_new_hyp(true,_) :- !.
add_new_hyp(H,1) :- hyp(_,H), !.
add_new_hyp(H,N) :- hyp(N,_),
                    M is N+1, !,
                    add_new_hyp(H,M),
                    !.

add_new_hyp(H,N) :- assertz(hyp(N,H)),
                    assertz(logfact(newhyp, hyp(N,H))),
                    retractall(could_not_infer(_)),
                    stand_all,
                    new_hyp_message(N, H), !.                   /* CFR018 */


/*** ADD_NEW_CONC(C,N) - adds formula C as the first free conclusion number
     after N ***/
add_new_conc(C,N) :- conc(N,_), M is N+1, add_new_conc(C,M), !.
add_new_conc(C,N) :- assertz(conc(N,C)), assertz(logfact(newconc,conc(N,C))),
                     new_conc_message(N, C), !.                 /* CFR018 */


/*** new_hyp_message(No, Hyp) -- show it on screen ***/         /* CFR018 */
new_hyp_message(_N, _H) :-                                      /* CFR018 */
        show_vc_changes(off), !.                                /* CFR018 */
new_hyp_message(N, H) :-                                        /* CFR018 */
        write('*** New H'),                                     /* CFR018 */
        print(N),                                               /* CFR018 */
        write(':  '),                                           /* CFR018 */
        print(H),                                               /* CFR018 */
        nl,                                                     /* CFR018 */
        !.                                                      /* CFR018 */


/*** new_conc_message(No, Conc) -- show it on screen ***/       /* CFR018 */
new_conc_message(_N, _C) :-                                     /* CFR018 */
        show_vc_changes(off), !.                                /* CFR018 */
new_conc_message(N, C) :-                                       /* CFR018 */
        write('>>> New goal C'),                                /* CFR018 */
        print(N),                                               /* CFR018 */
        write(':  '),                                           /* CFR018 */
        print(C),                                               /* CFR018 */
        nl,                                                     /* CFR018 */
        !.                                                      /* CFR018 */


/* On NT, we get months as two-character numeric strings, which need to */
/* be converted into 3-character month names as follows: */
numeric_month_to_string("01", "JAN").
numeric_month_to_string("02", "FEB").
numeric_month_to_string("03", "MAR").
numeric_month_to_string("04", "APR").
numeric_month_to_string("05", "MAY").
numeric_month_to_string("06", "JUN").
numeric_month_to_string("07", "JUL").
numeric_month_to_string("08", "AUG").
numeric_month_to_string("09", "SEP").
numeric_month_to_string("10", "OCT").
numeric_month_to_string("11", "NOV").
numeric_month_to_string("12", "DEC").


/*** NEGIN(F,NewF) - move the nots in F in as far as possible to get NewF ***/
negin((not(P)),P1) :- !, neg(P,P1).
negin(for_all(X,P),for_all(X,P1)) :- !, negin(P,P1).
negin(for_some(X,P),for_some(X,P1)) :- !, negin(P,P1).
negin((P and Q),(P1 and Q1)) :- !, negin(P,P1), negin(Q,Q1).
negin((P or Q),(P1 or Q1)) :- !, negin(P,P1), negin(Q,Q1).
negin(P,P).


/*** NEG(F,NF) - return NF equivalent to "not F" but with nots moved in ***/
neg((not(P)),P1) :- !, negin(P,P1).
neg(for_all(X,P),for_some(X,P1)) :- !, neg(P,P1).
neg(for_some(X,P),for_all(X,P1)) :- !, neg(P,P1).
neg((P and Q),(P1 or Q1)) :- !, neg(P,P1), neg(Q,Q1).
neg((P or Q),(P1 and Q1)) :- !, neg(P,P1), neg(Q,Q1).
neg(A>B,A<=B) :- !.
neg(A<B,B<=A) :- !.
neg(A>=B,A<B) :- !.
neg(A<=B,B<A) :- !.
neg(A=B,A<>B) :- !.
neg(A<>B,A=B) :- !.
neg(P,(not(P))) :- !.


/*** VAR_FREE(J) - check no Prolog vars (or "goals") in justifications J ***/
var_free([]) :- !.
var_free([goal(_)|_]) :- !, fail. /** Prevent subgoaling on goal clauses **/
var_free([K|K1]) :- novars(K), var_free(K1), !.


/*** NO_VARS(F) - check no vars in (non-list) structure F ***/
novars(K) :- atomic(K), !.
novars(K) :- nonvar(K), K=..[_OP|Args], var_free(Args), !.


/* READ_ANSWER(Answer) -- read in a `yes' or a `no' from the user.          */
read_answer(Prompt,Answer):-
   repeat,
      print(Prompt),
      write(' (yes/no)? '),
      output_newline_if_necessary,                              /* CFR1334 */
      flush_output,
      get_yes_no_answer(Answer),                                /* CFR002 */
   /* until */ (Answer=yes ; Answer=no).

/* don't log output */
no_echo_read_answer(Prompt,Answer):-
   command_logging(ORIGLOG),
   retractall(command_logging(_)),
   assertz(command_logging(off)),
   repeat,
      print(Prompt),
      write(' (yes/no)? '),
      output_newline_if_necessary,                              /* CFR1334 */
      flush_output,
      get_yes_no_answer(Answer),                                /* CFR002 */
   /* until */ (Answer=yes ; Answer=no),
   retractall(command_logging(_)),
   assertz(command_logging(ORIGLOG)).


/* output_newline_if_necessary -- for interactive use inside editors, etc. */
output_newline_if_necessary :-                                  /* CFR1334 */
        newline_after_prompts(off), /* so no newline needed */  /* CFR1334 */
        !.                                                      /* CFR1334 */
output_newline_if_necessary :-      /* Otherwise... */          /* CFR1334 */
        nl,                                                     /* CFR1334 */
        !.                                                      /* CFR1334 */


/* GET_YES_NO_ANSWER(Answer) -- return `yes' or `no' from char input. */
get_yes_no_answer(Answer) :-                                    /* CFR002 */
        repeat,
           lget0(CH),                                           /* CFR014 */
           (
              (
                 CH = 89                /* "Y" */
              ;
                 CH = 121               /* "y" */
              ),
              Answer = yes,
              skip_to_terminator
           ;
              (
                 CH = 78                /* "N" */
              ;
                 CH = 110               /* "n" */
              ),
              Answer = no,
              skip_to_terminator
           ;
              eol_char(EOL),
              CH = EOL,                 /* RET */
              Answer = neither
           ),
           !.


/* skip_to_terminator -- skip to space, tab, CR, or full-stop */
skip_to_terminator :-                                           /* CFR002 */
        repeat,
           lget0(CHAR),                                         /* CFR014 */
        /* until */
        (
           CHAR = 32                    /* " " */
        ;
           CHAR =  9                    /* TAB */
        ;
           eol_char(EOL),
           CHAR = EOL                   /* RET */
        ),
        !.


/* lget0(CHAR) -- get0 CHAR and log if necessary + switch to user if EOF */
lget0(CHAR) :-                                                  /* CFR014 */
        seeing(F),                                              /* CFR014 */
        get_code(CH),                                           /* CFR014 */
        !,                                                      /* CFR014 */
        (                                                       /* CFR014 */
           eof_char(EOF),
           CH = EOF,                                            /* CFR015 */
           F \= user,                                           /* CFR015 */
           nl,                                                  /* CFR015 */
           write('<<< End of command script '),                 /* CFR015 */
           print(F),                                            /* CFR015 */
           write(' reached >>>'),                               /* CFR015 */
           nl,                                                  /* CFR015 */
           seen,                                                /* CFR015 */
           retract(perform_script_file(F)),                     /* CFR015 */
           (                                                    /* CFR015 */
              perform_script_file(S),                           /* CFR015 */
              write('<<< Resuming command script '),            /* CFR015 */
              print(S),                                         /* CFR015 */
              write(' >>>'),                                    /* CFR015 */
              nl,                                               /* CFR015 */
              see(S)                                            /* CFR015 */
           ;                                                    /* CFR015 */
              write('<<< Returning to interactive input >>>'),  /* CFR015 */
              nl,                                               /* CFR015 */
              see(user),                                        /* CFR015 */
              prompt_user('CHECK|:')
           ),                                                   /* CFR015 */
           /* Check to see whether command logging should be switched back on */
           findall(X, perform_script_file(X), B),
           length(B, DEPTH),
           toplevel_execute(SOURCE, ORIGLOG),
           (
              DEPTH = 0,
              SOURCE = user,
              retractall(command_logging(_)),
              assertz(command_logging(ORIGLOG))
           ;
              DEPTH = 1,
              SOURCE = script,
              retractall(command_logging(_)),
              assertz(command_logging(ORIGLOG))
           ;
              true
           ),
           lget0(CHAR)                                          /* CFR015 */
        ;                                                       /* CFR014 */
           CHAR = CH,                                           /* CFR014 */
           (                                                    /* CFR015 */
              F = user                                          /* CFR015 */
           ;                                                    /* CFR015 */
              put_code(CHAR)                                            /* CFR015 */
           ),                                                   /* CFR015 */
           !,                                                   /* CFR015 */
           (                                                    /* CFR014 */
              command_logging(on),                              /* CFR014 */
              command_log_filename(L),                          /* CFR014 */
              telling(T),                                       /* CFR014 */
              /* halt if file can't be written to */
              (
                 file_can_be_written(L)
              ;
                 \+ file_can_be_written(L),
                 write('Aborted: '),
                 print(L),
                 write(' cannot be written.'),
                 nl,
                 !,
                 close_all_streams,
                 halt
              ),
              tell(L),                                          /* CFR014 */
              put_code(CH),                                             /* CFR014 */
              tell(T)                                           /* CFR014 */
           ;                                                    /* CFR014 */
              true                                              /* CFR014 */
           )                                                    /* CFR014 */
        ),                                                      /* CFR014 */
        !.                                                      /* CFR014 */


/*** READ_ANSWER_ONCE(P,A) - prompt with P & get answer A; backtrack fails ***/
read_answer_once(P,A) :- read_answer(P,A), !.


/*** WRITE_JUSTS(J) - write out the list of justifications J on the screen ***/
write_justs([]) :- !.
write_justs([H|T]) :-
   nl,
   write('            '),
   print(H),
   write_justs(T), !.


/*** CREATE_FORMULA(L,F,G) - make G from list L & formula F as "L -> F" ***/
create_formula([],F,F) :- !.
create_formula([X],F,X -> F) :- !.
create_formula([X|Y],F,(X and Z) -> F) :- create_formula(Y,F,Z -> F), !.


/***** MESSAGE: useful for messages during non-interactive display-proof *****/
message :-
   nl,
   repeat,
      nl,
      read_term_and_layout(X),
      (X=stop ; print(X)),
   /* until */ X=stop,
   nl, !.

% Make this potential predicate call (potentially made during a
% non-interactive display-proof) visible to the spxref tool.
:- public message/0.


/******** TRIVIAL_COMMAND(C): command C does not affect VC ********/
trivial_command(list).
trivial_command(status).
trivial_command('help').
trivial_command(forget).
trivial_command(remember).
trivial_command(delete).
trivial_command(undelete).
trivial_command(consult) :- record_consults(off), !.
trivial_command('set').
trivial_command(show).
trivial_command(declare).
trivial_command(save_state).
trivial_command(traverse).
trivial_command(printvc).
trivial_command(execute).                                       /* CFR017 */
trivial_command(callpro).


/*** FORGET: tell checker not to show certain hypotheses ***/
forget :-
        (
           command_arg(hyplist,_)
        ;
           prompt_user('FORGET -- which hypothesis or hypotheses?','Hypotheses? '),
           rread(HYPS),
           parse_command_arguments(forget,HYPS)
        ),
        do_forgetting,
        !.


/*** DO_FORGETTING -- forget each hypothesis (or range) in turn ***/
do_forgetting :-
        command_arg(hyplist, HYPLIST),
        forget(HYPLIST),
        fail.
do_forgetting :- !.


/*** FORGET(HYPLIST) -- forget each hypothesis in hyplist ***/
forget([H|T]) :- forget(H), forget(T), !.
forget([]).
forget(N) :-
        integer(N),
        N > 0,                                                  /* CFR003 */
        \+ forgotten(N),
        \+ deleted(N),
        assertz(forgotten(N)),
        !.
forget(N) :-
        integer(N),
        N > 0,                                                  /* CFR003 */
        write('H'),
        print(N),
        write(' cannot be forgotten (it is already forgotten/deleted)'),
        nl,
        !.
forget(N) :-                                                    /* CFR003 */
        write('Illegal hypothesis number to forget: '),         /* CFR003 */
        print(N),                                               /* CFR003 */
        nl,                                                     /* CFR003 */
        !.                                                      /* CFR003 */


/*** DELETE: tell checker not to use certain hypotheses ***/
delete :-
        (
           command_arg(hyplist,_)
        ;
           prompt_user('DELETE -- which hypothesis or hypotheses?','Hypotheses? '),
           rread(HYPS),
           parse_command_arguments(delete,HYPS)
        ),
        do_deleting,
        !.


/*** DO_DELETING -- delete each hypothesis (or range) in turn ***/
do_deleting :-
        command_arg(hyplist, HYPLIST),
        delete(HYPLIST),
        retractall(could_infer(_)),
        fail.
do_deleting :- !.


/*** DELETE(HYPLIST) -- delete each hypothesis in hyplist ***/
delete([H|T]) :- delete(H), delete(T), !.
delete([]) :- !.
delete(N) :-
        integer(N),
        N > 0,                                                  /* CFR003 */
        \+ deleted(N),
        retract(hyp(N,X)),
        assertz(deleted(N)),
        assertz(deleted_hyp(N,X)),
        retractall(forgotten(N)),
        assertz(hyp(N,true)),
        !.
delete(N) :-
        integer(N),
        N > 0,                                                  /* CFR003 */
        write('H'),
        print(N),
        write(' is already deleted'),
        nl,
        !.
delete(N) :-                                                    /* CFR003 */
        write('Illegal hypothesis number to delete: '),         /* CFR003 */
        print(N),                                               /* CFR003 */
        nl,                                                     /* CFR003 */
        !.                                                      /* CFR003 */


/*** REMEMBER: tell checker to show certain hypotheses once again ***/
remember :-
        (
           command_arg(hyplist,_)
        ;
           prompt_user('REMEMBER -- which hypothesis or hypotheses?', 'Hypotheses? '),
           rread(HYPS),
           parse_command_arguments(remember,HYPS)
        ),
        do_remembering,
        !.


/*** DO_REMEMBERING -- remember each hypothesis (or range) in turn ***/
do_remembering :-
        command_arg(hyplist, HYPLIST),
        remember(HYPLIST),
        fail.
do_remembering :- !.


/*** REMEMBER(HYPLIST) -- remember each hypothesis in hyplist ***/
remember([H|T]) :- remember(H), remember(T), !.
remember([]) :- !.
remember(N) :-
        integer(N),
        N > 0,                                                  /* CFR003 */
        retract(forgotten(N)),
        !.
remember(N) :-                                                  /* CFR003 */
        integer(N),                                             /* CFR003 */
        N > 0,                                                  /* CFR003 */
        \+ forgotten(N),                                        /* CFR003 */
        write('H'),                                             /* CFR003 */
        print(N),                                               /* CFR003 */
        write(' has not been forgotten.'),                      /* CFR003 */
        nl,                                                     /* CFR003 */
        !.                                                      /* CFR003 */
remember(N) :-                                                  /* CFR003 */
        write('Illegal hypothesis number to remember: '),       /* CFR003 */
        print(N),                                               /* CFR003 */
        nl,                                                     /* CFR003 */
        !.                                                      /* CFR003 */


/*** UNDELETE: tell checker to use certain hypotheses once again ***/
undelete :-
        (
           command_arg(hyplist,_)
        ;
           prompt_user('UNDELETE -- which hypothesis or hypotheses?','Hypotheses? '),
           rread(HYPS),
           parse_command_arguments(undelete,HYPS)
        ),
        do_undeleting,
        !.


/*** DO_UNDELETING -- undelete each hypothesis (or range) in turn ***/
do_undeleting :-
        command_arg(hyplist, HYPLIST),
        undelete(HYPLIST),
        fail.
do_undeleting :- !.


/*** UNDELETE(HYPLIST) -- undelete each hypothesis in hyplist ***/
undelete([H|T]) :- undelete(H), undelete(T), !.
undelete([]) :- !.
undelete(N) :-
        integer(N),
        N > 0,                                                  /* CFR003 */
        retract(deleted(N)),
        retract(hyp(N,true)),
        retract(deleted_hyp(N,X)),
        assertz(hyp(N,X)),
        !.
undelete(N) :-
        integer(N),
        N > 0,                                                  /* CFR003 */
        write('H'),
        print(N),
        write(' has not been deleted.'),
        nl,                                                     /* CFR003 */
        !.
undelete(N) :-                                                  /* CFR003 */
        write('Illegal hypothesis number to undelete: '),       /* CFR003 */
        print(N),                                               /* CFR003 */
        nl,                                                     /* CFR003 */
        !.                                                      /* CFR003 */


temp_del_hyps(LIST) :-
        repeat,
        /* UNTIL */ del_til_none_left_in(LIST).


del_til_none_left_in(LIST) :-
        hyp(N,X),
        \+ is_in(N,LIST),
        !,
        assertz(temp_del_hyp(N,X)),
        retract(hyp(N,X)),
        !,
        fail.
del_til_none_left_in(_).


restore_temp_del_hyps :-
        retract(temp_del_hyp(N,X)),
        assertz(hyp(N,X)),
        fail.
restore_temp_del_hyps.


/*** EXIT: the way out ***/
exit :- asserta(logfact(exit, [])), !.

/*** FORCEEXIT: another way out ***/
forceexit :- asserta(logfact(forceexit, [])), !.


/*** enumeration_list(CONST, LIST) -- CONST occurs in enumeration LIST ***/
enumeration_list(CONST, LIST) :-
        atom(CONST),
        enumeration(_, LIST),
        is_in(CONST, LIST),
        !.


/*** in_order(E1, E2, LIST) -- E1 occurs before E2 in LIST ***/
in_order(E, E, LIST) :- is_in(E, LIST).
in_order(X, Y, LIST) :- append(_, [X|REST], LIST), is_in(Y, REST).


/*** strict_sublist(SUB, LIST) -- SUB is a sublist of LIST ***/
strict_sublist(SUB, LIST) :- append(SUB, _, LIST).
strict_sublist(SUB, [_|LIST]) :- strict_sublist(SUB, LIST).


/*** build_other_cases(VAR, CONST, ENUMERATION, DISJUNCTION) ***/
build_other_cases(V, C, E, D) :-
        do_build_other_cases(V, C, E, F),
        flatten_disjunction(F, D),
        !.


/*** do_build_other_cases(VAR, CONST, ENUMERATION, DISJUNCTION) ***/
do_build_other_cases(_X, E, [E], false) :- !.
do_build_other_cases(X, _E, [F], false) :- infer(X<>F), !.
do_build_other_cases(X, _E, [F], X=F) :- !.
do_build_other_cases(X, E, [C|CL], DISJ) :-
        do_build_other_cases(X, E, CL, FORM),
        (
           (
              C=E
           ;
              infer(X<>C)
           ),
           DISJ=FORM
        ;
           (
              FORM=false,
              DISJ=(X=C)
           ;
              DISJ=(X=C or FORM)
           )
        ), !.


/*** flatten_disjunction(OLD, NEW) -- make it ((..(D1 or D2) or ...) or Dn) ***/
flatten_disjunction(A or (B or C), F) :-
        flatten_disjunction((A or B) or C, F),
        !.
flatten_disjunction(A or B, AA or BB) :-
        flatten_disjunction(B, BB),
        !,
        flatten_disjunction(A, AA),
        !.
flatten_disjunction(X, X) :- !.


/*** set_union(A,B,C) -- C = (A union B) ***/
set_union(A, B, C) :-
        append(A,B,CC),
        sort(CC,C),
        !.


/*** set_intersect(A,B,C) -- C = (A intersect B) ***/
set_intersect([],_A,[]) :- !.
set_intersect(_A,[],[]) :- !.
set_intersect([A|AA],B,C) :-
        set_intersect(AA,B,CC),
        !,
        (
           set_find_in(A,B),
           C = [A|CC]
        ;
           set_not_in(A,B),
           C = CC
        ),
        !.


/*** set_find_in(A,B) -- A is definitely equal to an element of B ***/
set_find_in(A,B) :-
        is_in(A,B),
        !.
set_find_in(A,[B|_BB]) :-
        infer(A=B),
        !.
set_find_in(A,[_B|BB]) :-
        !,
        set_find_in(A,BB),
        !.


/*** set_not_in(A,B) -- A is definitely not equal to a member of B ***/
set_not_in(A,[B|BB]) :-
        !,
        infer(A<>B),
        !,
        set_not_in(A,BB),
        !.
set_not_in(_A,[]) :- !.


/*** subset(A,B) -- A is a subset of B ***/
subset([A|AA],B) :-
        set_find_in(A,B),
        !,
        subset(AA,B),
        !.
subset([],_) :- !.


/*** set_lacking(A,B,C) -- C is A \ B ***/
set_lacking([],_,[]) :- !.
set_lacking(A,[],A) :- !.
set_lacking(A,[B|BB],C) :-
        set_lacking(A,BB,CC),
        !,
        (
           set_not_in(B,CC),
           C = CC
        ;
           set_remove_all(B,CC,C)
        ),
        !.


/*** set_remove_all(A,B,C) -- C is B \ {A} ***/
set_remove_all(A,[B|BB],C) :-
        (
           infer(A=B),
           !,
           set_remove_all(A,BB,C)
        ;
           infer(A<>B),
           !,
           set_remove_all(A,BB,CC),
           C = [B|CC]
        ),
        !.
set_remove_all(_A,[],[]) :- !.


/*** make_record_equality_goal(FIELDS, R1, R2, GOAL) -- for RECORD.RUL ***/
make_record_equality_goal([[F,_T]], R, S, LHS=RHS) :-
        !,
        record_function(_, LHS, access, F, [R], Type),          /* CFR029 */
        record_function(_, RHS, access, F, [S], Type),          /* CFR029 */
        !.
make_record_equality_goal([[F,_T]|FIELDS], R, S, REST_GOAL and LHS=RHS) :-
        make_record_equality_goal(FIELDS, R, S, REST_GOAL),
        !,
        record_function(_, LHS, access, F, [R], Type),          /* CFR029 */
        record_function(_, RHS, access, F, [S], Type),          /* CFR029 */
        !.


/*** callpro - call a predicate utility ***/
callpro :-
        (
           command_arg(goal, GOAL)
        ;
           prompt_user('Goal? '),
           rread(GOAL),
           nonvar(GOAL)
        ),
        nl,
        !,
        (
           novars(GOAL),
           (
              call(GOAL),
              write('SUCCEEDED')
           ;
              write('FAILED')
           )
        ;
           (
              call(GOAL),
              write('*** '),
              print(GOAL)
           ;
              write('FAILED')
           )
        ),
        !.

prompt_user(Prompt):-
        write(Prompt),
        output_newline_if_necessary,
        flush_output,
        !.
prompt_user(Prompt1, Prompt2):-
        write(Prompt1),
        nl,
        write(Prompt2),
        output_newline_if_necessary,
        flush_output,
        !.

tab(0) :- !.
tab(N) :-
    !,
    put_char(' '),
    NewN is N - 1,
    tab(NewN).
        
%###############################################################################
%END-OF-FILE
