1:- module( edcg, [
    2    op(1200, xfx, '-->>'),   % Similar to '-->'
    3    op(1200, xfx, '==>>'),   % Similar to '-->'
    4    op( 990,  fx, '?'),      % For guards with '==>>'
    5    edcg_import_sentinel/0
    6]).    7
    8% If running a version of SWI-Prolog older than 8.3.19, define the
    9% '=>' operator to prevent syntax errors in this module.  The '==>>'
   10% operator is still defined in the module export, even though it'll
   11% generate a runtime error if it's used.
   12:- if(\+ current_op(_, _, '=>')).   13:- op(1200, xfx, '=>').   14:- endif.   15
   16:- use_module(library(debug), [debug/3]).   17:- use_module(library(lists), [member/2, selectchk/3]).   18:- use_module(library(apply), [maplist/3, maplist/4, foldl/4]).   19
   20% These predicates define extra arguments and are defined in the
   21% modules that use the edcg module.
   22:- multifile
   23    acc_info/5,
   24    acc_info/7,
   25    pred_info/3,
   26    pass_info/1,
   27    pass_info/2.   28
   29:- multifile
   30    prolog_clause:make_varnames_hook/5,
   31    prolog_clause:unify_clause_hook/5.   32
   33% True if the module being read has opted-in to EDCG macro expansion.
   34wants_edcg_expansion :-
   35    prolog_load_context(module, Module),
   36    wants_edcg_expansion(Module).
   37
   38wants_edcg_expansion(Module) :-
   39    Module \== edcg,  % don't expand macros in our own library
   40    predicate_property(Module:edcg_import_sentinel, imported_from(edcg)).
   41
   42% dummy predicate exported to detect which modules want EDCG expansion
   43edcg_import_sentinel.
   44
   45
   46% term_expansion/4 is used to work around SWI-Prolog's attempts to
   47% match variable names when doing a listing (or interactive trace) and
   48% getting confused; this sometimes results in a strange error message
   49% for an unknown extended_pos(Pos,N).
   50
   51% Returning a variable for _Layout2 means "I don't know".
   52% See https://swi-prolog.discourse.group/t/strange-warning-message-from-compile-or-listing/3774
   53user:term_expansion(Term, Layout0, Expansion, Layout) :-
   54    wants_edcg_expansion,
   55    edcg_expand_clause(Term, Expansion, Layout0, Layout).
   56
   57% TODO:
   58% prolog_clause:unify_clause_hook(Read, Decompiled, Module, TermPos0, TermPos) :-
   59%     wants_edcg_expansion(Module),
   60%     edcg_expand_clause(Read, Decompiled, TermPos0, TermPos).
   61
   62% TODO:
   63%   prolog_clause:make_varnames_hook(ReadClause, DecompiledClause, Offsets, Names, Term) :- ...
   64
   65% TODO: support ((H,PB-->>B) [same as regular DCG]
   66edcg_expand_clause((H-->>B), Expansion, TermPos0, _) :-
   67    edcg_expand_clause_wrap((H-->>B), Expansion, TermPos0, _).
   68edcg_expand_clause((H,PB==>>B), Expansion, TermPos0, _) :-
   69    edcg_expand_clause_wrap((H,PB==>>B), Expansion, TermPos0, _).
   70edcg_expand_clause((H==>>B), Expansion, TermPos0, _) :-
   71    edcg_expand_clause_wrap((H==>>B), Expansion, TermPos0, _).
   72
   73edcg_expand_clause_wrap(Term, Expansion, TermPos0, TermPos) :-
   74    % (   valid_termpos(Term, TermPos0)  % for debugging
   75    % ->  true
   76    % ;   throw(error(invalid_termpos_read(Term,TermPos0), _))
   77    % ),
   78    (   '_expand_clause'(Term, Expansion, TermPos0, TermPos)
   79    ->  true
   80    ;   throw(error('FAILED_expand_clause'(Term, Expansion, TermPos0, TermPos), _))
   81    ),
   82    % (   valid_termpos(Expansion, TermPos) % for debugging
   83    % ->  true
   84    % ;   throw(error(invalid_termpos_expansion(Expansion, TermPos), _))
   85    % ).
   86    true.
   87
   88% :- det('_expand_clause'/4).
   89% Perform EDCG macro expansion
   90% TODO: support ((H,PB-->>B) [same as regular DCG]
   91'_expand_clause'((H-->>B), Expansion, TermPos0, TermPos) =>
   92    TermPos0 = term_position(From,To,ArrowFrom,ArrowTo,[H_pos,B_pos]),
   93    TermPos  = term_position(From,To,ArrowFrom,ArrowTo,[Hx_pos,Bx_pos]),
   94    Expansion = (TH:-TB),
   95    '_expand_head_body'(H, B, TH, TB, NewAcc, H_pos,B_pos, Hx_pos,Bx_pos),
   96    '_finish_acc'(NewAcc),
   97    !.
   98'_expand_clause'((H,PB==>>B), Expansion, _TermPos0, _) => % TODO TermPos
   99    % '==>>'(',',(H,PB),B)
  100    Expansion = (TH,Guards=>TB2),
  101    '_expand_guard'(PB, Guards),
  102    '_expand_head_body'(H, B, TH, TB, NewAcc, _H_pos,_B_pos, _Hx_pos,_Bx_pos),
  103    '_finish_acc_ssu'(NewAcc, TB, TB2),
  104    !.
  105'_expand_clause'((H==>>B), Expansion, TermPos0, TermPos) =>
  106    TermPos0 = term_position(From,To,ArrowFrom,ArrowTo,[H_pos,B_pos]),
  107    TermPos  = term_position(From,To,ArrowFrom,ArrowTo,[Hx_pos,Bx_pos]),
  108    Expansion = (TH=>TB2),
  109    '_expand_head_body'(H, B, TH, TB, NewAcc, H_pos,B_pos, Hx_pos,Bx_pos),
  110    '_finish_acc_ssu'(NewAcc, TB, TB2),
  111    !.
  112
  113:- det('_expand_guard'/2).  114% TODO: Do we want to expand the guards?
  115%       For now, just verify that they all start with '?'
  116'_expand_guard'((?G0,G2), Expansion) =>
  117    Expansion = (G, GE2),
  118    '_expand_guard_curly'(G0, G),
  119    '_expand_guard'(G2, GE2).
  120'_expand_guard'(?G0, G) =>
  121    '_expand_guard_curly'(G0, G).
  122'_expand_guard'(G, _) =>
  123    throw(error(type_error(guard,G),_)).
  124
  125:- det('_expand_guard_curly'/2).  126'_expand_guard_curly'({G}, G) :- !.
  127'_expand_guard_curly'(G, G).
  128
  129
  130:- det('_expand_head_body'/9).  131'_expand_head_body'(H, B, TH, TB, NewAcc, _H_pos,_B_pos, _Hx_pos,_Bx_pos) :-
  132    functor(H, Na, Ar),
  133    '_has_hidden'(H, HList), % TODO: can backtrack - should it?
  134    debug(edcg,'Expanding ~w',[H]),
  135    '_new_goal'(H, HList, HArity, TH),
  136    '_create_acc_pass'(HList, HArity, TH, Acc, Pass),
  137    '_expand_goal'(B, TB, Na/Ar, HList, Acc, NewAcc, Pass),
  138    !.
  139
  140% Expand a goal:
  141'_expand_goal'((G1,G2), Expansion, NaAr, HList, Acc, NewAcc, Pass) =>
  142    Expansion = (TG1,TG2),
  143    '_expand_goal'(G1, TG1, NaAr, HList, Acc, MidAcc, Pass),
  144    '_expand_goal'(G2, TG2, NaAr, HList, MidAcc, NewAcc, Pass).
  145'_expand_goal'((G1->G2;G3), Expansion, NaAr, HList, Acc, NewAcc, Pass) =>
  146    Expansion = (TG1->TG2;TG3),
  147    '_expand_goal'(G1, TG1, NaAr, HList, Acc, MidAcc, Pass),
  148    '_expand_goal'(G2, MG2, NaAr, HList, MidAcc, Acc1, Pass),
  149    '_expand_goal'(G3, MG3, NaAr, HList, Acc, Acc2, Pass),
  150    '_merge_acc'(Acc, Acc1, MG2, TG2, Acc2, MG3, TG3, NewAcc).
  151'_expand_goal'((G1*->G2;G3), Expansion, NaAr, HList, Acc, NewAcc, Pass) =>
  152    Expansion = (TG1*->TG2;TG3),
  153    '_expand_goal'(G1, TG1, NaAr, HList, Acc, MidAcc, Pass),
  154    '_expand_goal'(G2, MG2, NaAr, HList, MidAcc, Acc1, Pass),
  155    '_expand_goal'(G3, MG3, NaAr, HList, Acc, Acc2, Pass),
  156    '_merge_acc'(Acc, Acc1, MG2, TG2, Acc2, MG3, TG3, NewAcc).
  157'_expand_goal'((G1;G2), Expansion, NaAr, HList, Acc, NewAcc, Pass) =>
  158    Expansion = (TG1;TG2),
  159    '_expand_goal'(G1, MG1, NaAr, HList, Acc, Acc1, Pass),
  160    '_expand_goal'(G2, MG2, NaAr, HList, Acc, Acc2, Pass),
  161    '_merge_acc'(Acc, Acc1, MG1, TG1, Acc2, MG2, TG2, NewAcc).
  162'_expand_goal'((G1->G2), Expansion, NaAr, HList, Acc, NewAcc, Pass) =>
  163    Expansion = (TG1->TG2),
  164    '_expand_goal'(G1, TG1, NaAr, HList, Acc, MidAcc, Pass),
  165    '_expand_goal'(G2, TG2, NaAr, HList, MidAcc, NewAcc, Pass).
  166'_expand_goal'((G1*->G2), Expansion, NaAr, HList, Acc, NewAcc, Pass) =>
  167    Expansion = (TG1*->TG2),
  168    '_expand_goal'(G1, TG1, NaAr, HList, Acc, MidAcc, Pass),
  169    '_expand_goal'(G2, TG2, NaAr, HList, MidAcc, NewAcc, Pass).
  170'_expand_goal'((\+G), Expansion, NaAr, HList, Acc, NewAcc, Pass) =>
  171    Expansion = (\+TG),
  172    NewAcc = Acc,
  173    '_expand_goal'(G, TG, NaAr, HList, Acc, _TempAcc, Pass).
  174'_expand_goal'({G}, Expansion, _, _, Acc, NewAcc, _) =>
  175    Expansion = G,
  176    NewAcc = Acc.
  177'_expand_goal'(insert(X,Y), Expansion, _, _, Acc, NewAcc, _) =>
  178    Expansion = (LeftA=X),
  179    '_replace_acc'(dcg, LeftA, RightA, Y, RightA, Acc, NewAcc), !.
  180'_expand_goal'(insert(X,Y):A, Expansion, _, _, Acc, NewAcc, _) =>
  181    Expansion = (LeftA=X),
  182    '_replace_acc'(A, LeftA, RightA, Y, RightA, Acc, NewAcc),
  183    debug(edcg,'Expanding accumulator goal: ~w',[insert(X,Y):A]),
  184    !.
  185% Force hidden arguments in L to be appended to G:
  186'_expand_goal'((G:A), TG, _, _HList, Acc, NewAcc, Pass),
  187    \+'_list'(G),
  188    '_has_hidden'(G, []) =>
  189    '_make_list'(A, AList),
  190    '_new_goal'(G, AList, GArity, TG),
  191    '_use_acc_pass'(AList, GArity, TG, Acc, NewAcc, Pass).
  192% Use G's regular hidden arguments & override defaults for those arguments
  193% not in the head:
  194'_expand_goal'((G:A), TG, _, _HList, Acc, NewAcc, Pass),
  195    \+'_list'(G),
  196    '_has_hidden'(G, GList), GList\==[] =>
  197    '_make_list'(A, L),
  198    '_new_goal'(G, GList, GArity, TG),
  199    '_replace_defaults'(GList, NGList, L),
  200    '_use_acc_pass'(NGList, GArity, TG, Acc, NewAcc, Pass).
  201'_expand_goal'((L:A), Joiner, NaAr, _, Acc, NewAcc, _),
  202    '_list'(L) =>
  203    '_joiner'(L, A, NaAr, Joiner, Acc, NewAcc).
  204'_expand_goal'(L, Joiner, NaAr, _, Acc, NewAcc, _),
  205    '_list'(L) =>
  206    '_joiner'(L, dcg, NaAr, Joiner, Acc, NewAcc).
  207'_expand_goal'((X/A), Expansion, _, _, Acc, NewAcc, _),
  208    atomic(A),
  209    member(acc(A,X,_), Acc) =>
  210    Expansion = true,
  211    NewAcc = Acc,
  212    debug(edcg,'Expanding accumulator goal: ~w',[X/A]),
  213    !.
  214'_expand_goal'((X/A), Expansion, _, _, Acc, NewAcc, Pass),
  215    atomic(A),
  216    member(pass(A,X), Pass) =>
  217    Expansion = true,
  218    NewAcc = Acc,
  219    debug(edcg,'Expanding passed argument goal: ~w',[X/A]),
  220    !.
  221'_expand_goal'((A/X), Expansion, _, _, Acc, NewAcc, _),
  222    atomic(A),
  223    member(acc(A,_,X), Acc) =>
  224    Expansion = true,
  225    NewAcc = Acc.
  226'_expand_goal'((X/A/Y), Expansion, _, _, Acc, NewAcc, _),
  227    member(acc(A,X,Y), Acc),
  228    var(X), var(Y), atomic(A) =>
  229    Expansion = true,
  230    NewAcc = Acc.
  231'_expand_goal'((X/Y), true, NaAr, _, Acc, NewAcc, _) =>
  232    NewAcc = Acc,
  233    print_message(warning,missing_hidden_parameter(NaAr,X/Y)).
  234% Defaulty cases:
  235'_expand_goal'(G, TG, _HList, _, Acc, NewAcc, Pass) =>
  236    '_has_hidden'(G, GList), !,
  237    '_new_goal'(G, GList, GArity, TG),
  238    '_use_acc_pass'(GList, GArity, TG, Acc, NewAcc, Pass).
  239
  240% ==== The following was originally acc-pass.pl ====
  241
  242% Operations on the Acc and Pass data structures:
  243
  244:- det('_create_acc_pass'/5).  245% Create the Acc and Pass data structures:
  246% Acc contains terms of the form acc(A,LeftA,RightA) where A is the name of an
  247% accumulator, and RightA and LeftA are the accumulating parameters.
  248% Pass contains terms of the form pass(A,Arg) where A is the name of a passed
  249% argument, and Arg is the argument.
  250'_create_acc_pass'([], _, _, Acc, Pass) =>
  251    Acc = [],
  252    Pass = [].
  253'_create_acc_pass'([A|AList], Index, TGoal, Acc2, Pass),
  254    '_is_acc'(A) =>
  255    Acc2 = [acc(A,LeftA,RightA)|Acc],
  256    Index1 is Index+1,
  257    arg(Index1, TGoal, LeftA),
  258    Index2 is Index+2,
  259    arg(Index2, TGoal, RightA),
  260    '_create_acc_pass'(AList, Index2, TGoal, Acc, Pass).
  261'_create_acc_pass'([A|AList], Index, TGoal, Acc, Pass2),
  262    '_is_pass'(A) =>
  263    Pass2 = [pass(A,Arg)|Pass],
  264    Index1 is Index+1,
  265    arg(Index1, TGoal, Arg),
  266    '_create_acc_pass'(AList, Index1, TGoal, Acc, Pass).
  267'_create_acc_pass'([A|_AList], _Index, _TGoal, _Acc, _Pass),
  268    \+'_is_acc'(A),
  269    \+'_is_pass'(A) =>
  270    print_message(error,not_a_hidden_param(A)).
  271
  272
  273:- det('_use_acc_pass'/6).  274% Use the Acc and Pass data structures to create the arguments of a body goal:
  275% Add the hidden parameters named in GList to the goal.
  276'_use_acc_pass'([], _, _, Acc, NewAcc, _) =>
  277    NewAcc = Acc.
  278% 1a. The accumulator A is used in the head:
  279%     Note: the '_replace_acc' guard instantiates MidAcc
  280'_use_acc_pass'([A|GList], Index, TGoal, Acc, NewAcc, Pass),
  281    '_replace_acc'(A, LeftA, RightA, MidA, RightA, Acc, MidAcc) =>
  282    Index1 is Index+1,
  283    arg(Index1, TGoal, LeftA),
  284    Index2 is Index+2,
  285    arg(Index2, TGoal, MidA),
  286    '_use_acc_pass'(GList, Index2, TGoal, MidAcc, NewAcc, Pass).
  287% 1b. The accumulator A is not used in the head:
  288'_use_acc_pass'([A|GList], Index, TGoal, Acc, NewAcc, Pass),
  289    '_acc_info'(A, LStart, RStart) =>
  290    Index1 is Index+1,
  291    arg(Index1, TGoal, LStart),
  292    Index2 is Index+2,
  293    arg(Index2, TGoal, RStart),
  294    '_use_acc_pass'(GList, Index2, TGoal, Acc, NewAcc, Pass).
  295% 2a. The passed argument A is used in the head:
  296'_use_acc_pass'([A|GList], Index, TGoal, Acc, NewAcc, Pass),
  297    '_is_pass'(A),
  298    member(pass(A,Arg), Pass) =>
  299    Index1 is Index+1,
  300    arg(Index1, TGoal, Arg),
  301    '_use_acc_pass'(GList, Index1, TGoal, Acc, NewAcc, Pass).
  302% 2b. The passed argument A is not used in the head:
  303'_use_acc_pass'([A|GList], Index, TGoal, Acc, NewAcc, Pass),
  304    '_pass_info'(A, AStart) =>
  305    Index1 is Index+1,
  306    arg(Index1, TGoal, AStart),
  307    '_use_acc_pass'(GList, Index1, TGoal, Acc, NewAcc, Pass).
  308% 3. Defaulty case when A does not exist:
  309'_use_acc_pass'([A|_GList], _Index, _TGoal, Acc, Acc, _Pass) =>
  310    print_message(error,not_a_hidden_param(A)).
  311
  312:- det('_finish_acc'/1).  313% Finish the Acc data structure:
  314% Link its Left and Right accumulation variables together in pairs:
  315% TODO: does this work correctly in the presence of cuts? ("!") - see README
  316'_finish_acc'([]).
  317'_finish_acc'([acc(_,Link,Link)|Acc]) :- '_finish_acc'(Acc).
  318
  319:- det('_finish_acc_ssu'/3).  320'_finish_acc_ssu'([], TB, TB).
  321'_finish_acc_ssu'([acc(_,Link0,Link1)|Acc], TB0, TB) :-
  322    '_finish_acc_ssu'(Acc, (Link0=Link1,TB0), TB).
  323
  324% Replace elements in the Acc data structure:
  325% Succeeds iff replacement is successful.
  326'_replace_acc'(A, L1, R1, L2, R2, Acc, NewAcc) :-
  327    member(acc(A,L1,R1), Acc), !,
  328    '_replace'(acc(A,_,_), acc(A,L2,R2), Acc, NewAcc).
  329
  330:- det('_merge_acc'/8).  331% Combine two accumulator lists ('or'ing their values)
  332'_merge_acc'([], [], G1, G1, [], G2, G2, []) :- !.
  333'_merge_acc'([acc(Acc,OL,R)|Accs], [acc(Acc,L1,R)|Accs1], G1, NG1,
  334         [acc(Acc,L2,R)|Accs2], G2, NG2, [acc(Acc,NL,R)|NewAccs]) :- !,
  335    ( ( OL == L1, OL \== L2 ) ->
  336      MG1 = (G1,L1=L2), MG2 = G2, NL = L2
  337        ; ( OL == L2, OL \== L1 ) ->
  338      MG2 = (G2,L2=L1), MG1 = G1, NL = L1
  339        ; MG1 = G1, MG2 = G2, L1 = L2, L2 = NL ),
  340    '_merge_acc'(Accs, Accs1, MG1, NG1, Accs2, MG2, NG2, NewAccs).
  341
  342% ==== The following was originally generic-util.pl ====
  343
  344% Generic utilities special-util.pl
  345
  346:- det('_match'/4).  347% Match arguments L, L+1, ..., H of the predicates P and Q:
  348'_match'(L, H, _, _) :- L>H, !.
  349'_match'(L, H, P, Q) :- L=<H, !,
  350    arg(L, P, A),
  351    arg(L, Q, A),
  352    L1 is L+1,
  353    '_match'(L1, H, P, Q).
  354
  355
  356'_list'(L) :- nonvar(L), L=[_|_], !.
  357'_list'(L) :- L==[], !.
  358
  359:- det('_make_list'/2).  360'_make_list'(A, [A]) :- \+'_list'(A), !.
  361'_make_list'(L,   L) :-   '_list'(L), !.
  362
  363:- det('_replace'/4).  364% replace(Elem, RepElem, List, RepList)
  365'_replace'(_, _, [], []) :- !.
  366'_replace'(A, B, [A|L], [B|R]) :- !,
  367    '_replace'(A, B, L, R).
  368'_replace'(A, B, [C|L], [C|R]) :-
  369    \+C=A, !,
  370    '_replace'(A, B, L, R).
  371
  372% ==== The following was originally special-util.pl ====
  373
  374% Specialized utilities:
  375
  376% Given a goal Goal and a list of hidden parameters GList
  377% create a new goal TGoal with the correct number of arguments.
  378% Also return the arity of the original goal.
  379'_new_goal'(Goal, GList, GArity, TGoal) :-
  380    functor(Goal, Name, GArity),
  381    '_number_args'(GList, GArity, TArity),
  382    functor(TGoal, Name, TArity),
  383    '_match'(1, GArity, Goal, TGoal).
  384
  385% Add the number of arguments needed for the hidden parameters:
  386'_number_args'([], N, N).
  387'_number_args'([A|List], N, M) :-
  388    '_is_acc'(A), !,
  389    N2 is N+2,
  390    '_number_args'(List, N2, M).
  391'_number_args'([A|List], N, M) :-
  392    '_is_pass'(A), !,
  393    N1 is N+1,
  394    '_number_args'(List, N1, M).
  395'_number_args'([_|List], N, M) :- !,
  396    % error caught elsewhere
  397    '_number_args'(List, N, M).
  398
  399% Give a list of G's hidden parameters:
  400'_has_hidden'(G, GList) :-
  401    functor(G, GName, GArity),
  402    (   pred_info(GName, GArity, GList)
  403    ->  true
  404    ;   GList = []
  405    ).
  406
  407% Succeeds if A is an accumulator:
  408'_is_acc'(A), atomic(A) => '_acc_info'(A, _, _, _, _, _, _).
  409'_is_acc'(A), functor(A, N, 2) => '_acc_info'(N, _, _, _, _, _, _).
  410
  411% Succeeds if A is a passed argument:
  412'_is_pass'(A), atomic(A) => '_pass_info'(A, _).
  413'_is_pass'(A), functor(A, N, 1) => '_pass_info'(N, _).
  414
  415% Get initial values for the accumulator:
  416'_acc_info'(AccParams, LStart, RStart) :-
  417    functor(AccParams, Acc, 2),
  418    '_is_acc'(Acc), !,
  419    arg(1, AccParams, LStart),
  420    arg(2, AccParams, RStart).
  421'_acc_info'(Acc, LStart, RStart) :-
  422    '_acc_info'(Acc, _, _, _, _, LStart, RStart).
  423
  424% Isolate the internal database from the user database:
  425'_acc_info'(Acc, Term, Left, Right, Joiner, LStart, RStart) :-
  426    acc_info(Acc, Term, Left, Right, Joiner, LStart, RStart).
  427'_acc_info'(Acc, Term, Left, Right, Joiner, _, _) :-
  428    acc_info(Acc, Term, Left, Right, Joiner).
  429'_acc_info'(dcg, Term, Left, Right, Left=[Term|Right], _, []).
  430
  431% Get initial value for the passed argument:
  432% Also, isolate the internal database from the user database.
  433'_pass_info'(PassParam, PStart) :-
  434    functor(PassParam, Pass, 1),
  435    '_is_pass'(Pass), !,
  436    arg(1, PassParam, PStart).
  437'_pass_info'(Pass, PStart) :-
  438    pass_info(Pass, PStart).
  439'_pass_info'(Pass, _) :-
  440    pass_info(Pass).
  441
  442% Calculate the joiner for an accumulator A:
  443'_joiner'([], _, _, true, Acc, Acc).
  444'_joiner'([Term|List], A, NaAr, (Joiner,LJoiner), Acc, NewAcc) :-
  445    '_replace_acc'(A, LeftA, RightA, MidA, RightA, Acc, MidAcc),
  446    '_acc_info'(A, Term, LeftA, MidA, Joiner, _, _), !,
  447    '_joiner'(List, A, NaAr, LJoiner, MidAcc, NewAcc).
  448% Defaulty case:
  449'_joiner'([_Term|List], A, NaAr, Joiner, Acc, NewAcc) :-
  450    print_message(warning, missing_accumulator(NaAr,A)),
  451    '_joiner'(List, A, NaAr, Joiner, Acc, NewAcc).
  452
  453% Replace hidden parameters with ones containing initial values:
  454'_replace_defaults'([], [], _).
  455'_replace_defaults'([A|GList], [NA|NGList], AList) :-
  456    '_replace_default'(A, NA, AList),
  457    '_replace_defaults'(GList, NGList, AList).
  458
  459'_replace_default'(A, NewA, AList) :-  % New initial values for accumulator.
  460    functor(NewA, A, 2),
  461    member(NewA, AList), !.
  462'_replace_default'(A, NewA, AList) :-  % New initial values for passed argument.
  463    functor(NewA, A, 1),
  464    member(NewA, AList), !.
  465'_replace_default'(A, NewA, _) :-      % Use default initial values.
  466    A=NewA.
  467
  468% ==== The following was originally messages.pl ====
  469
  470:- multifile prolog:message//1.  471
  472prolog:message(missing_accumulator(Predicate,Accumulator)) -->
  473    ['In ~w the accumulator ''~w'' does not exist'-[Predicate,Accumulator]].
  474prolog:message(missing_hidden_parameter(Predicate,Term)) -->
  475    ['In ~w the term ''~w'' uses a non-existent hidden parameter.'-[Predicate,Term]].
  476prolog:message(not_a_hidden_param(Name)) -->
  477    ['~w is not a hidden parameter'-[Name]].
  478% === The following are for debugging term_expansion/4
  479
  480% :- det(valid_termpos/2). % DO NOT SUBMIT
  481%! valid_termpos(+Term, ?TermPos) is semidet.
  482% Checks that a Term has an appropriate TermPos.
  483% This should always succeed:
  484%    read_term(Term, [subterm_positions(TermPos)]),
  485%    valid_termpos(Term, TermPos)
  486% Note that this can create a TermPos. Each clause ends with
  487% a cut, to avoid unneeded backtracking.
  488valid_termpos(Term, TermPos) :-
  489    (   valid_termpos_(Term, TermPos)
  490    ->  true
  491    ;   fail % throw(error(invalid_termpos(Term,TermPos), _)) % DO NOT SUBMIT
  492    ).
  493
  494valid_termpos_(Var,    _From-_To) :- var(Var).
  495valid_termpos_(Atom,   _From-_To) :- atom(Atom), !.
  496valid_termpos_(Number, _From-_To) :- number(Number), !.
  497valid_termpos_(String,  string_position(_From,_To)) :- string(String), !.
  498valid_termpos_([],     _From-_To) :- !.
  499valid_termpos_({Arg},   brace_term_position(_From,_To,ArgPos)) :-
  500    valid_termpos(Arg, ArgPos), !.
  501% TODO: combine the two list_position clauses
  502valid_termpos_([Hd|Tl], list_position(_From,_To, ElemsPos, none)) :-
  503    maplist(valid_termpos, [Hd|Tl], ElemsPos),
  504    list_tail([Hd|Tl], _, []), !.
  505valid_termpos_([Hd|Tl], list_position(_From,_To, ElemsPos, TailPos)) :-
  506    list_tail([Hd|Tl], HdPart, Tail),
  507    tailPos \= none, Tail \= [],
  508    maplist(valid_termpos, HdPart, ElemsPos),
  509    valid_termpos(Tail, TailPos), !.
  510valid_termpos_(Term, term_position(_From,_To, FFrom,FTo,SubPos)) :-
  511    compound_name_arguments(Term, Name, Arguments),
  512    valid_termpos(Name, FFrom-FTo),
  513    maplist(valid_termpos, Arguments, SubPos), !.
  514valid_termpos_(Dict, dict_position(_From,_To,TagFrom,TagTo,KeyValuePosList)) :-
  515    dict_pairs(Dict, Tag, Pairs),
  516    valid_termpos(Tag, TagFrom-TagTo),
  517    foldl(valid_termpos_dict, Pairs, KeyValuePosList, []), !.
  518% key_value_position(From, To, SepFrom, SepTo, Key, KeyPos, ValuePos) is handled
  519% in valid_termpos_dict.
  520valid_termpos_(Term, parentheses_term_position(_From,_To,ContentPos)) :-
  521    valid_termpos(Term, ContentPos), !.
  522% TODO: documentation for quasi_quotation_position is wrong (SyntaxTo,SyntaxFrom should be SYntaxTerm,SyntaxPos).
  523valid_termpos_(_Term, quasi_quotation_position(_From,_To,SyntaxTerm,SyntaxPos,_ContentPos)) :-
  524    valid_termpos(SyntaxTerm, SyntaxPos), !.
  525
  526:- det(valid_termpos_dict/3).  527valid_termpos_dict(Key-Value, KeyValuePosList0, KeyValuePosList1) :-
  528    selectchk(key_value_position(_From,_To,_SepFrom,_SepTo,Key,KeyPos,ValuePos),
  529              KeyValuePosList0, KeyValuePosList1),
  530    valid_termpos(Key, KeyPos),
  531    valid_termpos(Value, ValuePos).
  532
  533:- det(list_tail/3).  534list_tail([X|Xs], HdPart, Tail) =>
  535    HdPart = [X|HdPart2],
  536    list_tail(Xs, HdPart2, Tail).
  537list_tail(Tail0, HdPart, Tail) => HdPart = [], Tail0 = Tail