All Packages Class Hierarchy This Package Previous Next Index
java.lang.Object | +----epp.Macro
Macro
class is the super class of the class
of all macro expansion objects.
Within the syntax macro expansion pass, each node of the abstract syntax
tree is checked to see if it is a macro node, and if so, the call
method of the corresponding macro expansion object is called.
When a plug-in programmer introduces a node that was not included in
standard Java, the programmer must also provide a class of a "macro expansion
object" that will convert the node into a standard Java node.
Furthurmore, the newly defined macro expansion object must be registered
with the macro expansion object table using the Epp method
defineMacro
.
For example, in the source code of the enum
plug-in,
an expansion object that expands a tree that has a tag named
:enum
is registered as follows.
(The EnumMacro
class is a subclass of class Macro
.)
extend void initMacroTable() { original(); defineMacro(:enum, new EnumMacro()); }
The macro expansion object is an instance of a subclass of
class Macro
. The macro expansion object has a method
named call
, that accepts a tree as an argument and returns
a tree.
The macro expansion object can be expanded using a decorator pattern.
In order to do so, you use Epp's extendMacro
method.
The original macro expansion object can be called from the decorator
via the instance variable orig
.
The value of the variable orig
is null if it is not
expanded by extendMacro
.
The recursive macro expansion of a tree is done by the
macroExpandTree
method.
The behaviour of the macroExpandTree
method is
strictly defined as follows.
Symbol lastTag = null; while(true) { Symbol tag = tree.tag(); if (tag == lastTag) break; lastTag = tag; Macro func = (Macro)macroTable.get(tag); if (func != null) { tree = func.call(tree); } else { tree = tree.modifyArgs(macroExpandArray(tree.args())); } } return tree;That is, it calls the
call
method of the macro expansion object
corresponding to the tag of the tree, and if the returned tag and the tag
prior to calling the method match, it exits the loop and returns the returned
value. Otherwise, it keeps on converting the macro expansion until
the tag does not change any further. If a macro expansion function
corresponding to the tag of the node does not exist, it creates a node
with its own subtree replaced with a macro expanded one, and returns that node.
A class named InvokeStyleMacro
is provided to make it easier
to define a macro that has the same grammar as a method call.
public Macro()
public abstract Tree call(Tree tree)
public static Tree macroExpandTree(Tree tree)
Macro.macroTable
using the tag of the argument
tree as the key. If the object exists, it calls it, and otherwise
executes the default macro expansion.
You may call this method explicitely from within a macro
expansion object that a plug-in programmer defines, but
in most cases will need to do so.
(The tree returned by the call
method of the
macro expansion object is expanded automatically until
all internal macros are expanded.)
public static Tree macroExpand1(Tree tree)
public static Tree[] macroExpandArray(Tree args[])
public static void checkArgsLength(Tree tree, int argc)
error
method is called.
public static void addTree(Symbol sym, Tree tree)
public static void addTree(Symbol sym, Tree tree){ TreeVec tvec = (TreeVec)Dynamic.get(sym); tvec.add(macroExpandTree(tree)); }
For example, you may want to add a method to the class currently expanding while executing macro expansion for an expanded syntax. In order to do so, you may write the following.
addTree(:beginningOfClassBody, aMethodDeclarationTree);The following symbols can be specified as the first argument to
addTree
.
:beforeCurrentTypeDeclaration :afterCurrentTypeDeclaration :beginningOfClassBody :beforeCurrentClassBodyDeclaration :afterCurrentClassBodyDeclaration :beforeCurrentBlockStatement :afterCurrentBlockStatementWith these, you can add code to the top level of the current file, add instance variables and methods to the current class, add local type declarations immediately before the current statement, add post-processing immediately after the current statement, etc.
public static Symbol genTemp(String prefix)
public static Symbol genTemp(String prefix){ return Symbol.intern(prefix + genTempCounter++); }
Where genTempCounter
is a static variable with an initial
value of 0.
Initialization is done only once when EPP is invoked.
public static Error error(String str)
EppUserError
.
Its usage is the same as EppCore#error
.
All Packages Class Hierarchy This Package Previous Next Index