36
37:- module(prolog_listing,
38 [ listing/0,
39 listing/1, 40 listing/2, 41 portray_clause/1, 42 portray_clause/2, 43 portray_clause/3 44 ]). 45:- use_module(library(settings),[setting/4,setting/2]). 46
47:- autoload(library(ansi_term),[ansi_format/3]). 48:- autoload(library(apply),[foldl/4]). 49:- autoload(library(debug),[debug/3]). 50:- autoload(library(error),[instantiation_error/1,must_be/2]). 51:- autoload(library(lists),[member/2]). 52:- autoload(library(option),[option/2,option/3,meta_options/3]). 53:- autoload(library(prolog_clause),[clause_info/5]). 54:- autoload(library(prolog_code), [most_general_goal/2]). 55
57
58:- module_transparent
59 listing/0. 60:- meta_predicate
61 listing(:),
62 listing(:, +),
63 portray_clause(+,+,:). 64
65:- predicate_options(portray_clause/3, 3,
66 [ indent(nonneg),
67 pass_to(system:write_term/3, 3)
68 ]). 69
70:- multifile
71 prolog:locate_clauses/2. 72
101
102:- setting(listing:body_indentation, nonneg, 4,
103 'Indentation used goals in the body'). 104:- setting(listing:tab_distance, nonneg, 0,
105 'Distance between tab-stops. 0 uses only spaces'). 106:- setting(listing:cut_on_same_line, boolean, false,
107 'Place cuts (!) on the same line'). 108:- setting(listing:line_width, nonneg, 78,
109 'Width of a line. 0 is infinite'). 110:- setting(listing:comment_ansi_attributes, list, [fg(green)],
111 'ansi_format/3 attributes to print comments'). 112
113
124
125listing :-
126 context_module(Context),
127 list_module(Context, []).
128
129list_module(Module, Options) :-
130 ( current_predicate(_, Module:Pred),
131 \+ predicate_property(Module:Pred, imported_from(_)),
132 strip_module(Pred, _Module, Head),
133 functor(Head, Name, _Arity),
134 ( ( predicate_property(Module:Pred, built_in)
135 ; sub_atom(Name, 0, _, _, $)
136 )
137 -> current_prolog_flag(access_level, system)
138 ; true
139 ),
140 nl,
141 list_predicate(Module:Head, Module, Options),
142 fail
143 ; true
144 ).
145
146
189
190listing(Spec) :-
191 listing(Spec, []).
192
193listing(Spec, Options) :-
194 call_cleanup(
195 listing_(Spec, Options),
196 close_sources).
197
198listing_(M:Spec, Options) :-
199 var(Spec),
200 !,
201 list_module(M, Options).
202listing_(M:List, Options) :-
203 is_list(List),
204 !,
205 forall(member(Spec, List),
206 listing_(M:Spec, Options)).
207listing_(X, Options) :-
208 ( prolog:locate_clauses(X, ClauseRefs)
209 -> strip_module(X, Context, _),
210 list_clauserefs(ClauseRefs, Context, Options)
211 ; '$find_predicate'(X, Preds),
212 list_predicates(Preds, X, Options)
213 ).
214
215list_clauserefs([], _, _) :- !.
216list_clauserefs([H|T], Context, Options) :-
217 !,
218 list_clauserefs(H, Context, Options),
219 list_clauserefs(T, Context, Options).
220list_clauserefs(Ref, Context, Options) :-
221 @(rule(_, Rule, Ref), Context),
222 list_clause(Rule, Ref, Context, Options).
223
225
226list_predicates(PIs, Context:X, Options) :-
227 member(PI, PIs),
228 pi_to_head(PI, Pred),
229 unify_args(Pred, X),
230 list_define(Pred, DefPred),
231 list_predicate(DefPred, Context, Options),
232 nl,
233 fail.
234list_predicates(_, _, _).
235
236list_define(Head, LoadModule:Head) :-
237 compound(Head),
238 Head \= (_:_),
239 functor(Head, Name, Arity),
240 '$find_library'(_, Name, Arity, LoadModule, Library),
241 !,
242 use_module(Library, []).
243list_define(M:Pred, DefM:Pred) :-
244 '$define_predicate'(M:Pred),
245 ( predicate_property(M:Pred, imported_from(DefM))
246 -> true
247 ; DefM = M
248 ).
249
250pi_to_head(PI, _) :-
251 var(PI),
252 !,
253 instantiation_error(PI).
254pi_to_head(M:PI, M:Head) :-
255 !,
256 pi_to_head(PI, Head).
257pi_to_head(Name/Arity, Head) :-
258 functor(Head, Name, Arity).
259
260
263
264unify_args(_, _/_) :- !. 265unify_args(X, X) :- !.
266unify_args(_:X, X) :- !.
267unify_args(_, _).
268
269list_predicate(Pred, Context, _) :-
270 predicate_property(Pred, undefined),
271 !,
272 decl_term(Pred, Context, Decl),
273 comment('% Undefined: ~q~n', [Decl]).
274list_predicate(Pred, Context, _) :-
275 predicate_property(Pred, foreign),
276 !,
277 decl_term(Pred, Context, Decl),
278 comment('% Foreign: ~q~n', [Decl]).
279list_predicate(Pred, Context, Options) :-
280 notify_changed(Pred, Context),
281 list_declarations(Pred, Context),
282 list_clauses(Pred, Context, Options).
283
284decl_term(Pred, Context, Decl) :-
285 strip_module(Pred, Module, Head),
286 functor(Head, Name, Arity),
287 ( hide_module(Module, Context, Head)
288 -> Decl = Name/Arity
289 ; Decl = Module:Name/Arity
290 ).
291
292
293decl(thread_local, thread_local).
294decl(dynamic, dynamic).
295decl(volatile, volatile).
296decl(multifile, multifile).
297decl(public, public).
298
306
307declaration(Pred, Source, Decl) :-
308 predicate_property(Pred, tabled),
309 Pred = M:Head,
310 ( M:'$table_mode'(Head, Head, _)
311 -> decl_term(Pred, Source, Funct),
312 table_options(Pred, Funct, TableDecl),
313 Decl = table(TableDecl)
314 ; comment('% tabled using answer subsumption~n', []),
315 fail 316 ).
317declaration(Pred, Source, Decl) :-
318 decl(Prop, Declname),
319 predicate_property(Pred, Prop),
320 decl_term(Pred, Source, Funct),
321 Decl =.. [ Declname, Funct ].
322declaration(Pred, Source, Decl) :-
323 predicate_property(Pred, meta_predicate(Head)),
324 strip_module(Pred, Module, _),
325 ( (Module == system; Source == Module)
326 -> Decl = meta_predicate(Head)
327 ; Decl = meta_predicate(Module:Head)
328 ),
329 ( meta_implies_transparent(Head)
330 -> ! 331 ; true
332 ).
333declaration(Pred, Source, Decl) :-
334 predicate_property(Pred, transparent),
335 decl_term(Pred, Source, PI),
336 Decl = module_transparent(PI).
337
342
343meta_implies_transparent(Head):-
344 compound(Head),
345 arg(_, Head, Arg),
346 implies_transparent(Arg),
347 !.
348
349implies_transparent(Arg) :-
350 integer(Arg),
351 !.
352implies_transparent(:).
353implies_transparent(//).
354implies_transparent(^).
355
356table_options(Pred, Decl0, as(Decl0, Options)) :-
357 findall(Flag, predicate_property(Pred, tabled(Flag)), [F0|Flags]),
358 !,
359 foldl(table_option, Flags, F0, Options).
360table_options(_, Decl, Decl).
361
362table_option(Flag, X, (Flag,X)).
363
364list_declarations(Pred, Source) :-
365 findall(Decl, declaration(Pred, Source, Decl), Decls),
366 ( Decls == []
367 -> true
368 ; write_declarations(Decls, Source),
369 format('~n', [])
370 ).
371
372
373write_declarations([], _) :- !.
374write_declarations([H|T], Module) :-
375 format(':- ~q.~n', [H]),
376 write_declarations(T, Module).
377
378list_clauses(Pred, Source, Options) :-
379 strip_module(Pred, Module, Head),
380 most_general_goal(Head, GenHead),
381 forall(( rule(Module:GenHead, Rule, Ref),
382 \+ \+ rule_head(Rule, Head)
383 ),
384 list_clause(Module:Rule, Ref, Source, Options)).
385
386rule_head((Head0 :- _Body), Head) :- !, Head = Head0.
387rule_head((Head0,_Cond => _Body), Head) :- !, Head = Head0.
388rule_head((Head0 => _Body), Head) :- !, Head = Head0.
389rule_head(?=>(Head0, _Body), Head) :- !, Head = Head0.
390rule_head(Head, Head).
391
392list_clause(_Rule, Ref, _Source, Options) :-
393 option(source(true), Options),
394 ( clause_property(Ref, file(File)),
395 clause_property(Ref, line_count(Line)),
396 catch(source_clause_string(File, Line, String, Repositioned),
397 _, fail),
398 debug(listing(source), 'Read ~w:~d: "~s"~n', [File, Line, String])
399 -> !,
400 ( Repositioned == true
401 -> comment('% From ~w:~d~n', [ File, Line ])
402 ; true
403 ),
404 writeln(String)
405 ; decompiled
406 -> fail
407 ; asserta(decompiled),
408 comment('% From database (decompiled)~n', []),
409 fail 410 ).
411list_clause(Module:(Head:-Body), Ref, Source, Options) :-
412 !,
413 list_clause(Module:Head, Body, :-, Ref, Source, Options).
414list_clause(Module:(Head=>Body), Ref, Source, Options) :-
415 list_clause(Module:Head, Body, =>, Ref, Source, Options).
416list_clause(Module:Head, Ref, Source, Options) :-
417 !,
418 list_clause(Module:Head, true, :-, Ref, Source, Options).
419
420list_clause(Module:Head, Body, Neck, Ref, Source, Options) :-
421 restore_variable_names(Module, Head, Body, Ref, Options),
422 write_module(Module, Source, Head),
423 Rule =.. [Neck,Head,Body],
424 portray_clause(Rule).
425
430
431restore_variable_names(Module, Head, Body, Ref, Options) :-
432 option(variable_names(source), Options, source),
433 catch(clause_info(Ref, _, _, _,
434 [ head(QHead),
435 body(Body),
436 variable_names(Bindings)
437 ]),
438 _, true),
439 unify_head(Module, Head, QHead),
440 !,
441 bind_vars(Bindings),
442 name_other_vars((Head:-Body), Bindings).
443restore_variable_names(_,_,_,_,_).
444
445unify_head(Module, Head, Module:Head) :-
446 !.
447unify_head(_, Head, Head) :-
448 !.
449unify_head(_, _, _).
450
451bind_vars([]) :-
452 !.
453bind_vars([Name = Var|T]) :-
454 ignore(Var = '$VAR'(Name)),
455 bind_vars(T).
456
461
462name_other_vars(Term, Bindings) :-
463 term_singletons(Term, Singletons),
464 bind_singletons(Singletons),
465 term_variables(Term, Vars),
466 name_vars(Vars, 0, Bindings).
467
468bind_singletons([]).
469bind_singletons(['$VAR'('_')|T]) :-
470 bind_singletons(T).
471
472name_vars([], _, _).
473name_vars([H|T], N, Bindings) :-
474 between(N, infinite, N2),
475 var_name(N2, Name),
476 \+ memberchk(Name=_, Bindings),
477 !,
478 H = '$VAR'(N2),
479 N3 is N2 + 1,
480 name_vars(T, N3, Bindings).
481
482var_name(I, Name) :- 483 L is (I mod 26)+0'A,
484 N is I // 26,
485 ( N == 0
486 -> char_code(Name, L)
487 ; format(atom(Name), '~c~d', [L, N])
488 ).
489
490write_module(Module, Context, Head) :-
491 hide_module(Module, Context, Head),
492 !.
493write_module(Module, _, _) :-
494 format('~q:', [Module]).
495
496hide_module(system, Module, Head) :-
497 predicate_property(Module:Head, imported_from(M)),
498 predicate_property(system:Head, imported_from(M)),
499 !.
500hide_module(Module, Module, _) :- !.
501
502notify_changed(Pred, Context) :-
503 strip_module(Pred, user, Head),
504 predicate_property(Head, built_in),
505 \+ predicate_property(Head, (dynamic)),
506 !,
507 decl_term(Pred, Context, Decl),
508 comment('% NOTE: system definition has been overruled for ~q~n',
509 [Decl]).
510notify_changed(_, _).
511
516
517source_clause_string(File, Line, String, Repositioned) :-
518 open_source(File, Line, Stream, Repositioned),
519 stream_property(Stream, position(Start)),
520 '$raw_read'(Stream, _TextWithoutComments),
521 stream_property(Stream, position(End)),
522 stream_position_data(char_count, Start, StartChar),
523 stream_position_data(char_count, End, EndChar),
524 Length is EndChar - StartChar,
525 set_stream_position(Stream, Start),
526 read_string(Stream, Length, String),
527 skip_blanks_and_comments(Stream, blank).
528
529skip_blanks_and_comments(Stream, _) :-
530 at_end_of_stream(Stream),
531 !.
532skip_blanks_and_comments(Stream, State0) :-
533 peek_string(Stream, 80, String),
534 string_chars(String, Chars),
535 phrase(blanks_and_comments(State0, State), Chars, Rest),
536 ( Rest == []
537 -> read_string(Stream, 80, _),
538 skip_blanks_and_comments(Stream, State)
539 ; length(Chars, All),
540 length(Rest, RLen),
541 Skip is All-RLen,
542 read_string(Stream, Skip, _)
543 ).
544
545blanks_and_comments(State0, State) -->
546 [C],
547 { transition(C, State0, State1) },
548 !,
549 blanks_and_comments(State1, State).
550blanks_and_comments(State, State) -->
551 [].
552
553transition(C, blank, blank) :-
554 char_type(C, space).
555transition('%', blank, line_comment).
556transition('\n', line_comment, blank).
557transition(_, line_comment, line_comment).
558transition('/', blank, comment_0).
559transition('/', comment(N), comment(N,/)).
560transition('*', comment(N,/), comment(N1)) :-
561 N1 is N + 1.
562transition('*', comment_0, comment(1)).
563transition('*', comment(N), comment(N,*)).
564transition('/', comment(N,*), State) :-
565 ( N == 1
566 -> State = blank
567 ; N2 is N - 1,
568 State = comment(N2)
569 ).
570
571
572open_source(File, Line, Stream, Repositioned) :-
573 source_stream(File, Stream, Pos0, Repositioned),
574 line_count(Stream, Line0),
575 ( Line >= Line0
576 -> Skip is Line - Line0
577 ; set_stream_position(Stream, Pos0),
578 Skip is Line - 1
579 ),
580 debug(listing(source), '~w: skip ~d to ~d', [File, Line0, Line]),
581 ( Skip =\= 0
582 -> Repositioned = true
583 ; true
584 ),
585 forall(between(1, Skip, _),
586 skip(Stream, 0'\n)).
587
588:- thread_local
589 opened_source/3,
590 decompiled/0. 591
592source_stream(File, Stream, Pos0, _) :-
593 opened_source(File, Stream, Pos0),
594 !.
595source_stream(File, Stream, Pos0, true) :-
596 open(File, read, Stream),
597 stream_property(Stream, position(Pos0)),
598 asserta(opened_source(File, Stream, Pos0)).
599
600close_sources :-
601 retractall(decompiled),
602 forall(retract(opened_source(_,Stream,_)),
603 close(Stream)).
604
605
633
639
642portray_clause(Term) :-
643 current_output(Out),
644 portray_clause(Out, Term).
645
646portray_clause(Stream, Term) :-
647 must_be(stream, Stream),
648 portray_clause(Stream, Term, []).
649
650portray_clause(Stream, Term, M:Options) :-
651 must_be(list, Options),
652 meta_options(is_meta, M:Options, QOptions),
653 \+ \+ name_vars_and_portray_clause(Stream, Term, QOptions).
654
655name_vars_and_portray_clause(Stream, Term, Options) :-
656 term_attvars(Term, []),
657 !,
658 clause_vars(Term, Options),
659 do_portray_clause(Stream, Term, Options).
660name_vars_and_portray_clause(Stream, Term, Options) :-
661 option(variable_names(Bindings), Options),
662 !,
663 copy_term_nat(Term+Bindings, Copy+BCopy),
664 bind_vars(BCopy),
665 name_other_vars(Copy, BCopy),
666 do_portray_clause(Stream, Copy, Options).
667name_vars_and_portray_clause(Stream, Term, Options) :-
668 copy_term_nat(Term, Copy),
669 clause_vars(Copy, Options),
670 do_portray_clause(Stream, Copy, Options).
671
672clause_vars(Clause, Options) :-
673 option(variable_names(Bindings), Options),
674 !,
675 bind_vars(Bindings),
676 name_other_vars(Clause, Bindings).
677clause_vars(Clause, _) :-
678 numbervars(Clause, 0, _,
679 [ singletons(true)
680 ]).
681
682is_meta(portray_goal).
683
684do_portray_clause(Out, Var, Options) :-
685 var(Var),
686 !,
687 option(indent(LeftMargin), Options, 0),
688 indent(Out, LeftMargin),
689 pprint(Out, Var, 1200, Options).
690do_portray_clause(Out, (Head :- true), Options) :-
691 !,
692 option(indent(LeftMargin), Options, 0),
693 indent(Out, LeftMargin),
694 pprint(Out, Head, 1200, Options),
695 full_stop(Out).
696do_portray_clause(Out, Term, Options) :-
697 clause_term(Term, Head, Neck, Body),
698 !,
699 option(indent(LeftMargin), Options, 0),
700 inc_indent(LeftMargin, 1, Indent),
701 infix_op(Neck, RightPri, LeftPri),
702 indent(Out, LeftMargin),
703 pprint(Out, Head, LeftPri, Options),
704 format(Out, ' ~w', [Neck]),
705 ( nonvar(Body),
706 Body = Module:LocalBody,
707 \+ primitive(LocalBody)
708 -> nlindent(Out, Indent),
709 format(Out, '~q', [Module]),
710 '$put_token'(Out, :),
711 nlindent(Out, Indent),
712 write(Out, '( '),
713 inc_indent(Indent, 1, BodyIndent),
714 portray_body(LocalBody, BodyIndent, noindent, 1200, Out, Options),
715 nlindent(Out, Indent),
716 write(Out, ')')
717 ; setting(listing:body_indentation, BodyIndent0),
718 BodyIndent is LeftMargin+BodyIndent0,
719 portray_body(Body, BodyIndent, indent, RightPri, Out, Options)
720 ),
721 full_stop(Out).
722do_portray_clause(Out, (:-Directive), Options) :-
723 wrapped_list_directive(Directive),
724 !,
725 Directive =.. [Name, Arg, List],
726 option(indent(LeftMargin), Options, 0),
727 indent(Out, LeftMargin),
728 format(Out, ':- ~q(', [Name]),
729 line_position(Out, Indent),
730 format(Out, '~q,', [Arg]),
731 nlindent(Out, Indent),
732 portray_list(List, Indent, Out, Options),
733 write(Out, ').\n').
734do_portray_clause(Out, (:-Directive), Options) :-
735 !,
736 option(indent(LeftMargin), Options, 0),
737 indent(Out, LeftMargin),
738 write(Out, ':- '),
739 DIndent is LeftMargin+3,
740 portray_body(Directive, DIndent, noindent, 1199, Out, Options),
741 full_stop(Out).
742do_portray_clause(Out, Fact, Options) :-
743 option(indent(LeftMargin), Options, 0),
744 indent(Out, LeftMargin),
745 portray_body(Fact, LeftMargin, noindent, 1200, Out, Options),
746 full_stop(Out).
747
748clause_term((Head:-Body), Head, :-, Body).
749clause_term((Head=>Body), Head, =>, Body).
750clause_term(?=>(Head,Body), Head, ?=>, Body).
751clause_term((Head-->Body), Head, -->, Body).
752
753full_stop(Out) :-
754 '$put_token'(Out, '.'),
755 nl(Out).
756
757wrapped_list_directive(module(_,_)).
760
765
766portray_body(Var, _, _, Pri, Out, Options) :-
767 var(Var),
768 !,
769 pprint(Out, Var, Pri, Options).
770portray_body(!, _, _, _, Out, _) :-
771 setting(listing:cut_on_same_line, true),
772 !,
773 write(Out, ' !').
774portray_body((!, Clause), Indent, _, Pri, Out, Options) :-
775 setting(listing:cut_on_same_line, true),
776 \+ term_needs_braces((_,_), Pri),
777 !,
778 write(Out, ' !,'),
779 portray_body(Clause, Indent, indent, 1000, Out, Options).
780portray_body(Term, Indent, indent, Pri, Out, Options) :-
781 !,
782 nlindent(Out, Indent),
783 portray_body(Term, Indent, noindent, Pri, Out, Options).
784portray_body(Or, Indent, _, _, Out, Options) :-
785 or_layout(Or),
786 !,
787 write(Out, '( '),
788 portray_or(Or, Indent, 1200, Out, Options),
789 nlindent(Out, Indent),
790 write(Out, ')').
791portray_body(Term, Indent, _, Pri, Out, Options) :-
792 term_needs_braces(Term, Pri),
793 !,
794 write(Out, '( '),
795 ArgIndent is Indent + 2,
796 portray_body(Term, ArgIndent, noindent, 1200, Out, Options),
797 nlindent(Out, Indent),
798 write(Out, ')').
799portray_body(((AB),C), Indent, _, _Pri, Out, Options) :-
800 nonvar(AB),
801 AB = (A,B),
802 !,
803 infix_op(',', LeftPri, RightPri),
804 portray_body(A, Indent, noindent, LeftPri, Out, Options),
805 write(Out, ','),
806 portray_body((B,C), Indent, indent, RightPri, Out, Options).
807portray_body((A,B), Indent, _, _Pri, Out, Options) :-
808 !,
809 infix_op(',', LeftPri, RightPri),
810 portray_body(A, Indent, noindent, LeftPri, Out, Options),
811 write(Out, ','),
812 portray_body(B, Indent, indent, RightPri, Out, Options).
813portray_body(\+(Goal), Indent, _, _Pri, Out, Options) :-
814 !,
815 write(Out, \+), write(Out, ' '),
816 prefix_op(\+, ArgPri),
817 ArgIndent is Indent+3,
818 portray_body(Goal, ArgIndent, noindent, ArgPri, Out, Options).
819portray_body(Call, _, _, _, Out, Options) :- 820 m_callable(Call),
821 option(module(M), Options, user),
822 predicate_property(M:Call, meta_predicate(Meta)),
823 !,
824 portray_meta(Out, Call, Meta, Options).
825portray_body(Clause, _, _, Pri, Out, Options) :-
826 pprint(Out, Clause, Pri, Options).
827
828m_callable(Term) :-
829 strip_module(Term, _, Plain),
830 callable(Plain),
831 Plain \= (_:_).
832
833term_needs_braces(Term, Pri) :-
834 callable(Term),
835 functor(Term, Name, _Arity),
836 current_op(OpPri, _Type, Name),
837 OpPri > Pri,
838 !.
839
841
842portray_or(Term, Indent, Pri, Out, Options) :-
843 term_needs_braces(Term, Pri),
844 !,
845 inc_indent(Indent, 1, NewIndent),
846 write(Out, '( '),
847 portray_or(Term, NewIndent, Out, Options),
848 nlindent(Out, NewIndent),
849 write(Out, ')').
850portray_or(Term, Indent, _Pri, Out, Options) :-
851 or_layout(Term),
852 !,
853 portray_or(Term, Indent, Out, Options).
854portray_or(Term, Indent, Pri, Out, Options) :-
855 inc_indent(Indent, 1, NestIndent),
856 portray_body(Term, NestIndent, noindent, Pri, Out, Options).
857
858
859portray_or((If -> Then ; Else), Indent, Out, Options) :-
860 !,
861 inc_indent(Indent, 1, NestIndent),
862 infix_op((->), LeftPri, RightPri),
863 portray_body(If, NestIndent, noindent, LeftPri, Out, Options),
864 nlindent(Out, Indent),
865 write(Out, '-> '),
866 portray_body(Then, NestIndent, noindent, RightPri, Out, Options),
867 nlindent(Out, Indent),
868 write(Out, '; '),
869 infix_op(;, _LeftPri, RightPri2),
870 portray_or(Else, Indent, RightPri2, Out, Options).
871portray_or((If *-> Then ; Else), Indent, Out, Options) :-
872 !,
873 inc_indent(Indent, 1, NestIndent),
874 infix_op((*->), LeftPri, RightPri),
875 portray_body(If, NestIndent, noindent, LeftPri, Out, Options),
876 nlindent(Out, Indent),
877 write(Out, '*-> '),
878 portray_body(Then, NestIndent, noindent, RightPri, Out, Options),
879 nlindent(Out, Indent),
880 write(Out, '; '),
881 infix_op(;, _LeftPri, RightPri2),
882 portray_or(Else, Indent, RightPri2, Out, Options).
883portray_or((If -> Then), Indent, Out, Options) :-
884 !,
885 inc_indent(Indent, 1, NestIndent),
886 infix_op((->), LeftPri, RightPri),
887 portray_body(If, NestIndent, noindent, LeftPri, Out, Options),
888 nlindent(Out, Indent),
889 write(Out, '-> '),
890 portray_or(Then, Indent, RightPri, Out, Options).
891portray_or((If *-> Then), Indent, Out, Options) :-
892 !,
893 inc_indent(Indent, 1, NestIndent),
894 infix_op((->), LeftPri, RightPri),
895 portray_body(If, NestIndent, noindent, LeftPri, Out, Options),
896 nlindent(Out, Indent),
897 write(Out, '*-> '),
898 portray_or(Then, Indent, RightPri, Out, Options).
899portray_or((A;B), Indent, Out, Options) :-
900 !,
901 inc_indent(Indent, 1, NestIndent),
902 infix_op(;, LeftPri, RightPri),
903 portray_body(A, NestIndent, noindent, LeftPri, Out, Options),
904 nlindent(Out, Indent),
905 write(Out, '; '),
906 portray_or(B, Indent, RightPri, Out, Options).
907portray_or((A|B), Indent, Out, Options) :-
908 !,
909 inc_indent(Indent, 1, NestIndent),
910 infix_op('|', LeftPri, RightPri),
911 portray_body(A, NestIndent, noindent, LeftPri, Out, Options),
912 nlindent(Out, Indent),
913 write(Out, '| '),
914 portray_or(B, Indent, RightPri, Out, Options).
915
916
921
922infix_op(Op, Left, Right) :-
923 current_op(Pri, Assoc, Op),
924 infix_assoc(Assoc, LeftMin, RightMin),
925 !,
926 Left is Pri - LeftMin,
927 Right is Pri - RightMin.
928
929infix_assoc(xfx, 1, 1).
930infix_assoc(xfy, 1, 0).
931infix_assoc(yfx, 0, 1).
932
933prefix_op(Op, ArgPri) :-
934 current_op(Pri, Assoc, Op),
935 pre_assoc(Assoc, ArgMin),
936 !,
937 ArgPri is Pri - ArgMin.
938
939pre_assoc(fx, 1).
940pre_assoc(fy, 0).
941
942postfix_op(Op, ArgPri) :-
943 current_op(Pri, Assoc, Op),
944 post_assoc(Assoc, ArgMin),
945 !,
946 ArgPri is Pri - ArgMin.
947
948post_assoc(xf, 1).
949post_assoc(yf, 0).
950
957
958or_layout(Var) :-
959 var(Var), !, fail.
960or_layout((_;_)).
961or_layout((_->_)).
962or_layout((_*->_)).
963
964primitive(G) :-
965 or_layout(G), !, fail.
966primitive((_,_)) :- !, fail.
967primitive(_).
968
969
975
976portray_meta(Out, Call, Meta, Options) :-
977 contains_non_primitive_meta_arg(Call, Meta),
978 !,
979 Call =.. [Name|Args],
980 Meta =.. [_|Decls],
981 format(Out, '~q(', [Name]),
982 line_position(Out, Indent),
983 portray_meta_args(Decls, Args, Indent, Out, Options),
984 format(Out, ')', []).
985portray_meta(Out, Call, _, Options) :-
986 pprint(Out, Call, 999, Options).
987
988contains_non_primitive_meta_arg(Call, Decl) :-
989 arg(I, Call, CA),
990 arg(I, Decl, DA),
991 integer(DA),
992 \+ primitive(CA),
993 !.
994
995portray_meta_args([], [], _, _, _).
996portray_meta_args([D|DT], [A|AT], Indent, Out, Options) :-
997 portray_meta_arg(D, A, Out, Options),
998 ( DT == []
999 -> true
1000 ; format(Out, ',', []),
1001 nlindent(Out, Indent),
1002 portray_meta_args(DT, AT, Indent, Out, Options)
1003 ).
1004
1005portray_meta_arg(I, A, Out, Options) :-
1006 integer(I),
1007 !,
1008 line_position(Out, Indent),
1009 portray_body(A, Indent, noindent, 999, Out, Options).
1010portray_meta_arg(_, A, Out, Options) :-
1011 pprint(Out, A, 999, Options).
1012
1020
1021portray_list([], _, Out, _) :-
1022 !,
1023 write(Out, []).
1024portray_list(List, Indent, Out, Options) :-
1025 write(Out, '[ '),
1026 EIndent is Indent + 2,
1027 portray_list_elements(List, EIndent, Out, Options),
1028 nlindent(Out, Indent),
1029 write(Out, ']').
1030
1031portray_list_elements([H|T], EIndent, Out, Options) :-
1032 pprint(Out, H, 999, Options),
1033 ( T == []
1034 -> true
1035 ; nonvar(T), T = [_|_]
1036 -> write(Out, ','),
1037 nlindent(Out, EIndent),
1038 portray_list_elements(T, EIndent, Out, Options)
1039 ; Indent is EIndent - 2,
1040 nlindent(Out, Indent),
1041 write(Out, '| '),
1042 pprint(Out, T, 999, Options)
1043 ).
1044
1056
1057pprint(Out, Term, _, Options) :-
1058 nonvar(Term),
1059 Term = {}(Arg),
1060 line_position(Out, Indent),
1061 ArgIndent is Indent + 2,
1062 format(Out, '{ ', []),
1063 portray_body(Arg, ArgIndent, noident, 1000, Out, Options),
1064 nlindent(Out, Indent),
1065 format(Out, '}', []).
1066pprint(Out, Term, Pri, Options) :-
1067 ( compound(Term)
1068 -> compound_name_arity(Term, _, Arity),
1069 Arity > 0
1070 ; is_dict(Term)
1071 ),
1072 \+ nowrap_term(Term),
1073 setting(listing:line_width, Width),
1074 Width > 0,
1075 ( write_length(Term, Len, [max_length(Width)|Options])
1076 -> true
1077 ; Len = Width
1078 ),
1079 line_position(Out, Indent),
1080 Indent + Len > Width,
1081 Len > Width/4, 1082 !,
1083 pprint_wrapped(Out, Term, Pri, Options).
1084pprint(Out, Term, Pri, Options) :-
1085 listing_write_options(Pri, WrtOptions, Options),
1086 write_term(Out, Term,
1087 [ blobs(portray),
1088 portray_goal(portray_blob)
1089 | WrtOptions
1090 ]).
1091
1092portray_blob(Blob, _Options) :-
1093 blob(Blob, _),
1094 \+ atom(Blob),
1095 !,
1096 format(string(S), '~q', [Blob]),
1097 format('~q', ['$BLOB'(S)]).
1098
1099nowrap_term('$VAR'(_)) :- !.
1100nowrap_term(_{}) :- !. 1101nowrap_term(Term) :-
1102 functor(Term, Name, Arity),
1103 current_op(_, _, Name),
1104 ( Arity == 2
1105 -> infix_op(Name, _, _)
1106 ; Arity == 1
1107 -> ( prefix_op(Name, _)
1108 -> true
1109 ; postfix_op(Name, _)
1110 )
1111 ).
1112
1113
1114pprint_wrapped(Out, Term, _, Options) :-
1115 Term = [_|_],
1116 !,
1117 line_position(Out, Indent),
1118 portray_list(Term, Indent, Out, Options).
1119pprint_wrapped(Out, Dict, _, Options) :-
1120 is_dict(Dict),
1121 !,
1122 dict_pairs(Dict, Tag, Pairs),
1123 pprint(Out, Tag, 1200, Options),
1124 format(Out, '{ ', []),
1125 line_position(Out, Indent),
1126 pprint_nv(Pairs, Indent, Out, Options),
1127 nlindent(Out, Indent-2),
1128 format(Out, '}', []).
1129pprint_wrapped(Out, Term, _, Options) :-
1130 Term =.. [Name|Args],
1131 format(Out, '~q(', [Name]),
1132 line_position(Out, Indent),
1133 pprint_args(Args, Indent, Out, Options),
1134 format(Out, ')', []).
1135
1136pprint_args([], _, _, _).
1137pprint_args([H|T], Indent, Out, Options) :-
1138 pprint(Out, H, 999, Options),
1139 ( T == []
1140 -> true
1141 ; format(Out, ',', []),
1142 nlindent(Out, Indent),
1143 pprint_args(T, Indent, Out, Options)
1144 ).
1145
1146
1147pprint_nv([], _, _, _).
1148pprint_nv([Name-Value|T], Indent, Out, Options) :-
1149 pprint(Out, Name, 999, Options),
1150 format(Out, ':', []),
1151 pprint(Out, Value, 999, Options),
1152 ( T == []
1153 -> true
1154 ; format(Out, ',', []),
1155 nlindent(Out, Indent),
1156 pprint_nv(T, Indent, Out, Options)
1157 ).
1158
1159
1164
1165listing_write_options(Pri,
1166 [ quoted(true),
1167 numbervars(true),
1168 priority(Pri),
1169 spacing(next_argument)
1170 | Options
1171 ],
1172 Options).
1173
1179
1180nlindent(Out, N) :-
1181 nl(Out),
1182 indent(Out, N).
1183
1184indent(Out, N) :-
1185 setting(listing:tab_distance, D),
1186 ( D =:= 0
1187 -> tab(Out, N)
1188 ; Tab is N // D,
1189 Space is N mod D,
1190 put_tabs(Out, Tab),
1191 tab(Out, Space)
1192 ).
1193
1194put_tabs(Out, N) :-
1195 N > 0,
1196 !,
1197 put(Out, 0'\t),
1198 NN is N - 1,
1199 put_tabs(Out, NN).
1200put_tabs(_, _).
1201
1202
1206
1207inc_indent(Indent0, Inc, Indent) :-
1208 Indent is Indent0 + Inc*4.
1209
1210:- multifile
1211 sandbox:safe_meta/2. 1212
1213sandbox:safe_meta(listing(What), []) :-
1214 not_qualified(What).
1215
1216not_qualified(Var) :-
1217 var(Var),
1218 !.
1219not_qualified(_:_) :- !, fail.
1220not_qualified(_).
1221
1222
1226
(Format, Args) :-
1228 stream_property(current_output, tty(true)),
1229 setting(listing:comment_ansi_attributes, Attributes),
1230 Attributes \== [],
1231 !,
1232 ansi_format(Attributes, Format, Args).
1233comment(Format, Args) :-
1234 format(Format, Args)