/*  SHOW.PL  */
 
 
:- module show.
 
 
:- public show_fact/2,
          show_fact/3,
          fact_to_chars/2,
          show_question/2,
          show_question/3,
          question_to_chars/2,
          assign_variable_names/1.
 
 
/*
SPECIFICATION
-------------
 
These are the main fact-output predicates called by the Tutor. This
module is used when showing facts, when converting to text for editing,
and when saving them to file. There are similar predicates for
questions.
 
 
PUBLIC show_fact( Fact+, Mode+, Options+ ).
The central predicate is show_fact/3, which takes a fact, a mode, and a
list of options, and writes the fact accordingly, calling one of the SDO
rules in SHOW_SDO to do this.
 
The options are:
    number(N):      Precede the fact by fact number N
                    (default: no number).
    wrap_bad:       Wrap bad facts in <<< >>> brackets.
                    (default: no brackets).
    dot_and_nl:     Emit a dot and newline after the fact.
                    (default: no dot or newline).
 
The reason for the different forms is that several people need to do
output: the editor, the file-saver, and the editor, and the formats are
not the same.
 
 
PUBLIC show_fact( Fact+, OptionsOrMode+ ):
Write out Fact in 'show' format. If OptionsOrMode is a list, treat it as a
list of options, else as a mode.
 
 
PUBLIC fact_to_chars( Fact+, Chars- ):
Write Fact in editable form as a list of character codes, unifying the
result with Chars.
 
 
PUBLIC show_question( Question+, Mode+, Options+ ):
As for show_fact/3, but write out a question. The Options are the same,
except that number(_) is meaningless, and we use 'question_mark_and_nl',
not 'dot_and_nl'.
 
 
PUBLIC show_question( Question+, ModeOrOptions+ ):
As for show_question/3, but: if ModeOrOptions is a list, use it as a
list of options. Otherwise, treat it as the current mode.
 
 
PUBLIC question_to_chars( Question+, Chars- ):
Write Question in editable form as a list of character codes, unifying the
result with Chars.
 
 
PUBLIC assign_variable_names( Vars ):
Vars is a list each element of which is a structure
    var(Var,Name)
where Name is the variable's name as an atom. assign_variable_names
binds each Var to its Name so that if output, the variable will appear
as its name.
 
Actually, on my system (Poplog), I bind each variable to
    '$NOQUOTE'(Name)
and I have hacked Poplog so that 'writeq', if it encounters any such
structures, will not put quotes around the name. You will need to
do something similar, unfortunately. This is because variable names are
represented by atoms, but so are atoms themselves. I use 'writeq' to
output facts, as can be seen from the grammar in SHOW_SDO.SDO. If you
only use standard facilities, there is no way to make
    writeq( f('Fred') )
print
    f('Fred')
but
    writeq( f(Fred) )
print
    f(Fred)
 
However, to make the 'show' command work properly, and to preserve the
distinction between quoted atoms and variables that's introduced in
Lesson 4, it's essential that quotes appear around quoted atoms in
facts, but not around variable names. How are the standardisers going
to provide facilities to solve this problem?
 
Note that AND_OR.PL also relies on this trick.
*/
 
 
/*
IMPLEMENTATION
--------------
 
Question and fact structures both contain lists of variable-name pairs.
To write out the structure, each variable is bound to its name before
writing. It is important that the binding be undone on exit, so we call
the subsidiary _1 predicates, via non_binding_call, to undo any bindings
they make.
*/
 
 
:- needs
    assertion / 1,
    cos_to_chars / 2,
    fact_vs_clause_and_vars / 3,
    fact_vs_text / 2,
    is_good_fact / 1,
    is_good_question / 1,
    is_mode / 1,
    member / 2,
    output / 1,
    pretty / 3,
    question_vs_goal_and_vars / 3,
    question_vs_text / 2.
 
 
