Douglas R. Miles/LogicMoo schrieb:
> Where is a free prolog code beautifier that doesn't destroy comments?
>
> +1 if written in Prolog (with source avail)
>
I got a beautifier for Jekejeke Prolog, but its written partly
in Java and partly in Prolog. And sadly currently Java does
the main part of the work.
Its just a simple extension of the normal pretty printer for
Prolog terms that is for example also found in SWI-Prolog
not only Jekejeke Prolog.
For example you can easily make the following test, namely
enter a clause and do some listing. You will see that the
clause is already a little reformatted (here SWI-Prolog):
Input:
?- [user].
app([], X, X).
app([X|Y], Z, [X|T]) :- app(Y, Z, T).
Output (look see what happens with the (:-)/2):
?- listing(app/3).
app([], A, A).
app([A|B], C, [A|D]) :-
app(B, C, D).
To get a beautifier you need annotations or extra data structures
that delivers you more information from reading a term, and
also the pretty printer needs then take this information into
account.
Typically the following information is sufficient to give
a relatively good beautifier:
1) The variable names of the original clause need to be
carried over
2) Some syntax operators need special treatment, like the
','/2 is written without a space in front.
3) Some predicates need special treatment, a workable approach
is to look at the meta-predicate definitions
4) Some lists or numbers might need to be carried
over unformatted
5) Some compounds might need to be carried over with block comment
information interspersed
6) Some compounds might need to be carried over with line comment
information interspersed
7) Even the original clause might need to carry over block comment
or line comment at the front or at the back of the clause
8) HTML Links to the home of a predicate
9) HTML Anchors for the home of a predicate
In Jekejeke Prolog I use the following approach for the many
requirements from above:
a) For 1) I use the ISO variable_names option of the read_term
and write_term predicate.
b) For 2) syntax operators can have properties, this is a non-ISO
extension
c) For 3) there are additional meta argument specifiers not found
everywhere, such as the new (::)/1 for object orientation.
d) For 4) lists like "abc" or numbers like 0xabc are mapped to
atoms, and the atom has a hint property
e) For 5) and 6) the functor of a compound has a filler
property
f) For 7) the clause is wrapped into an additional functor '.'/1,
so app([], X, X) is read as '.'(app([],X,X)) and app([X|Y], Z,
[X|T]) :- app(Y, Z, T) is read as '.'(app([X|Y], Z, [X|T]) :-
app(Y, Z, T)). The filler property of the '.'/1 functor is then
used carry over line and block comments.
g) For 8) and 9) each predicate has a usage property, the
property is automatically set during consult or assert
The main loop for the beautifier is as follows.
Step 1) Consult all the files you want to beautify, this is needed
for requirement 8) and 9) otherwise you don't know what links
and anchors should be placed. Please note in Prolog you can easily
make forward references of predicates.
Step 2) Read the clauses of the files with the extra data, and
write the clauses with the extra data. This loop looks as follows
in Jekejeke Prolog:
copy_text(InName, OutName) :-
absolute_file_name(InName, SrcPin),
setup_call_cleanup(open(InName, read, InStream),
setup_call_cleanup(open(OutName, write, OutStream),
(repeat,
read_term(InStream, Term, [annotation(true),
variable_names(Names),
source(SrcPin), line_no(U)]),
term_variables(Term, Vars),
sys_term_singletons(Term, Anons),
sys_number_variables(Vars, Names, Anons, NamesAndAnons),
write_term(OutStream, Term, [annotation(true), context(-1),
quoted(true), format(true), variable_names(NamesAndAnons),
source(SrcPin), line_no(U)]),
(Term = end_of_file -> !; fail)),
close(OutStream)),
close(InStream)).
The following read/write options come into play:
- annotation/1: So that the extra information is read or written,
and the '.'/1 wrapping is done respectively undone.
- format/1: Different levels of formatting, true=use all
extra information
- context/1: Start with a clause
- source/1, line_no/1: So that the HTML anchor is generated.
You need the development environment to play with it, the
runtime library doesn't understand annotation/1, format/1.
Bye