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:- use_module(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
191
192listing(Spec) :-
193 listing(Spec, []).
194
195listing(Spec, Options) :-
196 call_cleanup(
197 listing_(Spec, Options),
198 close_sources).
199
200listing_(M:Spec, Options) :-
201 var(Spec),
202 !,
203 list_module(M, Options).
204listing_(M:List, Options) :-
205 is_list(List),
206 !,
207 forall(member(Spec, List),
208 listing_(M:Spec, Options)).
209listing_(M:CRef, Options) :-
210 blob(CRef, clause),
211 !,
212 list_clauserefs([CRef], M, Options).
213listing_(X, Options) :-
214 ( prolog:locate_clauses(X, ClauseRefs)
215 -> strip_module(X, Context, _),
216 list_clauserefs(ClauseRefs, Context, Options)
217 ; '$find_predicate'(X, Preds),
218 list_predicates(Preds, X, Options)
219 ).
220
221list_clauserefs([], _, _) :- !.
222list_clauserefs([H|T], Context, Options) :-
223 !,
224 list_clauserefs(H, Context, Options),
225 list_clauserefs(T, Context, Options).
226list_clauserefs(Ref, Context, Options) :-
227 @(rule(M:_, Rule, Ref), Context),
228 list_clause(M:Rule, Ref, Context, Options).
229
231
232list_predicates(PIs, Context:X, Options) :-
233 member(PI, PIs),
234 pi_to_head(PI, Pred),
235 unify_args(Pred, X),
236 list_define(Pred, DefPred),
237 list_predicate(DefPred, Context, Options),
238 nl,
239 fail.
240list_predicates(_, _, _).
241
242list_define(Head, LoadModule:Head) :-
243 compound(Head),
244 Head \= (_:_),
245 functor(Head, Name, Arity),
246 '$find_library'(_, Name, Arity, LoadModule, Library),
247 !,
248 use_module(Library, []).
249list_define(M:Pred, DefM:Pred) :-
250 '$define_predicate'(M:Pred),
251 ( predicate_property(M:Pred, imported_from(DefM))
252 -> true
253 ; DefM = M
254 ).
255
256pi_to_head(PI, _) :-
257 var(PI),
258 !,
259 instantiation_error(PI).
260pi_to_head(M:PI, M:Head) :-
261 !,
262 pi_to_head(PI, Head).
263pi_to_head(Name/Arity, Head) :-
264 functor(Head, Name, Arity).
265
266
269
270unify_args(_, _/_) :- !. 271unify_args(X, X) :- !.
272unify_args(_:X, X) :- !.
273unify_args(_, _).
274
275list_predicate(Pred, Context, _) :-
276 predicate_property(Pred, undefined),
277 !,
278 decl_term(Pred, Context, Decl),
279 comment('% Undefined: ~q~n', [Decl]).
280list_predicate(Pred, Context, _) :-
281 predicate_property(Pred, foreign),
282 !,
283 decl_term(Pred, Context, Decl),
284 comment('% Foreign: ~q~n', [Decl]).
285list_predicate(Pred, Context, Options) :-
286 notify_changed(Pred, Context),
287 list_declarations(Pred, Context),
288 list_clauses(Pred, Context, Options).
289
290decl_term(Pred, Context, Decl) :-
291 strip_module(Pred, Module, Head),
292 functor(Head, Name, Arity),
293 ( hide_module(Module, Context, Head)
294 -> Decl = Name/Arity
295 ; Decl = Module:Name/Arity
296 ).
297
298
299decl(thread_local, thread_local).
300decl(dynamic, dynamic).
301decl(volatile, volatile).
302decl(multifile, multifile).
303decl(public, public).
304
312
313declaration(Pred, Source, Decl) :-
314 predicate_property(Pred, tabled),
315 Pred = M:Head,
316 ( M:'$table_mode'(Head, Head, _)
317 -> decl_term(Pred, Source, Funct),
318 table_options(Pred, Funct, TableDecl),
319 Decl = table(TableDecl)
320 ; comment('% tabled using answer subsumption~n', []),
321 fail 322 ).
323declaration(Pred, Source, Decl) :-
324 decl(Prop, Declname),
325 predicate_property(Pred, Prop),
326 decl_term(Pred, Source, Funct),
327 Decl =.. [ Declname, Funct ].
328declaration(Pred, Source, Decl) :-
329 predicate_property(Pred, meta_predicate(Head)),
330 strip_module(Pred, Module, _),
331 ( (Module == system; Source == Module)
332 -> Decl = meta_predicate(Head)
333 ; Decl = meta_predicate(Module:Head)
334 ),
335 ( meta_implies_transparent(Head)
336 -> ! 337 ; true
338 ).
339declaration(Pred, Source, Decl) :-
340 predicate_property(Pred, transparent),
341 decl_term(Pred, Source, PI),
342 Decl = module_transparent(PI).
343
348
349meta_implies_transparent(Head):-
350 compound(Head),
351 arg(_, Head, Arg),
352 implies_transparent(Arg),
353 !.
354
355implies_transparent(Arg) :-
356 integer(Arg),
357 !.
358implies_transparent(:).
359implies_transparent(//).
360implies_transparent(^).
361
362table_options(Pred, Decl0, as(Decl0, Options)) :-
363 findall(Flag, predicate_property(Pred, tabled(Flag)), [F0|Flags]),
364 !,
365 foldl(table_option, Flags, F0, Options).
366table_options(_, Decl, Decl).
367
368table_option(Flag, X, (Flag,X)).
369
370list_declarations(Pred, Source) :-
371 findall(Decl, declaration(Pred, Source, Decl), Decls),
372 ( Decls == []
373 -> true
374 ; write_declarations(Decls, Source),
375 format('~n', [])
376 ).
377
378
379write_declarations([], _) :- !.
380write_declarations([H|T], Module) :-
381 format(':- ~q.~n', [H]),
382 write_declarations(T, Module).
383
384list_clauses(Pred, Source, Options) :-
385 strip_module(Pred, Module, Head),
386 most_general_goal(Head, GenHead),
387 forall(( rule(Module:GenHead, Rule, Ref),
388 \+ \+ rule_head(Rule, Head)
389 ),
390 list_clause(Module:Rule, Ref, Source, Options)).
391
392rule_head((Head0 :- _Body), Head) :- !, Head = Head0.
393rule_head((Head0,_Cond => _Body), Head) :- !, Head = Head0.
394rule_head((Head0 => _Body), Head) :- !, Head = Head0.
395rule_head(?=>(Head0, _Body), Head) :- !, Head = Head0.
396rule_head(Head, Head).
397
399
400list_clause(_Rule, Ref, _Source, Options) :-
401 option(source(true), Options),
402 ( clause_property(Ref, file(File)),
403 clause_property(Ref, line_count(Line)),
404 catch(source_clause_string(File, Line, String, Repositioned),
405 _, fail),
406 debug(listing(source), 'Read ~w:~d: "~s"~n', [File, Line, String])
407 -> !,
408 ( Repositioned == true
409 -> comment('% From ~w:~d~n', [ File, Line ])
410 ; true
411 ),
412 writeln(String)
413 ; decompiled
414 -> fail
415 ; asserta(decompiled),
416 comment('% From database (decompiled)~n', []),
417 fail 418 ).
419list_clause(Module:(Head:-Body), Ref, Source, Options) :-
420 !,
421 list_clause(Module:Head, Body, :-, Ref, Source, Options).
422list_clause(Module:(Head=>Body), Ref, Source, Options) :-
423 list_clause(Module:Head, Body, =>, Ref, Source, Options).
424list_clause(Module:Head, Ref, Source, Options) :-
425 !,
426 list_clause(Module:Head, true, :-, Ref, Source, Options).
427
428list_clause(Module:Head, Body, Neck, Ref, Source, Options) :-
429 restore_variable_names(Module, Head, Body, Ref, Options),
430 write_module(Module, Source, Head),
431 Rule =.. [Neck,Head,Body],
432 portray_clause(Rule).
433
438
439restore_variable_names(Module, Head, Body, Ref, Options) :-
440 option(variable_names(source), Options, source),
441 catch(clause_info(Ref, _, _, _,
442 [ head(QHead),
443 body(Body),
444 variable_names(Bindings)
445 ]),
446 _, true),
447 unify_head(Module, Head, QHead),
448 !,
449 bind_vars(Bindings),
450 name_other_vars((Head:-Body), Bindings).
451restore_variable_names(_,_,_,_,_).
452
453unify_head(Module, Head, Module:Head) :-
454 !.
455unify_head(_, Head, Head) :-
456 !.
457unify_head(_, _, _).
458
459bind_vars([]) :-
460 !.
461bind_vars([Name = Var|T]) :-
462 ignore(Var = '$VAR'(Name)),
463 bind_vars(T).
464
469
470name_other_vars(Term, Bindings) :-
471 term_singletons(Term, Singletons),
472 bind_singletons(Singletons),
473 term_variables(Term, Vars),
474 name_vars(Vars, 0, Bindings).
475
476bind_singletons([]).
477bind_singletons(['$VAR'('_')|T]) :-
478 bind_singletons(T).
479
480name_vars([], _, _).
481name_vars([H|T], N, Bindings) :-
482 between(N, infinite, N2),
483 var_name(N2, Name),
484 \+ memberchk(Name=_, Bindings),
485 !,
486 H = '$VAR'(N2),
487 N3 is N2 + 1,
488 name_vars(T, N3, Bindings).
489
490var_name(I, Name) :- 491 L is (I mod 26)+0'A,
492 N is I // 26,
493 ( N == 0
494 -> char_code(Name, L)
495 ; format(atom(Name), '~c~d', [L, N])
496 ).
497
498write_module(Module, Context, Head) :-
499 hide_module(Module, Context, Head),
500 !.
501write_module(Module, _, _) :-
502 format('~q:', [Module]).
503
504hide_module(system, Module, Head) :-
505 predicate_property(Module:Head, imported_from(M)),
506 predicate_property(system:Head, imported_from(M)),
507 !.
508hide_module(Module, Module, _) :- !.
509
510notify_changed(Pred, Context) :-
511 strip_module(Pred, user, Head),
512 predicate_property(Head, built_in),
513 \+ predicate_property(Head, (dynamic)),
514 !,
515 decl_term(Pred, Context, Decl),
516 comment('% NOTE: system definition has been overruled for ~q~n',
517 [Decl]).
518notify_changed(_, _).
519
524
525source_clause_string(File, Line, String, Repositioned) :-
526 open_source(File, Line, Stream, Repositioned),
527 stream_property(Stream, position(Start)),
528 '$raw_read'(Stream, _TextWithoutComments),
529 stream_property(Stream, position(End)),
530 stream_position_data(char_count, Start, StartChar),
531 stream_position_data(char_count, End, EndChar),
532 Length is EndChar - StartChar,
533 set_stream_position(Stream, Start),
534 read_string(Stream, Length, String),
535 skip_blanks_and_comments(Stream, blank).
536
537skip_blanks_and_comments(Stream, _) :-
538 at_end_of_stream(Stream),
539 !.
540skip_blanks_and_comments(Stream, State0) :-
541 peek_string(Stream, 80, String),
542 string_chars(String, Chars),
543 phrase(blanks_and_comments(State0, State), Chars, Rest),
544 ( Rest == []
545 -> read_string(Stream, 80, _),
546 skip_blanks_and_comments(Stream, State)
547 ; length(Chars, All),
548 length(Rest, RLen),
549 Skip is All-RLen,
550 read_string(Stream, Skip, _)
551 ).
552
553blanks_and_comments(State0, State) -->
554 [C],
555 { transition(C, State0, State1) },
556 !,
557 blanks_and_comments(State1, State).
558blanks_and_comments(State, State) -->
559 [].
560
561transition(C, blank, blank) :-
562 char_type(C, space).
563transition('%', blank, line_comment).
564transition('\n', line_comment, blank).
565transition(_, line_comment, line_comment).
566transition('/', blank, comment_0).
567transition('/', comment(N), comment(N,/)).
568transition('*', comment(N,/), comment(N1)) :-
569 N1 is N + 1.
570transition('*', comment_0, comment(1)).
571transition('*', comment(N), comment(N,*)).
572transition('/', comment(N,*), State) :-
573 ( N == 1
574 -> State = blank
575 ; N2 is N - 1,
576 State = comment(N2)
577 ).
578
579
580open_source(File, Line, Stream, Repositioned) :-
581 source_stream(File, Stream, Pos0, Repositioned),
582 line_count(Stream, Line0),
583 ( Line >= Line0
584 -> Skip is Line - Line0
585 ; set_stream_position(Stream, Pos0),
586 Skip is Line - 1
587 ),
588 debug(listing(source), '~w: skip ~d to ~d', [File, Line0, Line]),
589 ( Skip =\= 0
590 -> Repositioned = true
591 ; true
592 ),
593 forall(between(1, Skip, _),
594 skip(Stream, 0'\n)).
595
596:- thread_local
597 opened_source/3,
598 decompiled/0. 599
600source_stream(File, Stream, Pos0, _) :-
601 opened_source(File, Stream, Pos0),
602 !.
603source_stream(File, Stream, Pos0, true) :-
604 open(File, read, Stream),
605 stream_property(Stream, position(Pos0)),
606 asserta(opened_source(File, Stream, Pos0)).
607
608close_sources :-
609 retractall(decompiled),
610 forall(retract(opened_source(_,Stream,_)),
611 close(Stream)).
612
613
641
647
650portray_clause(Term) :-
651 current_output(Out),
652 portray_clause(Out, Term).
653
654portray_clause(Stream, Term) :-
655 must_be(stream, Stream),
656 portray_clause(Stream, Term, []).
657
658portray_clause(Stream, Term, M:Options) :-
659 must_be(list, Options),
660 meta_options(is_meta, M:Options, QOptions),
661 \+ \+ name_vars_and_portray_clause(Stream, Term, QOptions).
662
663name_vars_and_portray_clause(Stream, Term, Options) :-
664 term_attvars(Term, []),
665 !,
666 clause_vars(Term, Options),
667 do_portray_clause(Stream, Term, Options).
668name_vars_and_portray_clause(Stream, Term, Options) :-
669 option(variable_names(Bindings), Options),
670 !,
671 copy_term_nat(Term+Bindings, Copy+BCopy),
672 bind_vars(BCopy),
673 name_other_vars(Copy, BCopy),
674 do_portray_clause(Stream, Copy, Options).
675name_vars_and_portray_clause(Stream, Term, Options) :-
676 copy_term_nat(Term, Copy),
677 clause_vars(Copy, Options),
678 do_portray_clause(Stream, Copy, Options).
679
680clause_vars(Clause, Options) :-
681 option(variable_names(Bindings), Options),
682 !,
683 bind_vars(Bindings),
684 name_other_vars(Clause, Bindings).
685clause_vars(Clause, _) :-
686 numbervars(Clause, 0, _,
687 [ singletons(true)
688 ]).
689
690is_meta(portray_goal).
691
692do_portray_clause(Out, Var, Options) :-
693 var(Var),
694 !,
695 option(indent(LeftMargin), Options, 0),
696 indent(Out, LeftMargin),
697 pprint(Out, Var, 1200, Options).
698do_portray_clause(Out, (Head :- true), Options) :-
699 !,
700 option(indent(LeftMargin), Options, 0),
701 indent(Out, LeftMargin),
702 pprint(Out, Head, 1200, Options),
703 full_stop(Out).
704do_portray_clause(Out, Term, Options) :-
705 clause_term(Term, Head, Neck, Body),
706 !,
707 option(indent(LeftMargin), Options, 0),
708 inc_indent(LeftMargin, 1, Indent),
709 infix_op(Neck, RightPri, LeftPri),
710 indent(Out, LeftMargin),
711 pprint(Out, Head, LeftPri, Options),
712 format(Out, ' ~w', [Neck]),
713 ( nonvar(Body),
714 Body = Module:LocalBody,
715 \+ primitive(LocalBody)
716 -> nlindent(Out, Indent),
717 format(Out, '~q', [Module]),
718 '$put_token'(Out, :),
719 nlindent(Out, Indent),
720 write(Out, '( '),
721 inc_indent(Indent, 1, BodyIndent),
722 portray_body(LocalBody, BodyIndent, noindent, 1200, Out, Options),
723 nlindent(Out, Indent),
724 write(Out, ')')
725 ; setting(listing:body_indentation, BodyIndent0),
726 BodyIndent is LeftMargin+BodyIndent0,
727 portray_body(Body, BodyIndent, indent, RightPri, Out, Options)
728 ),
729 full_stop(Out).
730do_portray_clause(Out, (:-Directive), Options) :-
731 wrapped_list_directive(Directive),
732 !,
733 Directive =.. [Name, Arg, List],
734 option(indent(LeftMargin), Options, 0),
735 indent(Out, LeftMargin),
736 format(Out, ':- ~q(', [Name]),
737 line_position(Out, Indent),
738 format(Out, '~q,', [Arg]),
739 nlindent(Out, Indent),
740 portray_list(List, Indent, Out, Options),
741 write(Out, ').\n').
742do_portray_clause(Out, Clause, Options) :-
743 directive(Clause, Op, Directive),
744 !,
745 option(indent(LeftMargin), Options, 0),
746 indent(Out, LeftMargin),
747 format(Out, '~w ', [Op]),
748 DIndent is LeftMargin+3,
749 portray_body(Directive, DIndent, noindent, 1199, Out, Options),
750 full_stop(Out).
751do_portray_clause(Out, Fact, Options) :-
752 option(indent(LeftMargin), Options, 0),
753 indent(Out, LeftMargin),
754 portray_body(Fact, LeftMargin, noindent, 1200, Out, Options),
755 full_stop(Out).
756
757clause_term((Head:-Body), Head, :-, Body).
758clause_term((Head=>Body), Head, =>, Body).
759clause_term(?=>(Head,Body), Head, ?=>, Body).
760clause_term((Head-->Body), Head, -->, Body).
761
762full_stop(Out) :-
763 '$put_token'(Out, '.'),
764 nl(Out).
765
766directive((:- Directive), :-, Directive).
767directive((?- Directive), ?-, Directive).
768
769wrapped_list_directive(module(_,_)).
772
777
778portray_body(Var, _, _, Pri, Out, Options) :-
779 var(Var),
780 !,
781 pprint(Out, Var, Pri, Options).
782portray_body(!, _, _, _, Out, _) :-
783 setting(listing:cut_on_same_line, true),
784 !,
785 write(Out, ' !').
786portray_body((!, Clause), Indent, _, Pri, Out, Options) :-
787 setting(listing:cut_on_same_line, true),
788 \+ term_needs_braces((_,_), Pri),
789 !,
790 write(Out, ' !,'),
791 portray_body(Clause, Indent, indent, 1000, Out, Options).
792portray_body(Term, Indent, indent, Pri, Out, Options) :-
793 !,
794 nlindent(Out, Indent),
795 portray_body(Term, Indent, noindent, Pri, Out, Options).
796portray_body(Or, Indent, _, _, Out, Options) :-
797 or_layout(Or),
798 !,
799 write(Out, '( '),
800 portray_or(Or, Indent, 1200, Out, Options),
801 nlindent(Out, Indent),
802 write(Out, ')').
803portray_body(Term, Indent, _, Pri, Out, Options) :-
804 term_needs_braces(Term, Pri),
805 !,
806 write(Out, '( '),
807 ArgIndent is Indent + 2,
808 portray_body(Term, ArgIndent, noindent, 1200, Out, Options),
809 nlindent(Out, Indent),
810 write(Out, ')').
811portray_body(((AB),C), Indent, _, _Pri, Out, Options) :-
812 nonvar(AB),
813 AB = (A,B),
814 !,
815 infix_op(',', LeftPri, RightPri),
816 portray_body(A, Indent, noindent, LeftPri, Out, Options),
817 write(Out, ','),
818 portray_body((B,C), Indent, indent, RightPri, Out, Options).
819portray_body((A,B), Indent, _, _Pri, Out, Options) :-
820 !,
821 infix_op(',', LeftPri, RightPri),
822 portray_body(A, Indent, noindent, LeftPri, Out, Options),
823 write(Out, ','),
824 portray_body(B, Indent, indent, RightPri, Out, Options).
825portray_body(\+(Goal), Indent, _, _Pri, Out, Options) :-
826 !,
827 write(Out, \+), write(Out, ' '),
828 prefix_op(\+, ArgPri),
829 ArgIndent is Indent+3,
830 portray_body(Goal, ArgIndent, noindent, ArgPri, Out, Options).
831portray_body(Call, _, _, _, Out, Options) :- 832 m_callable(Call),
833 option(module(M), Options, user),
834 predicate_property(M:Call, meta_predicate(Meta)),
835 !,
836 portray_meta(Out, Call, Meta, Options).
837portray_body(Clause, _, _, Pri, Out, Options) :-
838 pprint(Out, Clause, Pri, Options).
839
840m_callable(Term) :-
841 strip_module(Term, _, Plain),
842 callable(Plain),
843 Plain \= (_:_).
844
845term_needs_braces(Term, Pri) :-
846 callable(Term),
847 functor(Term, Name, _Arity),
848 current_op(OpPri, _Type, Name),
849 OpPri > Pri,
850 !.
851
853
854portray_or(Term, Indent, Pri, Out, Options) :-
855 term_needs_braces(Term, Pri),
856 !,
857 inc_indent(Indent, 1, NewIndent),
858 write(Out, '( '),
859 portray_or(Term, NewIndent, Out, Options),
860 nlindent(Out, NewIndent),
861 write(Out, ')').
862portray_or(Term, Indent, _Pri, Out, Options) :-
863 or_layout(Term),
864 !,
865 portray_or(Term, Indent, Out, Options).
866portray_or(Term, Indent, Pri, Out, Options) :-
867 inc_indent(Indent, 1, NestIndent),
868 portray_body(Term, NestIndent, noindent, Pri, Out, Options).
869
870
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 ; Else), 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_body(Then, NestIndent, noindent, RightPri, Out, Options),
891 nlindent(Out, Indent),
892 write(Out, '; '),
893 infix_op(;, _LeftPri, RightPri2),
894 portray_or(Else, Indent, RightPri2, Out, Options).
895portray_or((If -> Then), Indent, Out, Options) :-
896 !,
897 inc_indent(Indent, 1, NestIndent),
898 infix_op((->), LeftPri, RightPri),
899 portray_body(If, NestIndent, noindent, LeftPri, Out, Options),
900 nlindent(Out, Indent),
901 write(Out, '-> '),
902 portray_or(Then, Indent, RightPri, Out, Options).
903portray_or((If *-> Then), Indent, Out, Options) :-
904 !,
905 inc_indent(Indent, 1, NestIndent),
906 infix_op((->), LeftPri, RightPri),
907 portray_body(If, NestIndent, noindent, LeftPri, Out, Options),
908 nlindent(Out, Indent),
909 write(Out, '*-> '),
910 portray_or(Then, Indent, RightPri, Out, Options).
911portray_or((A;B), Indent, Out, Options) :-
912 !,
913 inc_indent(Indent, 1, NestIndent),
914 infix_op(;, LeftPri, RightPri),
915 portray_body(A, NestIndent, noindent, LeftPri, Out, Options),
916 nlindent(Out, Indent),
917 write(Out, '; '),
918 portray_or(B, Indent, RightPri, Out, Options).
919portray_or((A|B), Indent, Out, Options) :-
920 !,
921 inc_indent(Indent, 1, NestIndent),
922 infix_op('|', LeftPri, RightPri),
923 portray_body(A, NestIndent, noindent, LeftPri, Out, Options),
924 nlindent(Out, Indent),
925 write(Out, '| '),
926 portray_or(B, Indent, RightPri, Out, Options).
927
928
933
934infix_op(Op, Left, Right) :-
935 current_op(Pri, Assoc, Op),
936 infix_assoc(Assoc, LeftMin, RightMin),
937 !,
938 Left is Pri - LeftMin,
939 Right is Pri - RightMin.
940
941infix_assoc(xfx, 1, 1).
942infix_assoc(xfy, 1, 0).
943infix_assoc(yfx, 0, 1).
944
945prefix_op(Op, ArgPri) :-
946 current_op(Pri, Assoc, Op),
947 pre_assoc(Assoc, ArgMin),
948 !,
949 ArgPri is Pri - ArgMin.
950
951pre_assoc(fx, 1).
952pre_assoc(fy, 0).
953
954postfix_op(Op, ArgPri) :-
955 current_op(Pri, Assoc, Op),
956 post_assoc(Assoc, ArgMin),
957 !,
958 ArgPri is Pri - ArgMin.
959
960post_assoc(xf, 1).
961post_assoc(yf, 0).
962
969
970or_layout(Var) :-
971 var(Var), !, fail.
972or_layout((_;_)).
973or_layout((_->_)).
974or_layout((_*->_)).
975
976primitive(G) :-
977 or_layout(G), !, fail.
978primitive((_,_)) :- !, fail.
979primitive(_).
980
981
987
988portray_meta(Out, Call, Meta, Options) :-
989 contains_non_primitive_meta_arg(Call, Meta),
990 !,
991 Call =.. [Name|Args],
992 Meta =.. [_|Decls],
993 format(Out, '~q(', [Name]),
994 line_position(Out, Indent),
995 portray_meta_args(Decls, Args, Indent, Out, Options),
996 format(Out, ')', []).
997portray_meta(Out, Call, _, Options) :-
998 pprint(Out, Call, 999, Options).
999
1000contains_non_primitive_meta_arg(Call, Decl) :-
1001 arg(I, Call, CA),
1002 arg(I, Decl, DA),
1003 integer(DA),
1004 \+ primitive(CA),
1005 !.
1006
1007portray_meta_args([], [], _, _, _).
1008portray_meta_args([D|DT], [A|AT], Indent, Out, Options) :-
1009 portray_meta_arg(D, A, Out, Options),
1010 ( DT == []
1011 -> true
1012 ; format(Out, ',', []),
1013 nlindent(Out, Indent),
1014 portray_meta_args(DT, AT, Indent, Out, Options)
1015 ).
1016
1017portray_meta_arg(I, A, Out, Options) :-
1018 integer(I),
1019 !,
1020 line_position(Out, Indent),
1021 portray_body(A, Indent, noindent, 999, Out, Options).
1022portray_meta_arg(_, A, Out, Options) :-
1023 pprint(Out, A, 999, Options).
1024
1032
1033portray_list([], _, Out, _) :-
1034 !,
1035 write(Out, []).
1036portray_list(List, Indent, Out, Options) :-
1037 write(Out, '[ '),
1038 EIndent is Indent + 2,
1039 portray_list_elements(List, EIndent, Out, Options),
1040 nlindent(Out, Indent),
1041 write(Out, ']').
1042
1043portray_list_elements([H|T], EIndent, Out, Options) :-
1044 pprint(Out, H, 999, Options),
1045 ( T == []
1046 -> true
1047 ; nonvar(T), T = [_|_]
1048 -> write(Out, ','),
1049 nlindent(Out, EIndent),
1050 portray_list_elements(T, EIndent, Out, Options)
1051 ; Indent is EIndent - 2,
1052 nlindent(Out, Indent),
1053 write(Out, '| '),
1054 pprint(Out, T, 999, Options)
1055 ).
1056
1068
1069pprint(Out, Term, _, Options) :-
1070 nonvar(Term),
1071 Term = {}(Arg),
1072 line_position(Out, Indent),
1073 ArgIndent is Indent + 2,
1074 format(Out, '{ ', []),
1075 portray_body(Arg, ArgIndent, noident, 1000, Out, Options),
1076 nlindent(Out, Indent),
1077 format(Out, '}', []).
1078pprint(Out, Term, Pri, Options) :-
1079 ( compound(Term)
1080 -> compound_name_arity(Term, _, Arity),
1081 Arity > 0
1082 ; is_dict(Term)
1083 ),
1084 \+ nowrap_term(Term),
1085 setting(listing:line_width, Width),
1086 Width > 0,
1087 ( write_length(Term, Len, [max_length(Width)|Options])
1088 -> true
1089 ; Len = Width
1090 ),
1091 line_position(Out, Indent),
1092 Indent + Len > Width,
1093 Len > Width/4, 1094 !,
1095 pprint_wrapped(Out, Term, Pri, Options).
1096pprint(Out, Term, Pri, Options) :-
1097 listing_write_options(Pri, WrtOptions, Options),
1098 write_term(Out, Term,
1099 [ blobs(portray),
1100 portray_goal(portray_blob)
1101 | WrtOptions
1102 ]).
1103
1104portray_blob(Blob, _Options) :-
1105 blob(Blob, _),
1106 \+ atom(Blob),
1107 !,
1108 format(string(S), '~q', [Blob]),
1109 format('~q', ['$BLOB'(S)]).
1110
1111nowrap_term('$VAR'(_)) :- !.
1112nowrap_term(_{}) :- !. 1113nowrap_term(Term) :-
1114 functor(Term, Name, Arity),
1115 current_op(_, _, Name),
1116 ( Arity == 2
1117 -> infix_op(Name, _, _)
1118 ; Arity == 1
1119 -> ( prefix_op(Name, _)
1120 -> true
1121 ; postfix_op(Name, _)
1122 )
1123 ).
1124
1125
1126pprint_wrapped(Out, Term, _, Options) :-
1127 Term = [_|_],
1128 !,
1129 line_position(Out, Indent),
1130 portray_list(Term, Indent, Out, Options).
1131pprint_wrapped(Out, Dict, _, Options) :-
1132 is_dict(Dict),
1133 !,
1134 dict_pairs(Dict, Tag, Pairs),
1135 pprint(Out, Tag, 1200, Options),
1136 format(Out, '{ ', []),
1137 line_position(Out, Indent),
1138 pprint_nv(Pairs, Indent, Out, Options),
1139 nlindent(Out, Indent-2),
1140 format(Out, '}', []).
1141pprint_wrapped(Out, Term, _, Options) :-
1142 Term =.. [Name|Args],
1143 format(Out, '~q(', [Name]),
1144 line_position(Out, Indent),
1145 pprint_args(Args, Indent, Out, Options),
1146 format(Out, ')', []).
1147
1148pprint_args([], _, _, _).
1149pprint_args([H|T], Indent, Out, Options) :-
1150 pprint(Out, H, 999, Options),
1151 ( T == []
1152 -> true
1153 ; format(Out, ',', []),
1154 nlindent(Out, Indent),
1155 pprint_args(T, Indent, Out, Options)
1156 ).
1157
1158
1159pprint_nv([], _, _, _).
1160pprint_nv([Name-Value|T], Indent, Out, Options) :-
1161 pprint(Out, Name, 999, Options),
1162 format(Out, ':', []),
1163 pprint(Out, Value, 999, Options),
1164 ( T == []
1165 -> true
1166 ; format(Out, ',', []),
1167 nlindent(Out, Indent),
1168 pprint_nv(T, Indent, Out, Options)
1169 ).
1170
1171
1176
1177listing_write_options(Pri,
1178 [ quoted(true),
1179 numbervars(true),
1180 priority(Pri),
1181 spacing(next_argument)
1182 | Options
1183 ],
1184 Options).
1185
1191
1192nlindent(Out, N) :-
1193 nl(Out),
1194 indent(Out, N).
1195
1196indent(Out, N) :-
1197 setting(listing:tab_distance, D),
1198 ( D =:= 0
1199 -> tab(Out, N)
1200 ; Tab is N // D,
1201 Space is N mod D,
1202 put_tabs(Out, Tab),
1203 tab(Out, Space)
1204 ).
1205
1206put_tabs(Out, N) :-
1207 N > 0,
1208 !,
1209 put(Out, 0'\t),
1210 NN is N - 1,
1211 put_tabs(Out, NN).
1212put_tabs(_, _).
1213
1214
1218
1219inc_indent(Indent0, Inc, Indent) :-
1220 Indent is Indent0 + Inc*4.
1221
1222:- multifile
1223 sandbox:safe_meta/2. 1224
1225sandbox:safe_meta(listing(What), []) :-
1226 not_qualified(What).
1227
1228not_qualified(Var) :-
1229 var(Var),
1230 !.
1231not_qualified(_:_) :- !, fail.
1232not_qualified(_).
1233
1234
1238
(Format, Args) :-
1240 stream_property(current_output, tty(true)),
1241 setting(listing:comment_ansi_attributes, Attributes),
1242 Attributes \== [],
1243 !,
1244 ansi_format(Attributes, Format, Args).
1245comment(Format, Args) :-
1246 format(Format, Args)