/*  Facts.  */
 
 
show_fact( Fact, Options ) :-
    ( Options = [] ; Options = [_|_] ),
    !,
    is_mode( Mode ),
    show_fact( Fact, Mode, Options ).
 
show_fact( Fact, Mode ) :-
    show_fact( Fact, Mode, [] ).
 
 
fact_to_chars( Fact, Chars ) :-
    is_mode( Mode ),
    cos_to_chars( show_fact( Fact, Mode, [] ), Chars ).
 
 
/*  show_fact( Fact+, Mode+, Options+ ):
        Write out Fact in mode Mode according to Options
*/
show_fact( Fact, Mode, Options ) :-
    assertion( non_binding_call(show_fact_1( Fact, Mode, Options )) ).
 
 
show_fact_1( Fact, Mode, Options ) :-
    is_good_fact( Fact ),
    !,
    fact_vs_clause_and_vars( Fact, Clause, Vars ),
    assign_variable_names( Vars ),
    (
        member( number(N), Options )
    ->
        (
            Mode = prolog
        ->
            pretty( prolog_numbered_rule_out(N,Clause), 78, prolog )
        ;
            pretty( logic_numbered_rule_out(N,Clause), 78, prolog )
        )
    ;
        (
            Mode = prolog
        ->
            pretty( prolog_unnumbered_rule_out(Clause), 78, prolog )
        ;
            pretty( logic_unnumbered_rule_out(Clause), 78, prolog )
        )
    ),
    ( member( dot_and_nl, Options ) -> write('.'), nl ; true ).
 
show_fact_1( Fact, Mode, Options ) :-
    !,
    fact_vs_text( Fact, Tokens ),
    ( member(number(N),Options) -> pretty(number_padded_4_out(N),78,_) ; true ),
    ( member(wrap_bad,Options) -> output( '<<<  ' ) ; true ),
    pretty( bad_fact_out(Tokens), 78, prolog ),
    ( member(wrap_bad,Options) -> output( '  >>>' ) ; true ),
    ( member( dot_and_nl, Options ) -> write('.'), nl ; true ).
 
 
/*  Questions.  */
 
 
show_question( Question, Options ) :-
    ( Options = [] ; Options = [_|_] ),
    !,
    is_mode( Mode ),
    show_question( Question, Mode, Options ).
 
show_question( Question, Mode ) :-
    show_question( Question, Mode, [] ).
 
 
question_to_chars( Question, Chars ) :-
    is_mode( Mode ),
    cos_to_chars( show_question( Question, Mode, [] ), Chars ).
 
 
/*  show_question( Question+, Mode+, Options+ ):
        Write out Question in mode Mode according to Options
*/
show_question( Question, Mode, Options ) :-
    assertion( non_binding_call(show_question_1( Question, Mode, Options )) ).
 
 
show_question_1( Question, Mode, Options ) :-
    is_good_question( Question ),
    !,
    question_vs_goal_and_vars( Question, Goal, Vars ),
    assign_variable_names( Vars ),
    (
        Mode = prolog
    ->
        pretty( prolog_question_out(Goal), 78, prolog )
    ;
        pretty( logic_question_out(Goal), 78, prolog )
    ),
    ( member( question_mark_and_nl, Options ) -> write('?'), nl ; true ).
 
show_question_1( Question, Mode, Options ) :-
    !,
    question_vs_text( Question, Tokens ),
    ( member(wrap_bad,Options) -> output( '<<<  ' ) ; true ),
    pretty( bad_question_out(Tokens), 78, prolog ),               
    ( member(wrap_bad,Options) -> output( '  >>>' ) ; true ),
    ( member( question_mark_and_nl, Options ) -> write('?'), nl ; true ).
 
 
/*  Utilities.  */
 
 
assign_variable_names( [] ) :- !.
 
assign_variable_names( [var(Var,Name)|Rest] ) :-
    ( Var = '$NOQUOTE'(Name) -> true ; true ),
    assign_variable_names( Rest ).
 
 
:- endmodule.
