View source with raw comments or as raw
   1/*  Part of SWI-Prolog
   2
   3    Author:        Jan Wielemaker
   4    E-mail:        J.Wielemaker@vu.nl
   5    WWW:           http://www.swi-prolog.org
   6    Copyright (c)  2001-2016, University of Amsterdam
   7                              VU University Amsterdam
   8    All rights reserved.
   9
  10    Redistribution and use in source and binary forms, with or without
  11    modification, are permitted provided that the following conditions
  12    are met:
  13
  14    1. Redistributions of source code must retain the above copyright
  15       notice, this list of conditions and the following disclaimer.
  16
  17    2. Redistributions in binary form must reproduce the above copyright
  18       notice, this list of conditions and the following disclaimer in
  19       the documentation and/or other materials provided with the
  20       distribution.
  21
  22    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  25    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  26    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  27    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  28    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  29    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  30    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  32    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33    POSSIBILITY OF SUCH DAMAGE.
  34*/
  35
  36:- module(prolog_listing,
  37        [ listing/0,
  38          listing/1,
  39          portray_clause/1,             % +Clause
  40          portray_clause/2,             % +Stream, +Clause
  41          portray_clause/3              % +Stream, +Clause, +Options
  42        ]).
  43:- use_module(library(lists)).
  44:- use_module(library(settings)).
  45:- use_module(library(option)).
  46:- use_module(library(error)).
  47:- set_prolog_flag(generate_debug_info, false).
  48
  49:- module_transparent
  50    listing/0.
  51:- meta_predicate
  52    listing(:),
  53    portray_clause(+,+,:).
  54
  55:- predicate_options(portray_clause/3, 3, [pass_to(system:write_term/3, 3)]).
  56
  57:- multifile
  58    prolog:locate_clauses/2.        % +Spec, -ClauseRefList
  59
  60/** <module> List programs and pretty print clauses
  61
  62This module implements listing code from  the internal representation in
  63a human readable format.
  64
  65    * listing/0 lists a module.
  66    * listing/1 lists a predicate or matching clause
  67    * portray_clause/2 pretty-prints a clause-term
  68
  69Layout can be customized using library(settings). The effective settings
  70can be listed using list_settings/1 as   illustrated below. Settings can
  71be changed using set_setting/2.
  72
  73    ==
  74    ?- list_settings(listing).
  75    ========================================================================
  76    Name                      Value (*=modified) Comment
  77    ========================================================================
  78    listing:body_indentation  8              Indentation used goals in the body
  79    listing:tab_distance      8              Distance between tab-stops.
  80    ...
  81    ==
  82
  83@tbd    More settings, support _|Coding Guidelines for Prolog|_ and make
  84        the suggestions there the default.
  85@tbd    Provide persistent user customization
  86*/
  87
  88:- setting(listing:body_indentation, nonneg, 8,
  89           'Indentation used goals in the body').
  90:- setting(listing:tab_distance, nonneg, 8,
  91           'Distance between tab-stops.  0 uses only spaces').
  92:- setting(listing:cut_on_same_line, boolean, true,
  93           'Place cuts (!) on the same line').
  94:- setting(listing:line_width, nonneg, 78,
  95           'Width of a line.  0 is infinite').
  96
  97
  98%!  listing
  99%
 100%   Lists all predicates defined  in   the  calling module. Imported
 101%   predicates are not listed. To  list   the  content of the module
 102%   =mymodule=, use:
 103%
 104%     ==
 105%     ?- mymodule:listing.
 106%     ==
 107
 108listing :-
 109    context_module(Context),
 110    list_module(Context).
 111
 112list_module(Module) :-
 113    (   current_predicate(_, Module:Pred),
 114        \+ predicate_property(Module:Pred, imported_from(_)),
 115        strip_module(Pred, _Module, Head),
 116        functor(Head, Name, _Arity),
 117        (   (   predicate_property(Pred, built_in)
 118            ;   sub_atom(Name, 0, _, _, $)
 119            )
 120        ->  current_prolog_flag(access_level, system)
 121        ;   true
 122        ),
 123        nl,
 124        list_predicate(Module:Head, Module),
 125        fail
 126    ;   true
 127    ).
 128
 129
 130%!  listing(:What)
 131%
 132%   List matching clauses. What is either a plain specification or a
 133%   list of specifications. Plain specifications are:
 134%
 135%     * Predicate indicator (Name/Arity or Name//Arity)
 136%     Lists the indicated predicate.  This also outputs relevant
 137%     _declarations_, such as multifile/1 or dynamic/1.
 138%
 139%     * A _Head_ term.  In this case, only clauses whose head
 140%     unify with _Head_ are listed.  This is illustrated in the
 141%     query below that only lists the first clause of append/3.
 142%
 143%       ==
 144%       ?- listing(append([], _, _)).
 145%       lists:append([], A, A).
 146%       ==
 147
 148listing(M:Spec) :-
 149    var(Spec),
 150    !,
 151    list_module(M).
 152listing(M:List) :-
 153    is_list(List),
 154    !,
 155    forall(member(Spec, List),
 156           listing(M:Spec)).
 157listing(X) :-
 158    (   prolog:locate_clauses(X, ClauseRefs)
 159    ->  list_clauserefs(ClauseRefs)
 160    ;   '$find_predicate'(X, Preds),
 161        list_predicates(Preds, X)
 162    ).
 163
 164list_clauserefs([]) :- !.
 165list_clauserefs([H|T]) :-
 166    !,
 167    list_clauserefs(H),
 168    list_clauserefs(T).
 169list_clauserefs(Ref) :-
 170    clause(Head, Body, Ref),
 171    portray_clause((Head :- Body)).
 172
 173%!  list_predicates(:Preds:list(pi), :Spec) is det.
 174
 175list_predicates(PIs, Context:X) :-
 176    member(PI, PIs),
 177    pi_to_head(PI, Pred),
 178    unify_args(Pred, X),
 179    list_define(Pred, DefPred),
 180    list_predicate(DefPred, Context),
 181    nl,
 182    fail.
 183list_predicates(_, _).
 184
 185list_define(Head, LoadModule:Head) :-
 186    compound(Head),
 187    Head \= (_:_),
 188    functor(Head, Name, Arity),
 189    '$find_library'(_, Name, Arity, LoadModule, Library),
 190    !,
 191    use_module(Library, []).
 192list_define(M:Pred, DefM:Pred) :-
 193    '$define_predicate'(M:Pred),
 194    (   predicate_property(M:Pred, imported_from(DefM))
 195    ->  true
 196    ;   DefM = M
 197    ).
 198
 199pi_to_head(PI, _) :-
 200    var(PI),
 201    !,
 202    instantiation_error(PI).
 203pi_to_head(M:PI, M:Head) :-
 204    !,
 205    pi_to_head(PI, Head).
 206pi_to_head(Name/Arity, Head) :-
 207    functor(Head, Name, Arity).
 208
 209
 210%       Unify the arguments of the specification with the given term,
 211%       so we can partially instantate the head.
 212
 213unify_args(_, _/_) :- !.                % Name/arity spec
 214unify_args(X, X) :- !.
 215unify_args(_:X, X) :- !.
 216unify_args(_, _).
 217
 218list_predicate(Pred, Context) :-
 219    predicate_property(Pred, undefined),
 220    !,
 221    decl_term(Pred, Context, Decl),
 222    format('%   Undefined: ~q~n', [Decl]).
 223list_predicate(Pred, Context) :-
 224    predicate_property(Pred, foreign),
 225    !,
 226    decl_term(Pred, Context, Decl),
 227    format('%   Foreign: ~q~n', [Decl]).
 228list_predicate(Pred, Context) :-
 229    notify_changed(Pred, Context),
 230    list_declarations(Pred, Context),
 231    list_clauses(Pred, Context).
 232
 233decl_term(Pred, Context, Decl) :-
 234    strip_module(Pred, Module, Head),
 235    functor(Head, Name, Arity),
 236    (   hide_module(Module, Context, Head)
 237    ->  Decl = Name/Arity
 238    ;   Decl = Module:Name/Arity
 239    ).
 240
 241
 242decl(thread_local, thread_local).
 243decl(dynamic,      dynamic).
 244decl(volatile,     volatile).
 245decl(multifile,    multifile).
 246decl(public,       public).
 247
 248declaration(Pred, Source, Decl) :-
 249    decl(Prop, Declname),
 250    predicate_property(Pred, Prop),
 251    decl_term(Pred, Source, Funct),
 252    Decl =.. [ Declname, Funct ].
 253declaration(Pred, Source, Decl) :-
 254    predicate_property(Pred, meta_predicate(Head)),
 255    strip_module(Pred, Module, _),
 256    (   (Module == system; Source == Module)
 257    ->  Decl = meta_predicate(Head)
 258    ;   Decl = meta_predicate(Module:Head)
 259    ),
 260    (   meta_implies_transparent(Head)
 261    ->  !                                   % hide transparent
 262    ;   true
 263    ).
 264declaration(Pred, Source, Decl) :-
 265    predicate_property(Pred, transparent),
 266    decl_term(Pred, Source, PI),
 267    Decl = module_transparent(PI).
 268
 269%!  meta_implies_transparent(+Head) is semidet.
 270%
 271%   True if the meta-declaration Head implies  that the predicate is
 272%   transparent.
 273
 274meta_implies_transparent(Head):-
 275    compound(Head),
 276    arg(_, Head, Arg),
 277    implies_transparent(Arg),
 278    !.
 279
 280implies_transparent(Arg) :-
 281    integer(Arg),
 282    !.
 283implies_transparent(:).
 284implies_transparent(//).
 285implies_transparent(^).
 286
 287
 288list_declarations(Pred, Source) :-
 289    findall(Decl, declaration(Pred, Source, Decl), Decls),
 290    (   Decls == []
 291    ->  true
 292    ;   write_declarations(Decls, Source),
 293        format('~n', [])
 294    ).
 295
 296
 297write_declarations([], _) :- !.
 298write_declarations([H|T], Module) :-
 299    format(':- ~q.~n', [H]),
 300    write_declarations(T, Module).
 301
 302list_clauses(Pred, Source) :-
 303    strip_module(Pred, Module, Head),
 304    (   clause(Pred, Body),
 305        write_module(Module, Source, Head),
 306        portray_clause((Head:-Body)),
 307        fail
 308    ;   true
 309    ).
 310
 311write_module(Module, Context, Head) :-
 312    hide_module(Module, Context, Head),
 313    !.
 314write_module(Module, _, _) :-
 315    format('~q:', [Module]).
 316
 317hide_module(system, Module, Head) :-
 318    predicate_property(Module:Head, imported_from(M)),
 319    predicate_property(system:Head, imported_from(M)),
 320    !.
 321hide_module(Module, Module, _) :- !.
 322
 323notify_changed(Pred, Context) :-
 324    strip_module(Pred, user, Head),
 325    predicate_property(Head, built_in),
 326    \+ predicate_property(Head, (dynamic)),
 327    !,
 328    decl_term(Pred, Context, Decl),
 329    format('%   NOTE: system definition has been overruled for ~q~n',
 330           [Decl]).
 331notify_changed(_, _).
 332
 333%!  portray_clause(+Clause) is det.
 334%!  portray_clause(+Out:stream, +Clause) is det.
 335%!  portray_clause(+Out:stream, +Clause, +Options) is det.
 336%
 337%   Portray `Clause' on the current  output   stream.  Layout of the
 338%   clause is to our best standards.   As  the actual variable names
 339%   are not available we use A, B, ... Deals with ';', '|', '->' and
 340%   calls via meta-call predicates as determined using the predicate
 341%   property   meta_predicate.   If   Clause   contains   attributed
 342%   variables, these are treated as normal variables.
 343%
 344%   If  Options  is  provided,   the    option-list   is  passed  to
 345%   write_term/3 that does the final writing of arguments.
 346
 347%       The prolog_list_goal/1 hook is  a  dubious   as  it  may lead to
 348%       confusion if the heads relates to other   bodies.  For now it is
 349%       only used for XPCE methods and works just nice.
 350%
 351%       Not really ...  It may confuse the source-level debugger.
 352
 353%portray_clause(Head :- _Body) :-
 354%       user:prolog_list_goal(Head), !.
 355portray_clause(Term) :-
 356    current_output(Out),
 357    portray_clause(Out, Term).
 358
 359portray_clause(Stream, Term) :-
 360    must_be(stream, Stream),
 361    portray_clause(Stream, Term, []).
 362
 363portray_clause(Stream, Term, M:Options) :-
 364    must_be(list, Options),
 365    meta_options(is_meta, M:Options, QOptions),
 366    \+ \+ ( copy_term_nat(Term, Copy),
 367            numbervars(Copy, 0, _,
 368                       [ singletons(true)
 369                       ]),
 370            do_portray_clause(Stream, Copy, QOptions)
 371          ).
 372
 373is_meta(portray_goal).
 374
 375do_portray_clause(Out, Var, Options) :-
 376    var(Var),
 377    !,
 378    pprint(Out, Var, 1200, Options).
 379do_portray_clause(Out, (Head :- true), Options) :-
 380    !,
 381    pprint(Out, Head, 1200, Options),
 382    full_stop(Out).
 383do_portray_clause(Out, Term, Options) :-
 384    clause_term(Term, Head, Neck, Body),
 385    !,
 386    inc_indent(0, 1, Indent),
 387    infix_op(Neck, RightPri, LeftPri),
 388    pprint(Out, Head, LeftPri, Options),
 389    format(Out, ' ~w', [Neck]),
 390    (   nonvar(Body),
 391        Body = Module:LocalBody,
 392        \+ primitive(LocalBody)
 393    ->  nlindent(Out, Indent),
 394        format(Out, '~q', [Module]),
 395        '$put_token'(Out, :),
 396        nlindent(Out, Indent),
 397        write(Out, '(   '),
 398        inc_indent(Indent, 1, BodyIndent),
 399        portray_body(LocalBody, BodyIndent, noindent, 1200, Out, Options),
 400        nlindent(Out, Indent),
 401        write(Out, ')')
 402    ;   setting(listing:body_indentation, BodyIndent),
 403        portray_body(Body, BodyIndent, indent, RightPri, Out, Options)
 404    ),
 405    full_stop(Out).
 406do_portray_clause(Out, (:-use_module(File, Imports)), Options) :-
 407    length(Imports, Len),
 408    Len > 3,
 409    !,
 410    format(Out, ':- use_module(~q,', [File]),
 411    portray_list(Imports, 14, Out, Options),
 412    write(Out, ').\n').
 413do_portray_clause(Out, (:-module(Module, Exports)), Options) :-
 414    !,
 415    format(Out, ':- module(~q,', [Module]),
 416    portray_list(Exports, 10, Out, Options),
 417    write(Out, ').\n').
 418do_portray_clause(Out, (:-Directive), Options) :-
 419    !,
 420    write(Out, ':- '),
 421    portray_body(Directive, 3, noindent, 1199, Out, Options),
 422    full_stop(Out).
 423do_portray_clause(Out, Fact, Options) :-
 424    portray_body(Fact, 0, noindent, 1200, Out, Options),
 425    full_stop(Out).
 426
 427clause_term((Head:-Body), Head, :-, Body).
 428clause_term((Head-->Body), Head, -->, Body).
 429
 430full_stop(Out) :-
 431    '$put_token'(Out, '.'),
 432    nl(Out).
 433
 434
 435%!  portray_body(+Term, +Indent, +DoIndent, +Priority, +Out, +Options)
 436%
 437%   Write Term at current indentation. If   DoIndent  is 'indent' we
 438%   must first call nlindent/2 before emitting anything.
 439
 440portray_body(Var, _, _, Pri, Out, Options) :-
 441    var(Var),
 442    !,
 443    pprint(Out, Var, Pri, Options).
 444portray_body(!, _, _, _, Out, _) :-
 445    setting(listing:cut_on_same_line, true),
 446    !,
 447    write(Out, ' !').
 448portray_body((!, Clause), Indent, _, Pri, Out, Options) :-
 449    setting(listing:cut_on_same_line, true),
 450    \+ term_needs_braces((_,_), Pri),
 451    !,
 452    write(Out, ' !,'),
 453    portray_body(Clause, Indent, indent, 1000, Out, Options).
 454portray_body(Term, Indent, indent, Pri, Out, Options) :-
 455    !,
 456    nlindent(Out, Indent),
 457    portray_body(Term, Indent, noindent, Pri, Out, Options).
 458portray_body(Or, Indent, _, _, Out, Options) :-
 459    or_layout(Or),
 460    !,
 461    write(Out, '(   '),
 462    portray_or(Or, Indent, 1200, Out, Options),
 463    nlindent(Out, Indent),
 464    write(Out, ')').
 465portray_body(Term, Indent, _, Pri, Out, Options) :-
 466    term_needs_braces(Term, Pri),
 467    !,
 468    write(Out, '( '),
 469    ArgIndent is Indent + 2,
 470    portray_body(Term, ArgIndent, noindent, 1200, Out, Options),
 471    nlindent(Out, Indent),
 472    write(Out, ')').
 473portray_body((A,B), Indent, _, _Pri, Out, Options) :-
 474    !,
 475    infix_op(',', LeftPri, RightPri),
 476    portray_body(A, Indent, noindent, LeftPri, Out, Options),
 477    write(Out, ','),
 478    portray_body(B, Indent, indent, RightPri, Out, Options).
 479portray_body(\+(Goal), Indent, _, _Pri, Out, Options) :-
 480    !,
 481    write(Out, \+), write(Out, ' '),
 482    prefix_op(\+, ArgPri),
 483    ArgIndent is Indent+3,
 484    portray_body(Goal, ArgIndent, noindent, ArgPri, Out, Options).
 485portray_body(Call, _, _, _, Out, Options) :- % requires knowledge on the module!
 486    m_callable(Call),
 487    option(module(M), Options, user),
 488    predicate_property(M:Call, meta_predicate(Meta)),
 489    !,
 490    portray_meta(Out, Call, Meta, Options).
 491portray_body(Clause, _, _, Pri, Out, Options) :-
 492    pprint(Out, Clause, Pri, Options).
 493
 494m_callable(Term) :-
 495    strip_module(Term, _, Plain),
 496    callable(Plain),
 497    Plain \= (_:_).
 498
 499term_needs_braces(Term, Pri) :-
 500    callable(Term),
 501    functor(Term, Name, _Arity),
 502    current_op(OpPri, _Type, Name),
 503    OpPri > Pri,
 504    !.
 505
 506%!  portray_or(+Term, +Indent, +Priority, +Out) is det.
 507
 508portray_or(Term, Indent, Pri, Out, Options) :-
 509    term_needs_braces(Term, Pri),
 510    !,
 511    inc_indent(Indent, 1, NewIndent),
 512    write(Out, '(   '),
 513    portray_or(Term, NewIndent, Out, Options),
 514    nlindent(Out, NewIndent),
 515    write(Out, ')').
 516portray_or(Term, Indent, _Pri, Out, Options) :-
 517    or_layout(Term),
 518    !,
 519    portray_or(Term, Indent, Out, Options).
 520portray_or(Term, Indent, Pri, Out, Options) :-
 521    inc_indent(Indent, 1, NestIndent),
 522    portray_body(Term, NestIndent, noindent, Pri, Out, Options).
 523
 524
 525portray_or((If -> Then ; Else), Indent, Out, Options) :-
 526    !,
 527    inc_indent(Indent, 1, NestIndent),
 528    infix_op((->), LeftPri, RightPri),
 529    portray_body(If, NestIndent, noindent, LeftPri, Out, Options),
 530    nlindent(Out, Indent),
 531    write(Out, '->  '),
 532    portray_body(Then, NestIndent, noindent, RightPri, Out, Options),
 533    nlindent(Out, Indent),
 534    write(Out, ';   '),
 535    infix_op(;, _LeftPri, RightPri2),
 536    portray_or(Else, Indent, RightPri2, Out, Options).
 537portray_or((If *-> Then ; Else), Indent, Out, Options) :-
 538    !,
 539    inc_indent(Indent, 1, NestIndent),
 540    infix_op((*->), LeftPri, RightPri),
 541    portray_body(If, NestIndent, noindent, LeftPri, Out, Options),
 542    nlindent(Out, Indent),
 543    write(Out, '*-> '),
 544    portray_body(Then, NestIndent, noindent, RightPri, Out, Options),
 545    nlindent(Out, Indent),
 546    write(Out, ';   '),
 547    infix_op(;, _LeftPri, RightPri2),
 548    portray_or(Else, Indent, RightPri2, Out, Options).
 549portray_or((If -> Then), Indent, Out, Options) :-
 550    !,
 551    inc_indent(Indent, 1, NestIndent),
 552    infix_op((->), LeftPri, RightPri),
 553    portray_body(If, NestIndent, noindent, LeftPri, Out, Options),
 554    nlindent(Out, Indent),
 555    write(Out, '->  '),
 556    portray_or(Then, Indent, RightPri, Out, Options).
 557portray_or((If *-> Then), Indent, Out, Options) :-
 558    !,
 559    inc_indent(Indent, 1, NestIndent),
 560    infix_op((->), LeftPri, RightPri),
 561    portray_body(If, NestIndent, noindent, LeftPri, Out, Options),
 562    nlindent(Out, Indent),
 563    write(Out, '*-> '),
 564    portray_or(Then, Indent, RightPri, Out, Options).
 565portray_or((A;B), Indent, Out, Options) :-
 566    !,
 567    inc_indent(Indent, 1, NestIndent),
 568    infix_op(;, LeftPri, RightPri),
 569    portray_body(A, NestIndent, noindent, LeftPri, Out, Options),
 570    nlindent(Out, Indent),
 571    write(Out, ';   '),
 572    portray_or(B, Indent, RightPri, Out, Options).
 573portray_or((A|B), Indent, Out, Options) :-
 574    !,
 575    inc_indent(Indent, 1, NestIndent),
 576    infix_op('|', LeftPri, RightPri),
 577    portray_body(A, NestIndent, noindent, LeftPri, Out, Options),
 578    nlindent(Out, Indent),
 579    write(Out, '|   '),
 580    portray_or(B, Indent, RightPri, Out, Options).
 581
 582
 583%!  infix_op(+Op, -Left, -Right) is semidet.
 584%
 585%   True if Op is an infix operator and Left is the max priority of its
 586%   left hand and Right is the max priority of its right hand.
 587
 588infix_op(Op, Left, Right) :-
 589    current_op(Pri, Assoc, Op),
 590    infix_assoc(Assoc, LeftMin, RightMin),
 591    !,
 592    Left is Pri - LeftMin,
 593    Right is Pri - RightMin.
 594
 595infix_assoc(xfx, 1, 1).
 596infix_assoc(xfy, 1, 0).
 597infix_assoc(yfx, 0, 1).
 598
 599prefix_op(Op, ArgPri) :-
 600    current_op(Pri, Assoc, Op),
 601    pre_assoc(Assoc, ArgMin),
 602    !,
 603    ArgPri is Pri - ArgMin.
 604
 605pre_assoc(fx, 1).
 606pre_assoc(fy, 0).
 607
 608postfix_op(Op, ArgPri) :-
 609    current_op(Pri, Assoc, Op),
 610    post_assoc(Assoc, ArgMin),
 611    !,
 612    ArgPri is Pri - ArgMin.
 613
 614post_assoc(xf, 1).
 615post_assoc(yf, 0).
 616
 617%!  or_layout(@Term) is semidet.
 618%
 619%   True if Term is a control structure for which we want to use clean
 620%   layout.
 621%
 622%   @tbd    Change name.
 623
 624or_layout(Var) :-
 625    var(Var), !, fail.
 626or_layout((_;_)).
 627or_layout((_->_)).
 628or_layout((_*->_)).
 629
 630primitive(G) :-
 631    or_layout(G), !, fail.
 632primitive((_,_)) :- !, fail.
 633primitive(_).
 634
 635
 636%!  portray_meta(+Out, +Call, +MetaDecl, +Options)
 637%
 638%   Portray a meta-call. If Call   contains non-primitive meta-calls
 639%   we put each argument on a line and layout the body. Otherwise we
 640%   simply print the goal.
 641
 642portray_meta(Out, Call, Meta, Options) :-
 643    contains_non_primitive_meta_arg(Call, Meta),
 644    !,
 645    Call =.. [Name|Args],
 646    Meta =.. [_|Decls],
 647    format(Out, '~q(', [Name]),
 648    line_position(Out, Indent),
 649    portray_meta_args(Decls, Args, Indent, Out, Options),
 650    format(Out, ')', []).
 651portray_meta(Out, Call, _, Options) :-
 652    pprint(Out, Call, 999, Options).
 653
 654contains_non_primitive_meta_arg(Call, Decl) :-
 655    arg(I, Call, CA),
 656    arg(I, Decl, DA),
 657    integer(DA),
 658    \+ primitive(CA),
 659    !.
 660
 661portray_meta_args([], [], _, _, _).
 662portray_meta_args([D|DT], [A|AT], Indent, Out, Options) :-
 663    portray_meta_arg(D, A, Out, Options),
 664    (   DT == []
 665    ->  true
 666    ;   format(Out, ',', []),
 667        nlindent(Out, Indent),
 668        portray_meta_args(DT, AT, Indent, Out, Options)
 669    ).
 670
 671portray_meta_arg(I, A, Out, Options) :-
 672    integer(I),
 673    !,
 674    line_position(Out, Indent),
 675    portray_body(A, Indent, noindent, 999, Out, Options).
 676portray_meta_arg(_, A, Out, Options) :-
 677    pprint(Out, A, 999, Options).
 678
 679%!  portray_list(+List, +Indent, +Out)
 680%
 681%   Portray a list like this.  Right side for improper lists
 682%
 683%           [ element1,             [ element1
 684%             element2,     OR      | tail
 685%           ]                       ]
 686
 687portray_list([], _, Out, _) :-
 688    !,
 689    write(Out, []).
 690portray_list(List, Indent, Out, Options) :-
 691    nlindent(Out, Indent),
 692    write(Out, '[ '),
 693    EIndent is Indent + 2,
 694    portray_list_elements(List, EIndent, Out, Options),
 695    nlindent(Out, Indent),
 696    write(Out, ']').
 697
 698portray_list_elements([H|T], EIndent, Out, Options) :-
 699    pprint(Out, H, 999, Options),
 700    (   T == []
 701    ->  true
 702    ;   nonvar(T), T = [_|_]
 703    ->  write(Out, ','),
 704        nlindent(Out, EIndent),
 705        portray_list_elements(T, EIndent, Out, Options)
 706    ;   Indent is EIndent - 2,
 707        nlindent(Out, Indent),
 708        write(Out, '| '),
 709        pprint(Out, T, 999, Options)
 710    ).
 711
 712%!  pprint(+Out, +Term, +Priority, +Options)
 713%
 714%   Print  Term  at  Priority.  This  also  takes  care  of  several
 715%   formatting options, in particular:
 716%
 717%     * {}(Arg) terms are printed with aligned arguments, assuming
 718%     that the term is a body-term.
 719%     * Terms that do not fit on the line are wrapped using
 720%     pprint_wrapped/3.
 721%
 722%   @tbd    Decide when and how to wrap long terms.
 723
 724pprint(Out, Term, _, Options) :-
 725    nonvar(Term),
 726    Term = {}(Arg),
 727    line_position(Out, Indent),
 728    ArgIndent is Indent + 2,
 729    format(Out, '{ ', []),
 730    portray_body(Arg, ArgIndent, noident, 1000, Out, Options),
 731    nlindent(Out, Indent),
 732    format(Out, '}', []).
 733pprint(Out, Term, Pri, Options) :-
 734    (   compound(Term)
 735    ->  compound_name_arity(Term, _, Arity),
 736        Arity > 0
 737    ;   is_dict(Term)
 738    ),
 739    \+ nowrap_term(Term),
 740    setting(listing:line_width, Width),
 741    Width > 0,
 742    (   write_length(Term, Len, [max_length(Width)|Options])
 743    ->  true
 744    ;   Len = Width
 745    ),
 746    line_position(Out, Indent),
 747    Indent + Len > Width,
 748    Len > Width/4,                 % ad-hoc rule for deeply nested goals
 749    !,
 750    pprint_wrapped(Out, Term, Pri, Options).
 751pprint(Out, Term, Pri, Options) :-
 752    listing_write_options(Pri, WrtOptions, Options),
 753    write_term(Out, Term, WrtOptions).
 754
 755nowrap_term('$VAR'(_)) :- !.
 756nowrap_term(_{}) :- !.                  % empty dict
 757nowrap_term(Term) :-
 758    functor(Term, Name, Arity),
 759    current_op(_, _, Name),
 760    (   Arity == 2
 761    ->  infix_op(Name, _, _)
 762    ;   Arity == 1
 763    ->  (   prefix_op(Name, _)
 764        ->  true
 765        ;   postfix_op(Name, _)
 766        )
 767    ).
 768
 769
 770pprint_wrapped(Out, Term, _, Options) :-
 771    Term = [_|_],
 772    !,
 773    line_position(Out, Indent),
 774    portray_list(Term, Indent, Out, Options).
 775pprint_wrapped(Out, Dict, _, Options) :-
 776    is_dict(Dict),
 777    !,
 778    dict_pairs(Dict, Tag, Pairs),
 779    pprint(Out, Tag, 1200, Options),
 780    format(Out, '{ ', []),
 781    line_position(Out, Indent),
 782    pprint_nv(Pairs, Indent, Out, Options),
 783    nlindent(Out, Indent-2),
 784    format(Out, '}', []).
 785pprint_wrapped(Out, Term, _, Options) :-
 786    Term =.. [Name|Args],
 787    format(Out, '~q(', Name),
 788    line_position(Out, Indent),
 789    pprint_args(Args, Indent, Out, Options),
 790    format(Out, ')', []).
 791
 792pprint_args([], _, _, _).
 793pprint_args([H|T], Indent, Out, Options) :-
 794    pprint(Out, H, 999, Options),
 795    (   T == []
 796    ->  true
 797    ;   format(Out, ',', []),
 798        nlindent(Out, Indent),
 799        pprint_args(T, Indent, Out, Options)
 800    ).
 801
 802
 803pprint_nv([], _, _, _).
 804pprint_nv([Name-Value|T], Indent, Out, Options) :-
 805    pprint(Out, Name, 999, Options),
 806    format(Out, ':', []),
 807    pprint(Out, Value, 999, Options),
 808    (   T == []
 809    ->  true
 810    ;   format(Out, ',', []),
 811        nlindent(Out, Indent),
 812        pprint_nv(T, Indent, Out, Options)
 813    ).
 814
 815
 816%!  listing_write_options(+Priority, -WriteOptions) is det.
 817%
 818%   WriteOptions are write_term/3 options for writing a term at
 819%   priority Priority.
 820
 821listing_write_options(Pri,
 822                      [ quoted(true),
 823                        numbervars(true),
 824                        priority(Pri),
 825                        spacing(next_argument)
 826                      | Options
 827                      ],
 828                      Options).
 829
 830%!  nlindent(+Out, +Indent)
 831%
 832%   Write newline and indent to  column   Indent.  Uses  the setting
 833%   listing:tab_distance to determine the mapping   between tabs and
 834%   spaces.
 835
 836nlindent(Out, N) :-
 837    nl(Out),
 838    setting(listing:tab_distance, D),
 839    (   D =:= 0
 840    ->  tab(Out, N)
 841    ;   Tab is N // D,
 842        Space is N mod D,
 843        put_tabs(Out, Tab),
 844        tab(Out, Space)
 845    ).
 846
 847put_tabs(Out, N) :-
 848    N > 0,
 849    !,
 850    put(Out, 0'\t),
 851    NN is N - 1,
 852    put_tabs(Out, NN).
 853put_tabs(_, _).
 854
 855
 856%!  inc_indent(+Indent0, +Inc, -Indent)
 857%
 858%   Increment the indent with logical steps.
 859
 860inc_indent(Indent0, Inc, Indent) :-
 861    Indent is Indent0 + Inc*4.
 862
 863:- multifile
 864    sandbox:safe_meta/2.
 865
 866sandbox:safe_meta(listing(What), []) :-
 867    not_qualified(What).
 868
 869not_qualified(Var) :-
 870    var(Var),
 871    !.
 872not_qualified(_:_) :- !, fail.
 873not_qualified(_).