:- compiler_options([ciao_directives]).
:- export pretty_print/2, pretty_print/3.
:- import numbervars/3 from num_vars.
%% -----------------------------------------------------------------------
:- comment(title,"A simple pretty-printer for Ciao programs").
:- comment(module,"This library module writes out to standard output a
clause or a list of clauses.").
%% -----------------------------------------------------------------------
:- pred pretty_print(Cls,Flags) : clauses * list(flag)
# "Prints each clause in the list @var{Cls} after numbering its
variables.".
:- pred pretty_print(Cls,Flags,Ds) : clauses * list(flag) * varnamedict
# "Prints each clause in the list @var{Cls} after using the
corresponding variable names dictionary in @var{Ds} to
name its variables.".
:- comment(doinclude,clauses/1).
%% :- typedef clauses ::= [] ; [clause|clauses] ; clause .
:- regtype clauses/1.
clauses := [].
clauses := [~clause|~clauses].
clauses := ~clause.
:- comment(doinclude,clause/1).
%% :- typedef clause ::= clterm ; ^((clterm,any)) .
:- regtype clause/1.
clause := ~clterm.
clause := ^((~clterm,~term)).
:- comment(doinclude,clterm/1).
%% :- typedef clterm ::= ^clause(goal,body) ; ^directive(body)
%% ; ^((goal:-body)) ; goal .
:- regtype clterm/1.
clterm := clause(~callable,~body).
clterm := directive(~body).
clterm := (~callable :- ~body).
clterm := ~callable.
:- comment(doinclude,body/1).
:- comment(body/1,"A well formed body, including cge expressions and
&-concurrent expressions. The atomic goals may or may not have
a key in the form @tt{^(goal:any)}, and may or may not be
module qualified, but if they are it has to be in the form
@tt{^(^(moddesc:goal):any)}.").
:- regtype body(X)
# "@var{X} is a printable body.".
body(X):- body(X).
:- comment(doinclude,flag/1).
:- comment(flag/1,
"A keyword @tt{ask/1} flags whether to output @em{asks} or
@em{whens} and @tt{nl/1} whether to separate clauses with
a blank line or not.").
:- regtype flag(X)
# "@var{X} is a flag for the pretty-printer.".
flag(ask(A)):- ok_ans(A).
flag(nl(B)):- ok_ans(B).
:- regtype ok_ans(X)
# "@var{X} is an answer for yes/no questions.".
ok_ans(yes).
ok_ans(no).
% check hooks:
curr_hooks(L,A,B):- hooks(L,no,A,no,B).
hooks([],A,A,B,B).
hooks([X|Xs],A0,A,B0,B):-
hook(X,A0,B0,A1,B1),
hooks(Xs,A1,A,B1,B).
hook(ask(A),_A,B,A,B):- ok_ans(A).
hook(nl(B),A,_B,A,B):- ok_ans(B).
%% -----------------------------------------------------------------------
pretty_print(Cls,Hooks,Ds):-
curr_hooks(Hooks,Key,Nl),
pretty_printK(Cls,Ds,Key,Nl).
pretty_print(Cls,Hooks):-
curr_hooks(Hooks,Key,Nl),
pretty_printK(Cls,_nodict,Key,Nl).
pretty_printK([],_Ds,_Key,_Nl):- !.
pretty_printK([(Cl,_)|T],[D|Ds],Key,Nl) :- !,
pretty_print0(Cl,D,Key,Nl),
pretty_printK(T,Ds,Key,Nl).
pretty_printK([Cl|T],[D|Ds],Key,Nl) :- !,
pretty_print0(Cl,D,Key,Nl),
pretty_printK(T,Ds,Key,Nl).
pretty_printK((Cl,_),D,Key,Nl) :- !,
pretty_print0(Cl,D,Key,Nl).
pretty_printK(Cl,D,Key,Nl) :-
pretty_print0(Cl,D,Key,Nl).
pretty_print0(Cl,D,K,N):- var(D), !,
numbervars(Cl,0,_),
pp(Cl,K),
write('.'), nl,
separator(N).
pretty_print0(Cl,D,K,N):-
rename(Cl,D),
pp(Cl,K),
write('.'), nl,
separator(N).
separator(yes):- nl.
separator(no).
pp(directive(D),_K):- !,
write(':- '),
writeq(D).
pp((H :- B),K):- !,
pp(clause(H,B),K).
pp(clause(H,true),_K):- !,
writeq(H).
pp(clause(H,!),_K):- !,
writeq(H),
write(' :- !').
pp(clause(H,B),K):- !,
writeq(H),
write(' :-'), nl,
ppb(B,8,K).
pp(H,K):-
pp(clause(H,true),K).
ppb((A,B),Tab,K) :- !,
ppb(A,Tab,K),
write(','),nl,
ppb(B,Tab,K).
ppb('&'(A,B),Tab,K) :- !,
ppc(A,Tab,K),
write(' &'),nl,
ppc(B,Tab,K).
/* TLS: operator not added: were not doing &-parallel
ppb((A'&'),Tab,K) :- !,
ppb(A,Tab,K),
write(' &').*/
ppb((A->B;C),Tab,K) :- !,
tab(Tab), write('('), nl,
NTab1 is Tab+2,
NTab2 is Tab+5,
ppb(A,NTab1,K),
write(' ->'), nl,
ppb(B,NTab2,K),nl,
tab(Tab), write(';'), nl,
ppb(C,NTab2,K),nl,
tab(Tab), write(')').
ppb((A->B),Tab,K) :- !,
tab(Tab), write('('), nl,
NTab1 is Tab+2,
NTab2 is Tab+5,
ppb(A,NTab1,K),
write(' ->'), nl,
ppb(B,NTab2,K),nl,
tab(Tab), write(')').
ppb((A;B),Tab,K) :- !,
tab(Tab), write('('), nl,
NTab is Tab+5,
ppb(A,NTab,K),nl,
tab(Tab), write(';'), nl,
ppb(B,NTab,K),nl,
tab(Tab), write(')').
ppb('=>'(A,B),Tab,K) :- !,
tab(Tab), write('('), nl,
NTab is Tab+5,
ppb(A,NTab,K),nl,
tab(Tab), write('=>'), nl,
ppb(B,NTab,K),nl,
tab(Tab), write(')').
ppb(A:_,Tab,K) :- !,
ppg(A,Tab,K).
ppb(A,Tab,K) :-
ppg(A,Tab,K).
ppc('&'(A,B),Tab,K) :- !,
ppc(A,Tab,K),
write(' &'), nl,
ppc(B,Tab,K).
ppc(X,Tab,K) :-
functor(X,F,2),
( F=',' ; F='=>' ; F=';' ; F='->' ), !,
tab(Tab), write('('), nl,
NTab is Tab+1,
ppb(X,NTab,K),nl,
tab(Tab), write(')').
ppc(A,Tab,K) :-
ppb(A,Tab,K).
% when/2 to a guarded ask
ppg(when(A,B),Tab,yes) :- !,
ppb((ask(A)->B),Tab,ask),
write(' & ').
% complex-ask with an &
ppg(ask(A,B),Tab,yes) :- !,
tab(Tab),
writeq(ask(A,B)),
write(' & ').
% simple or qualified atomic goal
ppg(A,Tab,_K) :-
tab(Tab),
writeq(A).
%% -----------------------------------------------------------------------
:- comment(version_maintenance,dir('../version')).
:- comment(version(0*9+100,1999/05/26,12:36*46+'MEST'), "Minor fixes
to doc. (Manuel Hermenegildo)").
:- comment(version(0*8+20,1998/12/03,13:00*00+'MET'), "Updated types
and comment separators. (Manuel Hermenegildo)").
:- comment(version(0*5+38,1998/07/06,16:06*06+'MET DST'), "Added
argument for hooks to the two main entry points. (Francisco Bueno
Carrillo)").
:- comment(version(0*4+5,1998/2/24), "Synchronized file versions with
global CIAO version. (Manuel Hermenegildo)").
%% -----------------------------------------------------------------------
syntax highlighted by Code2HTML, v. 0.9.1