View source with raw comments or as raw
    1/*
    2* Copyright (c) 2016, University of Texas at Dallas
    3* All rights reserved.
    4*
    5* Redistribution and use in source and binary forms, with or without
    6* modification, are permitted provided that the following conditions are met:
    7*     * Redistributions of source code must retain the above copyright
    8*       notice, this list of conditions and the following disclaimer.
    9*     * Redistributions in binary form must reproduce the above copyright
   10*       notice, this list of conditions and the following disclaimer in the
   11*       documentation and/or other materials provided with the distribution.
   12*     * Neither the name of the University of Texas at Dallas nor the
   13*       names of its contributors may be used to endorse or promote products
   14*       derived from this software without specific prior written permission.
   15*
   16* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   17* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   19* DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT DALLAS BE LIABLE FOR
   20* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26*/
   27
   28:- module(scasp_pr_rules,
   29          [ generate_pr_rules/2,        % +Sources, +Options
   30            process_pr_pred/5,          % +Spec, -Atom, -Children, -Cond, -Human
   31            clean_pr_program/1          % +Module
   32          ]).

Output formatting and printing.

Predicates related to formatting and printing output. This includes predicates that may be used for warning and error output.

author
- Kyle Marple
version
- 20170510
license
- BSD-3 */
   44:- use_module(modules).   45:- use_module(common).   46:- use_module(program).   47:- use_module(variables).   48
   49:- autoload(library(option), [option/3]).   50:- autoload(library(apply), [maplist/4, maplist/3, exclude/3, maplist/2]).   51:- autoload(library(lists), [member/2]).   52:- autoload(library(prolog_code), [mkconj/3]).   53:- autoload(library(dcg/basics), [prolog_var_name/3, string/3]).   54:- use_module(library(yall), [(>>)/5]).   55
   56:- op(950, xfx, ::).   57
   58:- meta_predicate
   59    generate_pr_rules(:, +).   60
   61% fail,warning,error
   62:- create_prolog_flag(scasp_unknown, warning, [keep(true)]).
 format_term(+EntryIn:compound, -EntryOut:compound, -Constraints:list, +Vars:compound) is det
Format a term for printing.
Arguments:
EntryIn- The initial entry.
EntryOut- The formatted entry.
Constraints- Any constraints on variables in the entry.
Vars- Variable struct for filling in values.
   74format_term(X, X) :-
   75    is_var(X),				% constrained var
   76    !.
   77format_term(X, Xo) :-
   78    callable(X),
   79    !,
   80    format_predicate2(X, Xo).
   81format_term(X, X).		% anything else, just pass along
 format_term_list(+ListIn:compound, -ListOut:compound) is det
Format each term in a list.
Arguments:
ListIn- The initial list.
ListOut- The formatted list.
   90format_term_list([], []).
   91format_term_list([X|T], [X2|T2]) :-
   92    format_term(X, X2),
   93    format_term_list(T, T2).
 format_predicate2(+EntryIn:compound, -EntryOut:compound) is det
Given a term, remove the arity, strip any prefixes, and process arguments.
Arguments:
EntryIn- The initial entry.
EntryOut- The formatted entry.
  103format_predicate2(Xi, Xo) :-
  104    Xi = [_|_], % list
  105    !,
  106    format_predicate3(Xi, Xo).
  107format_predicate2(Xi, Xo) :-
  108    predicate(Xi, X2, A),
  109    atom(X2), % compound term, predicate or atom
  110    !,
  111    split_functor(X2, X3, _), % strip arity
  112    strip_prefixes(X3, X4),
  113    format_predicate3(A, A2),
  114    (   X4 = not(Xn) % append args
  115    ->  Xn2 =.. [Xn|A2],
  116        Xo = not(Xn2)
  117    ;   Xo =.. [X4|A2]
  118    ).
  119format_predicate2(Xi, Xo) :-
  120    Xi =.. [X2|A], % compound term, but not a predicate or atom head
  121    !,
  122    format_predicate3(A, A2),
  123    Xo =.. [X2|A2].
  124format_predicate2(X, X).
 format_predicate3(+ArgsIn:list, -ArgsOut:list) is det
Process a list of predicate args or variable constraints.
Arguments:
ArgsIn- Input args.
ArgsOut- Output args.
  133format_predicate3([], []) :-
  134    !.
  135format_predicate3([X|T], [Y|T2]) :-
  136    !,
  137    format_predicate4(X, Y),
  138    format_predicate3(T, T2).
  139format_predicate3(X, Y) :-
  140    format_predicate4(X, Y).
 format_predicate4(+ArgsIn:list, -ArgsOut:list) is det
