The TermClass specifies to which terms the transformation will be applied:
trans_function(OldTerm, NewTerm [, Module]) :- ... .or it can be source annotation aware, and be of arity 4 or 5, as follows:
trans_function(OldTerm, NewTerm, OldAnn, NewAnn [, Module]) :- ... .At transformation time, the system will call TransPred in the module where
local macro/3
was invoked. The term to transform is
passed as the first argument, the second is a free variable which the
transformation should bind to the transformed term. In the case of the
source annotation aware version of TransPred, if the term was read in by
read_annotated/2,3, the annotated version of the term to transformed is
passed in the third argument, and the transformation should bind the
fourth argument to the annotated transformed term; otherwise, if no
source annotation information is available, the third argument is passed
in as a free variable, and the transformation should not bind the fourth
argument. In both TransPred cases, the optional last argument is the
module where the term was being read in.
Options is a list which may be empty or contain one of the following type specification atoms:
In rare cases it is necessary to suppress macro expansion explicitly. The functor no_macro_expansion/1 can be wrapped around specific instances of a term to prevent it from being transformed. Macro expansion will then remove this wrapper so that the end result is the untransformed term alone.
Term-transformations (but not clause/goal transformation) automatically transform all subterms of a term in a bottom-up fashion. This means that the transformation predicate will see a term with already transformed subterms.
The source annotation aware transformation predicate is provided to allow the user to detail how the subterms of the original term is mapped to the transformed term. Without this extra information, the whole of the transformed term is given the source information (source position, source file etc.) of the original source term. This extra information is useful when the subterms are goals, because without the extra information, source tracing of these goals during debugging will not be done.
% The following example illustrates how a/1 may be % transformed into b/2 using the reader: [eclipse]: [user]. trans_a(a(X),b(X,10)). :- local macro(a/1,trans_a/2,[]). yes. [eclipse]: read(X). a(fred). X = b(fred, 10) yes. % Example showing use of protect_arg: [eclipse]: [user]. trb(X, newfunctor(Arg)) :- arg(1, X, Arg). trd(d, newd). :- local macro(b/1, trb/2, []), macro(b_protect/1, trb/2, [protect_arg]), macro(d/0, trd/2, []). yes. [eclipse]: read(X1),read(X2). b(d). b_protect(d). X1 = newfunctor(newd) % d is transformed X2 = newfunctor(d) % d is not transformed yes. % Example showing use of type macros [eclipse 1]: [user]. tr_int(0, 0). tr_int(N, s(S)) :- N > 0, N1 is N-1, tr_int(N1, S). :- local macro(type(integer), tr_int/2, []). yes. [eclipse 2]: read(X). 3. X = s(s(s(0))) yes. % Example showing use of annotation aware macro transformation [eclipse 1]: [user]. trans_r(r(A,B), New, AnnR, AnnNew) :- New = rr(B,A), (nonvar(AnnR) -> AnnR = annotated_term{term:RAnn}, RAnn = r(AnnA,AnnB), NewRAnn = rr(AnnB,AnnA), update_struct(annotated_term, [term:NewRAnn], AnnR, AnnNew) ; true ). :- local macro(r/2, trans_r/4,[]). yes. [eclipse 2]: read(user,R). r(a,b). R = rr(b, a) yes. [eclipse 3]: read_annotated(user,R,AR). r(a,b). R = rr(b, a) AR = annotated_term(rr(annotated_term(b, atom, user, 15, 362, 363), annotated_term(a, atom, user, 15, 360, 361)), compound, user, 15, 358, 360) yes. % The previous example with non-annotation aware transformation: [eclipse 1]: [user]. trans_r(r(A,B),rr(B,A)). :- local macro(r/2, trans_r/ 2,[]). yes. [eclipse 2]: read_annotated(user,R,AR). r(a,b). R = rr(b, a) AR = annotated_term(rr(annotated_term(b, atom, user, 3, 61, 63), annotated_term(a, atom, user, 3, 61, 63)), compound, user, 3, 61, 63) % all subterms have the same position information Error: local macro(X, trx/2, []). (Error 4). local macro(a/1, tra/2, [c]). (Error 6).