Next: mpg-ref-goal_source_info, Previous: mpg-ref-get_mutable, Up: mpg-bpr [Contents][Index]
goal_expansion/5
hookM:goal_expansion(+Goal1, +Layout1, +Module, -Goal2, -Layout2)
Defines transformations on goals while clauses are being compiled or asserted, and during meta-calls at runtime.
callable
Goal to transform.
term
Layout of goal to transform.
atom
Source module of goal to transform.
callable
Transformed goal.
term
Layout of transformed goal.
Defines transformations on goals while clauses are being consulted,
compiled or asserted, after any processing by
user:term_expansion/6
of the terms being read in. It is
called for every simple Goal1, defined in M, in the source module Module
found while traversing the clause bodies. Typically, Module has imported
the predicate Goal1 from module M
but it happens also if Module uses an explicit module prefix, i.e. M:Goal1
.
If it succeeds, then Goal1
is replaced by Goal2; otherwise, Goal1 = Goal2.
Goal2 may be an arbitrarily complex goal, and
M:goal_expansion/5
is recursively applied to the expansion and its subgoals.
Please note: the arguments of meta-predicates such as
call/1
,setof/3
andon_exception/3
are not subject to such compile-time processing. Instead the expansion is performed at runtime, see below.
The above description holds even if Goal1
is exported but not
defined in the module M, i.e. it is possible to define a goal
expansion for an exported, but otherwise undefined,
predicate.
However, in general, it is better to provide an ordinary predicate
definition as a fallback, e.g. to be able to handle meta calls if
the goal expansion is not defined at runtime.
This predicate is also used to resolve any meta-calls to
Goal1 at runtime via the same mechanism. If the transformation
succeeds, then Goal2 is simply called instead of Goal1.
Otherwise, if Goal1 is a goal of an existing predicate, then
that predicate is invoked. Otherwise, error recovery is attempted
by user:unknown_predicate_handler/3
.
M:goal_expansion/5
can be regarded as a macro expansion
facility. It is used for this purpose to support the interface to
attributed variables in library(atts)
, which defines the
predicates M:get_atts/2
and M:put_atts/2
to access module-specific variable attributes. These
“predicates” are actually implemented via the
M:goal_expansion/5
mechanism. This has the effect that calls
to the interface predicates are expanded at compile time to
efficient code.
For accessing aspects of the load context, e.g. the name of the
file being compiled, the predicate
prolog_load_context/2
(see ref-lps-lco) can be used.
Note that prolog_load_context/2
only gives meaningful results
during compile (or consult) time. This means that when a meta call is
goal expanded, at runtime, the load context will not be available, and
there is no reliable way for a goal expansion to distinguish between
these cases.
The goal expansion may happen both at compile time (the normal case) at runtime (for meta calls). In some cases the compiler may try to avoid meta calls by calling goal expansion also for meta calls. This all means that the code implementing goal expansion should be present at both compile time and runtime. It also implies that goal expansion should not misbehave if it is called more times than expected.
Layout1 and Layout2 are for supporting source-linked
debugging in the context of goal expansion. The predicate should
construct a suitable Layout2 compatible with Term2 that
contains the line number information from Layout1. If source-linked
debugging of Term2 is not important, then Layout2 should be []
.
The recording of source info is affected by the source_info
prolog flag (see ref-lps-flg).
Exceptions are treated as failures, except an error message is printed as well.