Process a single predicate arg or variable constraint. Where possible, substitute previously used variables for variables with the same value ID. This makes the final output more readable.
Arguments:
ArgIn- Input arg.
ArgOut- Output arg.
  151format_predicate4(X, X) :-
  152    is_var(X),
  153    !.
  154format_predicate4(Xi, Xo) :-
  155    format_predicate2(Xi, Xo).
 strip_prefixes(+FunctorIn:atom, -FunctorOut:atom) is det
Strip any reserved prefixes added during processing. If appropriate, modify the output functor to restore formatting represented by the prefix. To ensure that prefixes added by the user remain intact, this predicate will return after removing a single copy of the dummy prefix, if encountered. Otherwise, all reserved prefixes will be stripped. To prevent errors, the dual rule prefix, if present, should always be first.
Arguments:
FunctorIn- Input functor
FunctorOut- Output functor
  170strip_prefixes(Fi, Fo) :-
  171    atom_concat(c_, F1, Fi),		% 'c_': classical negation
  172    !,
  173    strip_prefixes(F1, F2),
  174    atom_concat(-, F2, Fo).
  175strip_prefixes(Fi, not(Fo)) :-
  176    atom_concat(n_, F1, Fi),		% 'n_': classical negation
  177    !,
  178    strip_prefixes(F1, Fo).
  179strip_prefixes(Fi, Fo) :-
  180    has_prefix(Fi, C),
  181    C \== 'd',				% non-dummy prefix
  182    !,
  183    sub_atom(Fi, 2, _, 0, F1),
  184    strip_prefixes(F1, Fo).
  185strip_prefixes(Fi, Fo) :-
  186    atom_concat(d_, Fo, Fi),		% 'd_': dummy prefix, remove and finish
  187    !.
  188strip_prefixes(Fi, Fo) :-		% '_c_' prefixes change to 'o_'
  189    atom_concat('_c_', Fc, Fi),
  190    !,
  191    atom_concat('o_-', Fc, Fo).
  192strip_prefixes(Fi, Fo) :-		% '_' prefixes change to 'o_'
  193    atom_concat('_', Fc, Fi),
  194    !,
  195    atom_concat('o_', Fc, Fo).
  196strip_prefixes(F, F).
 generate_pr_rules(:Sources, +Options)
Translate the sCASP program from the defined_* predicates into pr_* predicates for sCASP. It creates clauses for the following predicates in the target module:
  211:- det(generate_pr_rules/2).  212
  213generate_pr_rules(M:_Sources, Options) :-
  214    check_existence(Options),
  215    findall(O-R, (defined_rule(_, H, B, O), c_rule(R, H, B)), Rs),
  216    maplist([O-R, O, R]>>true, Rs, Origins, Rs1),
  217    format_term_list(Rs1,Rs2),
  218    maplist([O, H-B, c(O, H, B)]>>true, Origins, Rs2, Rs3),
  219    (   defined_nmr_check(NMR)
  220    ->  format_term_list(NMR, NMR2)
  221    ;   NMR2 = []
  222    ),
  223    (   defined_query(Q,_),
  224        format_term_list(Q,Q2),
  225        assert_pr_query(M:Q2)
  226    ->  true
  227    ;   true
  228    ),
  229    handle_table_directives(M),
  230    handle_show_directives(M),
  231    handle_pred_directives(M),
  232    assert_pr_rules(Rs3, M),
  233    assert_pr_rules([c(generated(nmr), 'global_constraints', NMR2)], M).
  234
  235:- det((handle_table_directives/1,
  236        handle_show_directives/1,
  237        handle_pred_directives/1)).  238
  239handle_table_directives(M) :-
  240    findall(T, defined_directive(table(T)), Ts),
  241    format_term_list(Ts, Ts2),
  242    assert_pr_table(Ts2, M).
  243
  244handle_show_directives(M) :-
  245    findall(S, defined_directive(show(S)), Ss),
  246    format_term_list(Ss, Ss2),
  247    assert_pr_show(Ss2, M).
  248
  249handle_pred_directives(M) :-
  250    findall(P, defined_directive(pred(P)), Ps),
  251    format_term_list(Ps, Ps2),
  252    assert_pr_pred(Ps2, M).
 assert_pr_table(+Tabled) is det
  256assert_pr_table([], _) => true.
  257assert_pr_table([H|T], M) =>
  258    assert_pr_table(H, M),
  259    assert_pr_table(T, M).
  260assert_pr_table((H,T), M) =>
  261    assert_pr_table(H, M),
  262    assert_pr_table(T, M).
  263assert_pr_table(Name/Arity, M) =>
  264    assert(M:pr_table_predicate(Name/Arity)).
 assert_pr_show(+Atoms) is det
  268assert_pr_show([], _) => true.
  269assert_pr_show([H|T], M) =>
  270    assert_pr_show(H, M),
  271    assert_pr_show(T, M).
  272assert_pr_show((H,T), M) =>
  273    assert_pr_show(H, M),
  274    assert_pr_show(T, M).
  275assert_pr_show(not(Name/Arity), M) =>
  276    functor(T, Name, Arity),
  277    assert(M:pr_show_predicate(not(T))).
  278assert_pr_show(Name/Arity, M) =>
  279    functor(T, Name, Arity),
  280    assert(M:pr_show_predicate(T)).
 process_pr_pred(+PredDecl) is det
  284assert_pr_pred([], _) => true.
  285assert_pr_pred([H|T], M) =>
  286    assert_pr_pred(H, M),
  287    assert_pr_pred(T, M).
  288assert_pr_pred((H,T), M) =>
  289    assert_pr_pred(H, M),
  290    assert_pr_pred(T, M).
  291assert_pr_pred(T, M) =>
  292    process_pr_pred(T, Atom, Children, Cond, Human),
  293    assert(M:pr_pred_predicate(Atom, Children, Cond, Human)).
 process_pr_pred(+Spec, -Atom, -Children, -Condition, -Human) is det
