1:- module(unfold_calls,
    2	  [unfold_calls/4]).    3
    4:- use_module(library(implementation_module)).    5:- use_module(library(qualify_meta_goal)).    6
    7:- multifile
    8    unfold_call_hook/4.    9
   10:- meta_predicate unfold_calls(+, +, 2, -).   11unfold_calls(Goal, CM, IsUnfold, Calls) :-
   12    implementation_module(CM:Goal, M),
   13    findall(Call, ( unfold_call(Goal, CM, IsUnfold, [], Call),
   14		    \+ M:Goal =@= Call
   15		  ), Calls).
   16
   17unfold_call(Goal, _, _, _, _) :- var(Goal), !, fail.
   18unfold_call(true, _, _, _, _) :- !, fail.
   19unfold_call(call(Goal), CM, IsUnfold, NonUnfoldL, Call) :- !,
   20    unfold_call(Goal, CM, IsUnfold, NonUnfoldL, Call).
   21unfold_call(\+ Goal, CM, IsUnfold, NonUnfoldL, Call) :- !,
   22    unfold_call(Goal, CM, IsUnfold, NonUnfoldL, Call).
   23unfold_call(CM:Goal, _, IsUnfold, NonUnfoldL, Call) :-
   24    nonvar(Goal), !,
   25    unfold_call(Goal, CM, IsUnfold, NonUnfoldL, Call).
   26unfold_call(Goal0, CM, IsUnfold, NonUnfoldL, Call) :-
   27    CMGoal0 = CM:Goal0,
   28    implementation_module(CMGoal0, M),
   29    qualify_meta_goal(CMGoal0, Goal),
   30    ( unfold_call_hook(Goal, M, CM, Goal2)
   31    *->
   32      unfold_call(Goal2, CM, IsUnfold, NonUnfoldL, Call)
   33    ; \+ \+ memberchk(M:Goal, NonUnfoldL)
   34    ->Call = CM:Goal
   35    ; \+ call(IsUnfold, Goal, M),
   36      \+ ( predicate_property(CM:Goal, meta_predicate(S)),
   37	   arg(_, S, 0 )
   38	 )
   39    ->Call = CM:Goal
   40    ; ( nth_clause(CM:Goal, _Idx, Ref),
   41	clause(M:Head, Body, Ref),
   42	Body \== call(Head)
   43      *->
   44	clause_property(Ref, module(BM)),
   45	( subsumes_term(Head, Goal)
   46	->Goal = Head,
   47	  unfold_call(Body, BM, IsUnfold, NonUnfoldL, Call)
   48	; \+ Head \= Goal
   49	->copy_term(Goal, Head),
   50	  unfold_call(Body, BM, IsUnfold, [M:Head|NonUnfoldL], Call)
   51				% Abstraction to get more info
   52	)
   53      ; predicate_property(CM:Goal, meta_predicate(Spec)),
   54	( arg(N, Spec, S),
   55	  arg(N, Goal, A),
   56	  S = 0,
   57	  unfold_call(A, CM, IsUnfold, NonUnfoldL, Call)
   58	)
   59      )
   60    )