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)  2011-2016, VU University Amsterdam
   7    All rights reserved.
   8
   9    Redistribution and use in source and binary forms, with or without
  10    modification, are permitted provided that the following conditions
  11    are met:
  12
  13    1. Redistributions of source code must retain the above copyright
  14       notice, this list of conditions and the following disclaimer.
  15
  16    2. Redistributions in binary form must reproduce the above copyright
  17       notice, this list of conditions and the following disclaimer in
  18       the documentation and/or other materials provided with the
  19       distribution.
  20
  21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  28    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  29    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32    POSSIBILITY OF SUCH DAMAGE.
  33*/
  34
  35:- module(predicate_options,
  36          [ predicate_options/3,                % +PI, +Arg, +Options
  37            assert_predicate_options/4,         % +PI, +Arg, +Options, ?New
  38
  39            current_option_arg/2,               % ?PI, ?Arg
  40            current_predicate_option/3,         % ?PI, ?Arg, ?Option
  41            check_predicate_option/3,           % +PI, +Arg, +Option
  42                                                % Create declarations
  43            current_predicate_options/3,        % ?PI, ?Arg, ?Options
  44            retractall_predicate_options/0,
  45            derived_predicate_options/3,        % :PI, ?Arg, ?Options
  46            derived_predicate_options/1,        % +Module
  47                                                % Checking
  48            check_predicate_options/0,
  49            derive_predicate_options/0,
  50            check_predicate_options/1           % :PredicateIndicator
  51          ]).
  52:- use_module(library(lists)).
  53:- use_module(library(pairs)).
  54:- use_module(library(error)).
  55:- use_module(library(lists)).
  56:- use_module(library(debug)).
  57:- use_module(library(prolog_clause)).
  58
  59:- meta_predicate
  60    predicate_options(:, +, +),
  61    assert_predicate_options(:, +, +, ?),
  62    current_predicate_option(:, ?, ?),
  63    check_predicate_option(:, ?, ?),
  64    current_predicate_options(:, ?, ?),
  65    current_option_arg(:, ?),
  66    pred_option(:,-),
  67    derived_predicate_options(:,?,?),
  68    check_predicate_options(:).
  69
  70/** <module> Access and analyse predicate options
  71
  72This  module  provides  the  developers   interface  for  the  directive
  73predicate_options/3. This directive allows  us  to  specify  that, e.g.,
  74open/4 processes options using the 4th  argument and supports the option
  75=type= using the values =text= and  =binary=. Declaring options that are
  76processed allows for more reliable  handling   of  predicate options and
  77simplifies porting applications. This  library   provides  the following
  78functionality:
  79
  80  * Query supported options through current_predicate_option/3
  81    or current_predicate_options/3.  This is intended to support
  82    conditional compilation and an IDE.
  83  * Derive additional declarations through dataflow analysis using
  84    derive_predicate_options/0.
  85  * Perform a compile-time analysis of the entire loaded program using
  86    check_predicate_options/0.
  87
  88Below, we describe some use-cases.
  89
  90  $ Quick check of a program :
  91  This scenario is useful as an occasional check or to assess problems
  92  with option-handling for porting an application to SWI-Prolog.  It
  93  consists of three steps: loading the program (1 and 2), deriving
  94  option handling for application predicates (3) and running the
  95  checker (4).
  96
  97    ==
  98    1 ?- [load].
  99    2 ?- autoload.
 100    3 ?- derive_predicate_options.
 101    4 ?- check_predicate_options.
 102    ==
 103
 104  $ Add declarations to your program :
 105  Adding declarations about option processes improves the quality of
 106  the checking.  The analysis of derive_predicate_options/0 may miss
 107  options and does not derive the types for options that are processed
 108  in Prolog code.  The process is similar to the above.  In steps 4 and
 109  further, the inferred declarations are listed, inspected and added to
 110  the source code of the module.
 111
 112    ==
 113    1 ?- [load].
 114    2 ?- autoload.
 115    3 ?- derive_predicate_options.
 116    4 ?- derived_predicate_options(module_1).
 117    5 ?- derived_predicate_options(module_2).
 118    6 ?- ...
 119    ==
 120
 121  $ Declare option processing requirements :
 122  If an application requires that open/4 needs to support lock(write),
 123  it may do so using the directive below.  This directive raises an
 124  exception when loaded on a Prolog implementation that does not support
 125  this option.
 126
 127    ==
 128    :- current_predicate_option(open/4, 4, lock(write)).
 129    ==
 130
 131@see library(option) for accessing options in Prolog code.
 132*/
 133
 134:- multifile option_decl/3, pred_option/3.
 135:- dynamic   dyn_option_decl/3.
 136
 137%!  predicate_options(:PI, +Arg, +Options) is det.
 138%
 139%   Declare that the predicate PI processes options on Arg.  Options
 140%   is a list of options processed.  Each element is one of:
 141%
 142%     * Option(ModeAndType)
 143%     PI processes Option. The option-value must comply to
 144%     ModeAndType.  Mode is one of + or - and Type is a type as
 145%     accepted by must_be/2.
 146%
 147%     * pass_to(:PI,Arg)
 148%     The option-list is passed to the indicated predicate.
 149%
 150%   Below is an example that   processes  the option header(boolean)
 151%   and passes all options to open/4:
 152%
 153%     ==
 154%     :- predicate_options(write_xml_file/3, 3,
 155%                          [ header(boolean),
 156%                            pass_to(open/4, 4)
 157%                          ]).
 158%
 159%     write_xml_file(File, XMLTerm, Options) :-
 160%         open(File, write, Out, Options),
 161%         (   option(header(true), Option, true)
 162%         ->  write_xml_header(Out)
 163%         ;   true
 164%         ),
 165%         ...
 166%     ==
 167%
 168%   This predicate may  only  be  used   as  a  _directive_  and  is
 169%   processed  by  expand_term/2.  Option  processing    can  be
 170%   specified at runtime using  assert_predicate_options/3, which is
 171%   intended to support program analysis.
 172
 173predicate_options(PI, Arg, Options) :-
 174    throw(error(context_error(nodirective,
 175                              predicate_options(PI, Arg, Options)), _)).
 176
 177
 178%!  assert_predicate_options(:PI, +Arg, +Options, ?New) is semidet.
 179%
 180%   As predicate_options(:PI, +Arg, +Options).  New   is  a  boolean
 181%   indicating whether the declarations  have   changed.  If  New is
 182%   provided and =false=, the predicate   becomes  semidet and fails
 183%   without modifications if modifications are required.
 184
 185assert_predicate_options(PI, Arg, Options, New) :-
 186    canonical_pi(PI, M:Name/Arity),
 187    functor(Head, Name, Arity),
 188    (   dyn_option_decl(Head, M, Arg)
 189    ->  true
 190    ;   New = true,
 191        assertz(dyn_option_decl(Head, M, Arg))
 192    ),
 193    phrase('$predopts':option_clauses(Options, Head, M, Arg),
 194           OptionClauses),
 195    forall(member(Clause, OptionClauses),
 196           assert_option_clause(Clause, New)),
 197    (   var(New)
 198    ->  New = false
 199    ;   true
 200    ).
 201
 202assert_option_clause(Clause, New) :-
 203    rename_clause(Clause, NewClause,
 204                  '$pred_option'(A,B,C,D), '$dyn_pred_option'(A,B,C,D)),
 205    clause_head(NewClause, NewHead),
 206    (   clause(NewHead, _)
 207    ->  true
 208    ;   New = true,
 209        assertz(NewClause)
 210    ).
 211
 212clause_head(M:(Head:-_Body), M:Head) :- !.
 213clause_head((M:Head :-_Body), M:Head) :- !.
 214clause_head(Head, Head).
 215
 216rename_clause(M:Clause, M:NewClause, Head, NewHead) :-
 217    !,
 218    rename_clause(Clause, NewClause, Head, NewHead).
 219rename_clause((Head :- Body), (NewHead :- Body), Head, NewHead) :- !.
 220rename_clause(Head, NewHead, Head, NewHead) :- !.
 221rename_clause(Head, Head, _, _).
 222
 223
 224
 225                 /*******************************
 226                 *        QUERY OPTIONS         *
 227                 *******************************/
 228
 229%!  current_option_arg(:PI, ?Arg) is nondet.
 230%
 231%   True when Arg of PI processes   predicate options. Which options
 232%   are processed can be accessed using current_predicate_option/3.
 233
 234current_option_arg(Module:Name/Arity, Arg) :-
 235    current_option_arg(Module:Name/Arity, Arg, _DefM).
 236
 237current_option_arg(Module:Name/Arity, Arg, DefM) :-
 238    atom(Name), integer(Arity),
 239    !,
 240    resolve_module(Module:Name/Arity, DefM:Name/Arity),
 241    functor(Head, Name, Arity),
 242    (   option_decl(Head, DefM, Arg)
 243    ;   dyn_option_decl(Head, DefM, Arg)
 244    ).
 245current_option_arg(M:Name/Arity, Arg, M) :-
 246    (   option_decl(Head, M, Arg)
 247    ;   dyn_option_decl(Head, M, Arg)
 248    ),
 249    functor(Head, Name, Arity).
 250
 251%!  current_predicate_option(:PI, ?Arg, ?Option) is nondet.
 252%
 253%   True when Arg of PI processes Option. For example, the following
 254%   is true:
 255%
 256%     ==
 257%     ?- current_predicate_option(open/4, 4, type(text)).
 258%     true.
 259%     ==
 260%
 261%   This predicate is intended to   support  conditional compilation
 262%   using      if/1      ...      endif/0.        The      predicate
 263%   current_predicate_options/3 can be  used  to   access  the  full
 264%   capabilities of a predicate.
 265
 266current_predicate_option(Module:PI, Arg, Option) :-
 267    current_option_arg(Module:PI, Arg, DefM),
 268    PI = Name/Arity,
 269    functor(Head, Name, Arity),
 270    catch(pred_option(DefM:Head, Option),
 271          error(type_error(_,_),_),
 272          fail).
 273
 274%!  check_predicate_option(:PI, +Arg, +Option) is det.
 275%
 276%   Verify   predicate   options    at     runtime.    Similar    to
 277%   current_predicate_option/3,  but  intended  to  support  runtime
 278%   checking.
 279%
 280%   @error  existence_error(option, OptionName) if the option is not
 281%           supported by PI.
 282%   @error  type_error(Type, Value) if the option is supported but
 283%           the value does not match the option type. See must_be/2.
 284
 285check_predicate_option(Module:PI, Arg, Option) :-
 286    define_predicate(Module:PI),
 287    current_option_arg(Module:PI, Arg, DefM),
 288    PI = Name/Arity,
 289    functor(Head, Name, Arity),
 290    (   pred_option(DefM:Head, Option)
 291    ->  true
 292    ;   existence_error(option, Option)
 293    ).
 294
 295
 296pred_option(M:Head, Option) :-
 297    pred_option(M:Head, Option, []).
 298
 299pred_option(M:Head, Option, Seen) :-
 300    (   has_static_option_decl(M),
 301        M:'$pred_option'(Head, _, Option, Seen)
 302    ;   has_dynamic_option_decl(M),
 303        M:'$dyn_pred_option'(Head, _, Option, Seen)
 304    ).
 305
 306has_static_option_decl(M) :-
 307    '$c_current_predicate'(_, M:'$pred_option'(_,_,_,_)).
 308has_dynamic_option_decl(M) :-
 309    '$c_current_predicate'(_, M:'$dyn_pred_option'(_,_,_,_)).
 310
 311
 312                 /*******************************
 313                 *     TYPE&MODE CONSTRAINTS    *
 314                 *******************************/
 315
 316:- public
 317    system:predicate_option_mode/2,
 318    system:predicate_option_type/2.
 319
 320add_attr(Var, Value) :-
 321    (   get_attr(Var, predicate_options, Old)
 322    ->  put_attr(Var, predicate_options, [Value|Old])
 323    ;   put_attr(Var, predicate_options, [Value])
 324    ).
 325
 326system:predicate_option_type(Type, Arg) :-
 327    var(Arg),
 328    !,
 329    add_attr(Arg, option_type(Type)).
 330system:predicate_option_type(Type, Arg) :-
 331    must_be(Type, Arg).
 332
 333system:predicate_option_mode(Mode, Arg) :-
 334    var(Arg),
 335    !,
 336    add_attr(Arg, option_mode(Mode)).
 337system:predicate_option_mode(Mode, Arg) :-
 338    check_mode(Mode, Arg).
 339
 340check_mode(input, Arg) :-
 341    (   nonvar(Arg)
 342    ->  true
 343    ;   instantiation_error(Arg)
 344    ).
 345check_mode(output, Arg) :-
 346    (   var(Arg)
 347    ->  true
 348    ;   uninstantiation_error(Arg)
 349    ).
 350
 351attr_unify_hook([], _).
 352attr_unify_hook([H|T], Var) :-
 353    option_hook(H, Var),
 354    attr_unify_hook(T, Var).
 355
 356option_hook(option_type(Type), Value) :-
 357    is_of_type(Type, Value).
 358option_hook(option_mode(Mode), Value) :-
 359    check_mode(Mode, Value).
 360
 361
 362attribute_goals(Var) -->
 363    { get_attr(Var, predicate_options, Attrs) },
 364    option_goals(Attrs, Var).
 365
 366option_goals([], _) --> [].
 367option_goals([H|T], Var) -->
 368    option_goal(H, Var),
 369    option_goals(T, Var).
 370
 371option_goal(option_type(Type), Var) --> [predicate_option_type(Type, Var)].
 372option_goal(option_mode(Mode), Var) --> [predicate_option_mode(Mode, Var)].
 373
 374
 375                 /*******************************
 376                 *      OUTPUT DECLARATIONS     *
 377                 *******************************/
 378
 379%!  current_predicate_options(:PI, ?Arg, ?Options) is nondet.
 380%
 381%   True when Options is the current   active option declaration for
 382%   PI  on  Arg.   See   predicate_options/3    for   the   argument
 383%   descriptions. If PI  is  ground  and   refers  to  an  undefined
 384%   predicate, the autoloader is used to  obtain a definition of the
 385%   predicate.
 386
 387current_predicate_options(PI, Arg, Options) :-
 388    define_predicate(PI),
 389    setof(Arg-Option,
 390          current_predicate_option_decl(PI, Arg, Option),
 391          Options0),
 392    group_pairs_by_key(Options0, Grouped),
 393    member(Arg-Options, Grouped).
 394
 395current_predicate_option_decl(PI, Arg, Option) :-
 396    current_predicate_option(PI, Arg, Option0),
 397    Option0 =.. [Name|Values],
 398    maplist(mode_and_type, Values, Types),
 399    Option =.. [Name|Types].
 400
 401mode_and_type(Value, ModeAndType) :-
 402    copy_term(Value,_,Goals),
 403    (   memberchk(predicate_option_mode(output, _), Goals)
 404    ->  ModeAndType = -(Type)
 405    ;   ModeAndType = Type
 406    ),
 407    (   memberchk(predicate_option_type(Type, _), Goals)
 408    ->  true
 409    ;   Type = any
 410    ).
 411
 412define_predicate(PI) :-
 413    ground(PI),
 414    !,
 415    PI = M:Name/Arity,
 416    functor(Head, Name, Arity),
 417    once(predicate_property(M:Head, _)).
 418define_predicate(_).
 419
 420%!  derived_predicate_options(:PI, ?Arg, ?Options) is nondet.
 421%
 422%   Derive option arguments using static analysis. True when Options
 423%   is the current _derived_ active  option   declaration  for PI on
 424%   Arg.
 425
 426derived_predicate_options(PI, Arg, Options) :-
 427    define_predicate(PI),
 428    setof(Arg-Option,
 429          derived_predicate_option(PI, Arg, Option),
 430          Options0),
 431    group_pairs_by_key(Options0, Grouped),
 432    member(Arg-Options1, Grouped),
 433    PI = M:_,
 434    phrase(expand_pass_to_options(Options1, M), Options2),
 435    sort(Options2, Options).
 436
 437derived_predicate_option(PI, Arg, Decl) :-
 438    current_option_arg(PI, Arg, DefM),
 439    PI = _:Name/Arity,
 440    functor(Head, Name, Arity),
 441    has_dynamic_option_decl(DefM),
 442    (   has_static_option_decl(DefM),
 443        DefM:'$pred_option'(Head, Decl, _, [])
 444    ;   DefM:'$dyn_pred_option'(Head, Decl, _, [])
 445    ).
 446
 447%!  expand_pass_to_options(+OptionsIn, +Module, -OptionsOut)// is det.
 448%
 449%   Expand the options of pass_to(PI,Arg) if PI  does not refer to a
 450%   public predicate.
 451
 452expand_pass_to_options([], _) --> [].
 453expand_pass_to_options([H|T], M) -->
 454    expand_pass_to(H, M),
 455    expand_pass_to_options(T, M).
 456
 457expand_pass_to(pass_to(PI, Arg), Module) -->
 458    { strip_module(Module:PI, M, Name/Arity),
 459      functor(Head, Name, Arity),
 460      \+ (   predicate_property(M:Head, exported)
 461         ;   predicate_property(M:Head, public)
 462         ;   M == system
 463         ),
 464      !,
 465      current_predicate_options(M:Name/Arity, Arg, Options)
 466    },
 467    list(Options).
 468expand_pass_to(Option, _) -->
 469    [Option].
 470
 471list([]) --> [].
 472list([H|T]) --> [H], list(T).
 473
 474%!  derived_predicate_options(+Module) is det.
 475%
 476%   Derive predicate option declarations for   a module. The derived
 477%   options are printed to the =current_output= stream.
 478
 479derived_predicate_options(Module) :-
 480    var(Module),
 481    !,
 482    forall(current_module(Module),
 483           derived_predicate_options(Module)).
 484derived_predicate_options(Module) :-
 485    findall(predicate_options(Module:PI, Arg, Options),
 486            ( derived_predicate_options(Module:PI, Arg, Options),
 487              PI = Name/Arity,
 488              functor(Head, Name, Arity),
 489              (   predicate_property(Module:Head, exported)
 490              ->  true
 491              ;   predicate_property(Module:Head, public)
 492              )
 493            ),
 494            Decls0),
 495    maplist(qualify_decl(Module), Decls0, Decls1),
 496    sort(Decls1, Decls),
 497    (   Decls \== []
 498    ->  format('~N~n~n% Predicate option declarations for module ~q~n~n',
 499               [Module]),
 500        forall(member(Decl, Decls),
 501               portray_clause((:-Decl)))
 502    ;   true
 503    ).
 504
 505qualify_decl(M,
 506             predicate_options(PI0, Arg, Options0),
 507             predicate_options(PI1, Arg, Options1)) :-
 508    qualify(PI0, M, PI1),
 509    maplist(qualify_option(M), Options0, Options1).
 510
 511qualify_option(M, pass_to(PI0, Arg), pass_to(PI1, Arg)) :-
 512    !,
 513    qualify(PI0, M, PI1).
 514qualify_option(_, Opt, Opt).
 515
 516qualify(M:Term, M, Term) :- !.
 517qualify(QTerm, _, QTerm).
 518
 519
 520                 /*******************************
 521                 *            CLEANUP           *
 522                 *******************************/
 523
 524%!  retractall_predicate_options is det.
 525%
 526%   Remove all dynamically (derived) predicate options.
 527
 528retractall_predicate_options :-
 529    forall(retract(dyn_option_decl(_,M,_)),
 530           abolish(M:'$dyn_pred_option'/4)).
 531
 532
 533                 /*******************************
 534                 *     COMPILE-TIME CHECKER     *
 535                 *******************************/
 536
 537
 538:- thread_local
 539    new_decl/1.
 540
 541%!  check_predicate_options is det.
 542%
 543%   Analyse loaded program for  erroneous   options.  This predicate
 544%   decompiles  the  current  program  and  searches  for  calls  to
 545%   predicates that process  options.  For   each  option  list,  it
 546%   validates  whether  the  provided  options   are  supported  and
 547%   validates the argument type.  This   predicate  performs partial
 548%   dataflow analysis to track option-lists inside a clause.
 549%
 550%   @see    derive_predicate_options/0 can be used to derive
 551%           declarations for predicates that pass options. This
 552%           predicate should normally be called before
 553%           check_predicate_options/0.
 554
 555check_predicate_options :-
 556    forall(current_module(Module),
 557           check_predicate_options_module(Module)).
 558
 559%!  derive_predicate_options is det.
 560%
 561%   Derive  new  predicate  option    declarations.  This  predicate
 562%   analyses the loaded program to find clauses that process options
 563%   using one of  the  predicates   from  library(option)  or passes
 564%   options to other predicates that are   known to process options.
 565%   The process is repeated until no new declarations are retrieved.
 566%
 567%   @see autoload/0 may be used to complete the loaded program.
 568
 569derive_predicate_options :-
 570    derive_predicate_options(NewDecls),
 571    (   NewDecls == []
 572    ->  true
 573    ;   print_message(informational, check_options(new(NewDecls))),
 574        new_decls(NewDecls),
 575        derive_predicate_options
 576    ).
 577
 578new_decls([]).
 579new_decls([predicate_options(PI, A, O)|T]) :-
 580    assert_predicate_options(PI, A, O, _),
 581    new_decls(T).
 582
 583
 584derive_predicate_options(NewDecls) :-
 585    call_cleanup(
 586        ( forall(
 587              current_module(Module),
 588              forall(
 589                  ( predicate_in_module(Module, PI),
 590                    PI = Name/Arity,
 591                    functor(Head, Name, Arity),
 592                    catch(Module:clause(Head, Body, Ref), _, fail)
 593                  ),
 594                  check_clause((Head:-Body), Module, Ref, decl))),
 595          (   setof(Decl, retract(new_decl(Decl)), NewDecls)
 596              ->  true
 597              ;   NewDecls = []
 598          )
 599        ),
 600        retractall(new_decl(_))).
 601
 602
 603check_predicate_options_module(Module) :-
 604    forall(predicate_in_module(Module, PI),
 605           check_predicate_options(Module:PI)).
 606
 607predicate_in_module(Module, PI) :-
 608    current_predicate(Module:PI),
 609    PI = Name/Arity,
 610    functor(Head, Name, Arity),
 611    \+ predicate_property(Module:Head, imported_from(_)).
 612
 613%!  check_predicate_options(:PredicateIndicator) is det.
 614%
 615%   Verify calls to predicates that have   options in all clauses of
 616%   the predicate indicated by PredicateIndicator.
 617
 618check_predicate_options(Module:Name/Arity) :-
 619    debug(predicate_options, 'Checking ~q', [Module:Name/Arity]),
 620    functor(Head, Name, Arity),
 621    forall(catch(Module:clause(Head, Body, Ref), _, fail),
 622           check_clause((Head:-Body), Module, Ref, check)).
 623
 624%!  check_clause(+Clause, +Module, +Ref, +Action) is det.
 625%
 626%   Action is one of
 627%
 628%     * decl
 629%     Create additional declarations
 630%     * check
 631%     Produce error messages
 632
 633check_clause((Head:-Body), M, ClauseRef, Action) :-
 634    !,
 635    catch(check_body(Body, M, _, Action), E, true),
 636    (   var(E)
 637    ->  option_decl(M:Head, Action)
 638    ;   (   clause_info(ClauseRef, File, TermPos, _NameOffset),
 639            TermPos = term_position(_,_,_,_,[_,BodyPos]),
 640            catch(check_body(Body, M, BodyPos, Action),
 641                  error(Formal, ArgPos), true),
 642            compound(ArgPos),
 643            arg(1, ArgPos, CharCount),
 644            integer(CharCount)
 645        ->  Location = file_char_count(File, CharCount)
 646        ;   Location = clause(ClauseRef),
 647            E = error(Formal, _)
 648        ),
 649        print_message(error, predicate_option_error(Formal, Location))
 650    ).
 651
 652
 653%!  check_body(+Body, +Module, +TermPos, +Action)
 654
 655:- multifile
 656    prolog:called_by/4,             % +Goal, +Module, +Context, -Called
 657    prolog:called_by/2.             % +Goal, -Called
 658
 659check_body(Var, _, _, _) :-
 660    var(Var),
 661    !.
 662check_body(M:G, _, term_position(_,_,_,_,[_,Pos]), Action) :-
 663    !,
 664    check_body(G, M, Pos, Action).
 665check_body((A,B), M, term_position(_,_,_,_,[PA,PB]), Action) :-
 666    !,
 667    check_body(A, M, PA, Action),
 668    check_body(B, M, PB, Action).
 669check_body(A=B, _, _, _) :-             % partial evaluation
 670    unify_with_occurs_check(A,B),
 671    !.
 672check_body(Goal, M, term_position(_,_,_,_,ArgPosList), Action) :-
 673    callable(Goal),
 674    functor(Goal, Name, Arity),
 675    (   '$get_predicate_attribute'(M:Goal, imported, DefM)
 676    ->  true
 677    ;   DefM = M
 678    ),
 679    (   eval_option_pred(DefM:Goal)
 680    ->  true
 681    ;   current_option_arg(DefM:Name/Arity, OptArg),
 682        !,
 683        arg(OptArg, Goal, Options),
 684        nth1(OptArg, ArgPosList, ArgPos),
 685        check_options(DefM:Name/Arity, OptArg, Options, ArgPos, Action)
 686    ).
 687check_body(Goal, M, _, Action) :-
 688    (   (   predicate_property(M:Goal, imported_from(IM))
 689        ->  true
 690        ;   IM = M
 691        ),
 692        prolog:called_by(Goal, IM, M, Called)
 693    ;   prolog:called_by(Goal, Called)
 694    ),
 695    !,
 696    check_called_by(Called, M, Action).
 697check_body(Meta, M, term_position(_,_,_,_,ArgPosList), Action) :-
 698    '$get_predicate_attribute'(M:Meta, meta_predicate, Head),
 699    !,
 700    check_meta_args(1, Head, Meta, M, ArgPosList, Action).
 701check_body(_, _, _, _).
 702
 703check_meta_args(I, Head, Meta, M, [ArgPos|ArgPosList], Action) :-
 704    arg(I, Head, AS),
 705    !,
 706    (   AS == 0
 707    ->  arg(I, Meta, MA),
 708        check_body(MA, M, ArgPos, Action)
 709    ;   true
 710    ),
 711    succ(I, I2),
 712    check_meta_args(I2, Head, Meta, M, ArgPosList, Action).
 713check_meta_args(_,_,_,_, _, _).
 714
 715%!  check_called_by(+CalledBy, +M, +Action) is det.
 716%
 717%   Handle results from prolog:called_by/2.
 718
 719check_called_by([], _, _).
 720check_called_by([H|T], M, Action) :-
 721    (   H = G+N
 722    ->  (   extend(G, N, G2)
 723        ->  check_body(G2, M, _, Action)
 724        ;   true
 725        )
 726    ;   check_body(H, M, _, Action)
 727    ),
 728    check_called_by(T, M, Action).
 729
 730extend(Goal, N, GoalEx) :-
 731    callable(Goal),
 732    Goal =.. List,
 733    length(Extra, N),
 734    append(List, Extra, ListEx),
 735    GoalEx =.. ListEx.
 736
 737
 738%!  check_options(:Predicate, +OptionArg, +Options, +ArgPos, +Action)
 739%
 740%   Verify the list Options,  that  is   passed  into  Predicate  on
 741%   argument OptionArg. ArgPos is a   term-position  term describing
 742%   the location of the Options list. If  Options is a partial list,
 743%   the tail is annotated with pass_to(PI, OptArg).
 744
 745check_options(PI, OptArg, QOptions, ArgPos, Action) :-
 746    debug(predicate_options, '\tChecking call to ~q', [PI]),
 747    remove_qualifier(QOptions, Options),
 748    must_be(list_or_partial_list, Options),
 749    check_option_list(Options, PI, OptArg, Options, ArgPos, Action).
 750
 751remove_qualifier(X, X) :-
 752    var(X),
 753    !.
 754remove_qualifier(_:X, X) :- !.
 755remove_qualifier(X, X).
 756
 757check_option_list(Var,  PI, OptArg, _, _, _) :-
 758    var(Var),
 759    !,
 760    annotate(Var, pass_to(PI, OptArg)).
 761check_option_list([], _, _, _, _, _).
 762check_option_list([H|T], PI, OptArg, Options, ArgPos, Action) :-
 763    check_option(PI, OptArg, H, ArgPos, Action),
 764    check_option_list(T, PI, OptArg, Options, ArgPos, Action).
 765
 766check_option(_, _, _, _, decl) :- !.
 767check_option(PI, OptArg, Opt, ArgPos, _) :-
 768    catch(check_predicate_option(PI, OptArg, Opt), E, true),
 769    !,
 770    (   var(E)
 771    ->  true
 772    ;   E = error(Formal,_),
 773        throw(error(Formal,ArgPos))
 774    ).
 775
 776
 777                 /*******************************
 778                 *          ANNOTATIONS         *
 779                 *******************************/
 780
 781%!  annotate(+Var, +Term) is det.
 782%
 783%   Use constraints to accumulate annotations   about  variables. If
 784%   two annotated variables are unified, the attributes are joined.
 785
 786annotate(Var, Term) :-
 787    (   get_attr(Var, predopts_analysis, Old)
 788    ->  put_attr(Var, predopts_analysis, [Term|Old])
 789    ;   var(Var)
 790    ->  put_attr(Var, predopts_analysis, [Term])
 791    ;   true
 792    ).
 793
 794annotations(Var, Annotations) :-
 795    get_attr(Var, predopts_analysis, Annotations).
 796
 797predopts_analysis:attr_unify_hook(Opts, Value) :-
 798    get_attr(Value, predopts_analysis, Others),
 799    !,
 800    append(Opts, Others, All),
 801    put_attr(Value, predopts_analysis, All).
 802predopts_analysis:attr_unify_hook(_, _).
 803
 804
 805                 /*******************************
 806                 *         PARTIAL EVAL         *
 807                 *******************************/
 808
 809eval_option_pred(swi_option:option(Opt, Options)) :-
 810    processes(Opt, Spec),
 811    annotate(Options, Spec).
 812eval_option_pred(swi_option:option(Opt, Options, _Default)) :-
 813    processes(Opt, Spec),
 814    annotate(Options, Spec).
 815eval_option_pred(swi_option:select_option(Opt, Options, Rest)) :-
 816    ignore(unify_with_occurs_check(Rest, Options)),
 817    processes(Opt, Spec),
 818    annotate(Options, Spec).
 819eval_option_pred(swi_option:select_option(Opt, Options, Rest, _Default)) :-
 820    ignore(unify_with_occurs_check(Rest, Options)),
 821    processes(Opt, Spec),
 822    annotate(Options, Spec).
 823eval_option_pred(swi_option:meta_options(_Cond, QOptionsIn, QOptionsOut)) :-
 824    remove_qualifier(QOptionsIn, OptionsIn),
 825    remove_qualifier(QOptionsOut, OptionsOut),
 826    ignore(unify_with_occurs_check(OptionsIn, OptionsOut)).
 827
 828processes(Opt, Spec) :-
 829    compound(Opt),
 830    functor(Opt, OptName, 1),
 831    Spec =.. [OptName,any].
 832
 833
 834                 /*******************************
 835                 *        NEW DECLARTIONS       *
 836                 *******************************/
 837
 838%!  option_decl(:Head, +Action) is det.
 839%
 840%   Add new declarations based on attributes   left  by the analysis
 841%   pass. We do not add declarations   for system modules or modules
 842%   that already contain static declarations.
 843%
 844%   @tbd    Should we add a mode to include generating declarations
 845%           for system modules and modules with static declarations?
 846
 847option_decl(_, check) :- !.
 848option_decl(M:_, _) :-
 849    system_module(M),
 850    !.
 851option_decl(M:_, _) :-
 852    has_static_option_decl(M),
 853    !.
 854option_decl(M:Head, _) :-
 855    compound(Head),
 856    arg(AP, Head, QA),
 857    remove_qualifier(QA, A),
 858    annotations(A, Annotations0),
 859    functor(Head, Name, Arity),
 860    PI = M:Name/Arity,
 861    delete(Annotations0, pass_to(PI,AP), Annotations),
 862    Annotations \== [],
 863    Decl = predicate_options(PI, AP, Annotations),
 864    (   new_decl(Decl)
 865    ->  true
 866    ;   assert_predicate_options(M:Name/Arity, AP, Annotations, false)
 867    ->  true
 868    ;   assertz(new_decl(Decl)),
 869        debug(predicate_options(decl), '~q', [Decl])
 870    ),
 871    fail.
 872option_decl(_, _).
 873
 874system_module(system) :- !.
 875system_module(Module) :-
 876    sub_atom(Module, 0, _, _, $).
 877
 878
 879                 /*******************************
 880                 *             MISC             *
 881                 *******************************/
 882
 883canonical_pi(M:Name//Arity, M:Name/PArity) :-
 884    integer(Arity),
 885    PArity is Arity+2.
 886canonical_pi(PI, PI).
 887
 888%!  resolve_module(:PI, -DefPI) is det.
 889%
 890%   Find the real predicate  indicator   pointing  to the definition
 891%   module of PI. This is similar to using predicate_property/3 with
 892%   the       property       imported_from,         but        using
 893%   '$get_predicate_attribute'/3    avoids    auto-importing     the
 894%   predicate.
 895
 896resolve_module(Module:Name/Arity, DefM:Name/Arity) :-
 897    functor(Head, Name, Arity),
 898    (   '$get_predicate_attribute'(Module:Head, imported, M)
 899    ->  DefM = M
 900    ;   DefM = Module
 901    ).
 902
 903
 904                 /*******************************
 905                 *            MESSAGES          *
 906                 *******************************/
 907:- multifile
 908    prolog:message//1.
 909
 910prolog:message(predicate_option_error(Formal, Location)) -->
 911    error_location(Location),
 912    '$messages':term_message(Formal). % TBD: clean interface
 913prolog:message(check_options(new(Decls))) -->
 914    [ 'Inferred declarations:'-[], nl ],
 915    new_decls(Decls).
 916
 917error_location(file_char_count(File, CharPos)) -->
 918    { filepos_line(File, CharPos, Line, LinePos) },
 919    [ '~w:~d:~d: '-[File, Line, LinePos] ].
 920error_location(clause(ClauseRef)) -->
 921    { clause_property(ClauseRef, file(File)),
 922      clause_property(ClauseRef, line_count(Line))
 923    },
 924    !,
 925    [ '~w:~d: '-[File, Line] ].
 926error_location(clause(ClauseRef)) -->
 927    [ 'Clause ~q: '-[ClauseRef] ].
 928
 929filepos_line(File, CharPos, Line, LinePos) :-
 930    setup_call_cleanup(
 931        ( open(File, read, In),
 932          open_null_stream(Out)
 933        ),
 934        ( Skip is CharPos-1,
 935          copy_stream_data(In, Out, Skip),
 936          stream_property(In, position(Pos)),
 937          stream_position_data(line_count, Pos, Line),
 938          stream_position_data(line_position, Pos, LinePos)
 939        ),
 940        ( close(Out),
 941          close(In)
 942        )).
 943
 944new_decls([]) --> [].
 945new_decls([H|T]) -->
 946    [ '    :- ~q'-[H], nl ],
 947    new_decls(T).
 948
 949
 950                 /*******************************
 951                 *      SYSTEM DECLARATIONS     *
 952                 *******************************/
 953
 954:- use_module(library(dialect/swi/syspred_options)).