Process a #pred Spec :: Template. directive.
Arguments:
Spec- is a term Head::Template, where Head is an sCASP atom where the variables are represented as $(Name) and Template is a string that embeds "@(Var)", "@(Var:Type)", "{{Var}}" or "{{Var:Type}}"
Pred- is a term `Head::format(Fmt, Args)`, where Fmt contains ~p and the arguments are of the shape @($(Var):Type), which is printed as "<Var>, a <Type>"
  307:- det(process_pr_pred/5).  308
  309process_pr_pred(Spec::html(HTML), A, Children, Cond, Human) =>
  310    revar(Spec+HTML, Spec1+HTML1, _),
  311    atom_cond(Spec1, A, Children, Cond),
  312    Human = html(HTML1).
  313process_pr_pred(Spec::B, A, Children, Cond, Human) =>
  314    atom_codes(B, Chars),
  315    phrase(pr_pred(FmtChars, Args, Spec, Spec1), Chars),
  316    atom_codes(Fmt, FmtChars),
  317    revar(Spec1, Spec2, _),                % need for s(CASP) input with vars
  318    atom_cond(Spec2, A, Children, Cond),   % not in template
  319    Human = format(Fmt,Args).
  320
  321pr_pred([0'~,0'p|Fmt], [@(Var:Type)|Args], A0, A) -->
  322    temp_var_start(Style), prolog_var_name(VarName),
  323    { insert_var(A0, A1, VarName, Var) },
  324    (   ":"
  325    ->  (   string(TypeChars), temp_var_end(Style)
  326        ->  {atom_codes(Type, TypeChars)}
  327        )
  328    ;   temp_var_end(Style)
  329    ->  {Type = ''}
  330    ),
  331    !,
  332    pr_pred(Fmt, Args, A1, A).
  333pr_pred([H|T], Args, A0, A) -->
  334    [H],
  335    !,
  336    pr_pred(T, Args, A0, A).
  337pr_pred([], [], A, A) -->
  338    [].
  339
  340temp_var_start(classic) --> "@(".
  341temp_var_start(modern)  --> "{{".
  342
  343temp_var_end(classic) --> ")".
  344temp_var_end(modern)  --> "}}".
 insert_var(+TermIn, -Term, +VarName, +Var) is det
  348insert_var($(Name), Repl, Name, Var) =>
  349    Repl = Var.
  350insert_var('$VAR'(Name), Repl, Name, Var) =>
  351    Repl = Var.
  352insert_var(V0, Repl, Name, Var), var(V0) =>
  353    (   prolog_load_context(variable_names, Bindings),
  354        member(Name = V1, Bindings),
  355        V0 == V1
  356    ->  Repl = Var
  357    ;   Repl = V0
  358    ).
  359insert_var(Name, Repl, Name, Var) =>
  360    Repl = Var.
  361insert_var(In, Out, Name, Var), compound(In) =>
  362    In =.. [F|Args0],
  363    maplist(insert_var_r(Name, Var), Args0, Args),
  364    Out =.. [F|Args].
  365insert_var(In, Out, _, _) =>
  366    Out = In.
  367
  368insert_var_r(Name, Var, In, Out) :-
  369    insert_var(In, Out, Name, Var).
 atom_cond(+Spec, -Atom, -Children, -Condition) is det
Translate a pred/1 condition. Spec specifies a node in the justification tree. Its general form is AtomSpec-Children, where Children is one of

Each AtomSpec is either a plain Atom, one wrapped, -(Atom) not(Atom) or not(-(Atom)). A condition may be added to an Atom as a conjunction, e.g., this denotes the atom p(X), but only if X is an integer.

