ISO Prolog defines no way for program transformations such as macro expansion or conditional compilation. Expansion through term_expansion/2 and expand_term/2 can be seen as part of the de-facto standard. This mechanism can do arbitrary translation between valid Prolog terms read from the source file to Prolog terms handed to the compiler. As term_expansion/2 can return a list, the transformation does not need to be term-to-term.
Various Prolog dialects provide the analogous goal_expansion/2 and expand_goal/2 that allow for translation of individual body terms, freeing the user of the task to disassemble each clause.
?- Goal.
or :- Goal
. Goal
is then treated as a directive. If Term2 is a list, all terms
of the list are stored in the database or called (for directives). If
Term2 is of the form below, the system will assert Clause
and record the indicated source location with it:
'$source_location'(<File>, <Line>):<Clause>
When compiling a module (see chapter
6 and the directive module/2),
expand_term/2
will first try term_expansion/2
in the module being compiled to allow for term expansion rules that are
local to a module. If there is no local definition, or the local
definition fails to translate the term, expand_term/2
will try term_expansion/2
in module
user
. For compatibility with SICStus and Quintus Prolog,
this feature should not be used. See also expand_term/2, goal_expansion/2
and
expand_goal/2.
It is possible to act on the beginning and end of a file by expanding
the terms begin_of_file
and end_of_file
. The
latter is supported by most Prolog systems that support term expansion
as
read_term/3
returns end_of_file
on reaching the end of the input.
Expanding begin_of_file
may be used to initialise the
compilation, for example base on the file name extension. It was added
in SWI-Prolog 8.1.1.
[]
if we are in a `false branch' of the conditional compilation. See section
4.3.1.2.
user
and finally in system
. Library modules inherit directly
from system
and can thus not be re-interpreted by term
expansion rules in user
.
The predicate goal_expansion/2
is first called in the module that is being compiled, and then follows
the module inheritance path as defined by default_module/2,
i.e., by default user
and system
. If Goal
is of the form Module:Goal where Module
is instantiated, goal_expansion/2
is called on Goal using rules from module Module
followed by default modules for Module.
Only goals appearing in the body of clauses when reading a source file are expanded using this mechanism, and only if they appear literally in the clause, or as an argument to a defined meta-predicate that is annotated using `0' (see meta_predicate/1). Other cases need a real predicate definition.
The expansion hook can use prolog_load_context/2 to obtain information about the context in which the goal is exanded such as the module, variable names or the encapsulating term.
Note that in some cases multiple expansions of similar goals can
share the same compiled auxiliary predicate. In such cases, the
implementation of goal_expansion/2
can use predicate_property/2
using the property
defined
to test whether the predicate is already defined in
the current context.
Head-->Body
into a normal Prolog clause. Normally this functionality should be
accessed using expand_term/2.
This sections documents extended versions of the program transformation predicates that also transform the source layout information. Extended layout information is currently processed, but unused. Future versions will use for the following enhancements:
subterm_positions
of read_term/2.
Conditional compilation builds on the same principle as term_expansion/2, goal_expansion/2 and the expansion of grammar rules to compile sections of the source code conditionally. One of the reasons for introducing conditional compilation is to simplify writing portable code. See section C for more information. Here is a simple example:
:- if(\+source_exports(library(lists), suffix/2)). suffix(Suffix, List) :- append(_, Suffix, List). :- endif.
Note that these directives can only appear as separate terms in the input. Typical usage scenarios include:
:- else. :-if(Goal).
... :- endif.
In a sequence as below, the section below the first matching elif
is processed. If no test succeeds, the else branch is processed.
:- if(test1). section_1. :- elif(test2). section_2. :- elif(test3). section_3. :- else. section_else. :- endif.