1/*****************************************************************************
    2 * This file is part of the Prolog Development Tool (PDT)
    3 * 
    4 * Author: G�nter Kniesel, Tobias Rho (among others)
    5 * WWW: http://sewiki.iai.uni-bonn.de/research/pdt/start
    6 * Mail: pdt@lists.iai.uni-bonn.de
    7 * Copyright (C): 2004-2012, CS Dept. III, University of Bonn
    8 * 
    9 * All rights reserved. This program is  made available under the terms
   10 * of the Eclipse Public License v1.0 which accompanies this distribution,
   11 * and is available at http://www.eclipse.org/legal/epl-v10.html
   12 * 
   13 ****************************************************************************/
   14
   15% Author: G�nter Kniesel & Tobias Rho
   16% Date:   5. April 2012
   17% Licence: EPL
(using clause/3 and predicate_property/2). It

USE:

Invoke ?- gen_call_graph. Then use the clauses generated in this module: ?- xref(CallingClauseRef,CallLiteral,ProgramPoint,CalledClauseRef).

For many applications call resolution at clause level granularity might be too detailed. Predicate-level granularity can be easily obtained by calling the internal predicate get_clause/2 via once/1. and asserting the xref(CallingRef,Literal,ProgramPoint,CalledRef) just for the first referenced clause.

   38:- module( pdt_xref_v3, 
   39         [ gen_call_graph/0
   40         , xref/4            % (CallingRef,Literal,ProgramPoint,CalledRef)
   41         ]
   42         ).   43 
   44% Folgendes Pr�dikat nutzen wir gar nicht mehr.
   45% Eigentlich m�ssten wir es in der vorletzten Klausel
   46% von process_body__/3 aufrufen. Wir tun es aber nicht.
   47resolve_call(Call,DeclaringModule,ClauseRef) :- 
   48	strip_module(Call,Module,Literal),
   49	functor(Literal,Name,Arity),
   50	defined_in(Module,Name,Arity,DeclaringModule),
   51	clause(DeclaringModule:Literal,_Body,ClauseRef).
   52% Das heisst: Entweder ist dort ein Fehler, oder es 
   53% funktioniert auch ohne den Aufruf von defined_in/3 
   54% also so:
   55%
   56%resolve_call(Call,DeclaringModule,ClauseRef) :- 
   57%	strip_module(Call,Module,Literal),
   58%	%defined_in(Module,Name,Arity,DeclaringModule),
   59%	clause(Module:Literal,_Body,ClauseRef).
   60%
   61%Das ist tats�chlich der Fall:	
   62%
   63%?- clause(sub:c(X),_Body,ClauseRef).
   64%X = 1,
   65%_Body = true,
   66%ClauseRef = <clause>(08A640F0) ;
   67%X = 2,
   68%_Body = true,
   69%ClauseRef = <clause>(08A64080) ;
   70%X = 3,
   71%_Body = true,
   72%ClauseRef = <clause>(08A640B8).
   73% FAZIT: Wenn man nur die referenzierten Klauseln will, reicht clause/3.
   74% Wenn man hingegen auch das Modul wissen will, aus dem die Klauseln 
   75% stammen braucht man defined_in. Das (bzw. resolve_call)
   76% ist also noch einzbauen in unsere Implementierung. 
   77 
   78 
   79 
   80  	
   81gen_call_graph :- 
   82   retractall(xref(_,_,_,_)),  
   83   defined_in_module(Module,Name,Arity),
   84      functor(Head,Name,Arity),
   85      \+ predicate_property(Module:Head, foreign),
   86      clause_xref(Module,Head,Xref),
   87      assert(Xref),
   88   fail.
   89gen_call_graph.
 clause_xref(+Module, +Head, ?Xref) is nondet
   93clause_xref(Module,Head,Xref):-
   94   clause(Module:Head,Body,CallingRef),
   95   process_body(Module,Body,Arc),
   96   Arc  = arc(            Literal,ProgramPoint,CalledRef),
   97   Xref = xref(CallingRef,Literal,ProgramPoint,CalledRef).
   98
   99process_body(Module,Body,Arc) :-
  100	nb_setval(program_point, 0),
  101	process_body__(Module,Body,Arc).
  102
  103%process_body__(Module,(A,B),Arc):-
  104%	!,
  105%	( process_body__(Module,A,Arc) 
  106%	; process_body__(Module,B,Arc)
  107%    ).
  108%	
  109%process_body__(Module,(A;B),Arc):-
  110%    !,
  111%	( process_body__(Module,A,Arc) 
  112%	; process_body__(Module,B,Arc)
  113%    ).
  114%   
  115process_body__(Module,Term,_Arc):-
  116	( var(Module) 
  117	; var(Term)
  118	),
  119	!,
  120	fail.
  121
  122
  123process_body__(_,Module:Term,Arc):-
  124	!,
  125	process_body__(Module,Term,Arc).
  126	 
  127process_body__(Module,Meta,Arc):-
  128	is_meta_call(Module:Meta),
  129	!,
  130	peel_meta(Module:Meta,Literal),
  131	process_body__(Module,Literal,Arc).
  132	
  133
  134process_body__(Module,Literal,Arc):-
  135	callable(Literal),
  136	!,
  137	inc_program_point,
  138	get_program_point(Pt),
  139	get_clause(Module:Literal,Ref),      % refer to each called clause
  140%	once(get_clause(Module:Literal,Ref),  % refer just to first clause
  141	Arc=arc(Module:Literal, Pt, Ref).
  142	
  143
  144process_body__(_,Literal, arc(Literal, -1, failed)).
  145
  146
  147is_meta_call(Call):-
  148	predicate_property(Call, meta_predicate(_)).
  149	
  150
  151get_clause(_:'$_variable'(Term,Number),variable(Term,Number)):-
  152    !.
  153get_clause(Module:Literal,Ref):-
  154    predicate_property(Module:Literal, foreign),
  155    !,
  156	Ref=foreign.
  157get_clause(Module:Literal,Ref):-
  158	\+ clause(Module:Literal,_,_),
  159	!,
  160	Ref=undefined.
  161get_clause(Module:Literal,Ref):-
  162	clause(Module:Literal,_Body,Ref).
 peel_meta(+Meta, ?Literal) is nondet
  167peel_meta(Module:Meta,Literal):-
  168	predicate_property(Module:Meta, meta_predicate(Pattern)),
  169	inc_program_point,
  170	meta_argument(Meta,Pattern,Literal).
 meta_argument(+Meta, +Pattern, ?Literal) is nondet
  174meta_argument(Meta,Pattern,Literal):-
  175	arg(Nr,Pattern,MetaIndicator),
  176	number(MetaIndicator),
  177	arg(Nr,Meta,Argument),
  178	add_arguments(Argument,MetaIndicator,Literal).
  179	
  180%peel_meta(Literal,Literal).
  181
  182
  183add_arguments(Term,Number,Result) :- 
  184    var(Term),
  185    !,
  186    Result = '$_variable'(Term,Number).
  187add_arguments(Term,0,Term) :- !.
  188add_arguments(Term,Number,BiggerTerm) :-
  189	callable(Term),
  190	Number > 0,
  191	Term =.. List,
  192	length(Postfix,Number),
  193	append(List,Postfix,BiggerList),
  194	BiggerTerm =.. BiggerList.
  195
  196
  197inc_program_point :- 
  198	nb_getval(program_point, Value),
  199	Next is Value+1,
  200	nb_setval(program_point, Next).
  201	
  202get_program_point(Value):- 	
  203	nb_getval(program_point, Value)