:- pred (p(X),integer(X)) :: "bla bla {{X}}".
  394:- det(atom_cond/4).  395
  396atom_cond(Atom0-Children0, Atom, Children, Cond) =>
  397    atom_cond(Atom0, Atom, Cond0),
  398    atom_cond_list(Children0, Children, Cond0, Cond).
  399atom_cond(Atom0, Atom, Children, Cond) =>
  400    Children = '*',
  401    atom_cond(Atom0, Atom, Cond).
  402
  403atom_cond((Atom0,Cond0), Atom, Cond) =>
  404    Atom = Atom0,
  405    inline_cond(Cond0, Cond).
  406atom_cond(Atom0, Atom, Cond) =>
  407    Atom = Atom0,
  408    Cond = true.
  409
  410atom_cond_list(-, -, Cond, Cond) :-
  411    !.
  412atom_cond_list([], [], Cond, Cond).
  413atom_cond_list([H0|T0], [H|T], Cond0, Cond) :-
  414    atom_cond(H0, H, Cond1),
  415    mkconj(Cond0, Cond1, Cond2),
  416    atom_cond_list(T0, T, Cond2, Cond).
  417
  418inline_cond(var(X), Cond) =>
  419    Cond = (var(X)->true;X = '$VAR'(_)).
  420inline_cond(nonvar(X), Cond) =>
  421    Cond = (var(X)->false;X \= '$VAR'(_)).
  422inline_cond((C0,C1), Cond) =>
  423    inline_cond(C0, D0),
  424    inline_cond(C1, D1),
  425    mkconj(D0,D1, Cond).
  426inline_cond(C, Cond) =>
  427    Cond = C.
 assert_pr_rules(+Rules:list, +Module) is det
  432assert_pr_rules([], _).
  433assert_pr_rules([c(Origin, Head, Body)|Rs], M) :-
  434    !,
  435    revar(Head-Body,H-B, _),
  436    assert(M:pr_rule(H, B, Origin)),
  437    assert_pr_user_predicate([H], M),
  438    assert_pr_rules(Rs, M).
  439
  440
  441assert_pr_query(M:Q) :-
  442    assert(M:pr_query(Q)).
  443
  444assert_pr_user_predicate([], _).
  445assert_pr_user_predicate([P|Ps], M) :-
  446    functor(P, Name, La),
  447    (   M:pr_user_predicate(Name/La)
  448    ->  true
  449    ;   assert(M:pr_user_predicate(Name/La))
  450    ),
  451    assert_pr_user_predicate(Ps, M).
 check_existence(+Options)
Check that all referenced predicates are defined.
  458check_existence(Options) :-
  459    current_prolog_flag(scasp_unknown, DefaultMode),
  460    option(unknown(Mode), Options, DefaultMode),
  461    (   Mode == fail
  462    ->  true
  463    ;   defined_predicates(Preds),
  464        exclude(defined, Preds, Undef0),
  465        maplist(scasp_pred_pi, Undef0, Undef),
  466        (   Undef == []
  467        ->  true
  468        ;   Mode == warning
  469        ->  maplist(report_undef, Undef)
  470        ;   throw(error(scasp_undefined(Undef), _))
  471        )
  472    ).
  473
  474defined('_false_0').
  475defined(true_0).
  476defined(false_0).
  477defined(findall_3).
  478defined(inf_2).
  479defined(sup_2).
  480defined(Name) :-
  481    defined_rule(Name, _, _, _).
  482
  483scasp_pred_pi(DecoratedName, Name/Arity) :-
  484    split_functor(DecoratedName, PrefixedName, Arity),
  485    strip_prefixes(PrefixedName, Name).
  486
  487report_undef(PI) :-
  488    scasp_is_defined(PI),
  489    !.
  490report_undef(PI) :-
  491    print_message(warning,
  492                  error(existence_error(scasp_predicate, PI), _)).
  493
  494scasp_is_defined(QName/Arity) :-
  495    encoded_module_term(M:Name, QName),
  496    !,
  497    (   raise_negation(Name, -TheName)
  498    ->  functor(Head, TheName, Arity),
  499        predicate_property(M:Head, defined)
  500    ;   functor(Head, Name, Arity),
  501        predicate_property(M:Head, defined)
  502    ).
 clean_pr_program(+Module) is det
Prepare Module to receive a compiled sCASP program. This wipes a possibly existing sCASP program. It also relies on the side effect of retractall/1 to create a non-existing predicate as dynamic.
  510clean_pr_program(M) :-
  511    retractall(M:pr_query(_)),
  512    retractall(M:pr_rule(_,_,_)),
  513    retractall(M:pr_user_predicate(_)),
  514    retractall(M:pr_table_predicate(_)),
  515    retractall(M:pr_show_predicate(_)),
  516    retractall(M:pr_pred_predicate(_,_,_,_)),
  517    retractall(M:pr_dcc_predicate(_,_))