public class AstSymbolResolver extends SymbolResolver
The pattern engine creates an instance of this class for each run of a ruleset pipeline. The pipeline uses this object to associate the following constructs with one another at a specific point in time, for a user-defined purpose:
A map of ASTs is maintained, where each AST is indexed by its unique ID.
This allows client code to create AST cross-references by storing one or
more external AST IDs as a node's annotations. The cross-references are
resolved by looking up an AST by its ID, using the the getAst(java.lang.Long)
method. This requires that every AST which may need to be looked up using
this mechanism first be registered with this resolver using the registerAst(com.goldencode.ast.Aast)
method. The map is cleared each time the resolver's cleanUp()
method is invoked. This method is called by the pattern engine
after each AST is fully processed against a ruleset. The map is populated
(at least for the source AST tree) when the source, root AST is first
set with the setAsts(com.goldencode.ast.Aast, com.goldencode.ast.Aast)
method. Pattern workers which create and
manipulate target (i.e., converted code) ASTs are responsible for
registering their AST nodes separately.
All pattern worker implementations loaded by a ruleset or by the pipeline
itself are managed by the resolver. Pattern workers are registered by
class name, and only one instance of a pattern worker implementation is
allowed at a time. Once an instance is registered, no other instance of
the same class is accepted. Rule containers register their pattern workers
here, based upon instructions received from the ConfigLoader
. Each
rule container is responsible for mapping namespace aliases to the pattern
worker objects about which it cares. As user expressions are parsed and
compiled, the resolver will use the namespace qualifier to request the
associated pattern worker object from a rule container.
Important Note: this class is not thread-safe. It is assumed that the pattern engine using this resolver object is responsible for correctly synchronizing the state of a resolver with the rules that access its data.
PatternEngine
,
RuleSet
Modifier and Type | Field and Description |
---|---|
private java.util.Map<java.lang.Long,Aast> |
astMap
Map of ids to ASTs
|
private static ContextLocal<AstSymbolResolver> |
context
Context-local instance of this class
|
private Aast |
copyAst
Copy of source AST which may be modified by actions
|
private java.lang.String |
currentCondition
Text of conditional expression currently under test
|
private boolean |
endWalk
Flag to indicate walking should cease after the current AST node
|
private java.lang.ref.WeakReference<PatternEngine> |
engine
Pattern processing engine
|
private java.util.Deque<Scope> |
funcScopes
Named function stack; top function is currently being processed
|
private int |
nextChildIndex
Tracks the next child index during walking.
|
private static java.lang.String |
PARENT
Variable name for current AST's parent's token type
|
private java.util.Deque<RuleContainer> |
resolvingContainers
Stack of rule containers currently in use for resolving namespaces
|
private RuleContainer |
ruleScope
Rule container which is currently in scope
|
private Aast |
sourceAst
Read-only source AST currently being processed
|
private Aast |
targetRootAst
Root node of target (converted code) AST hierarchy
|
private static java.lang.String |
TYPE
Variable name for current AST's token type
|
private java.util.Set<Aast> |
view
Set of filtered results which define a view on the original AST
|
private java.util.Map<java.lang.String,PatternWorker> |
workers
Pattern workers indexed by fully qualified class name
|
_aastore, _aconst_null, _aload_0, _aload_1, _aload_2, _aload_3, _anewarray, _areturn, _astore_1, _astore_2, _astore_3, _checkcast, _d2i, _d2l, _dadd, _dcmpg, _dconst_0, _dconst_1, _ddiv, _dmul, _dneg, _drem, _dreturn, _dsub, _dup, _getfield, _goto, _i2d, _i2l, _iadd, _iand, _iconst_0, _iconst_1, _iconst_2, _iconst_3, _iconst_4, _iconst_5, _idiv, _if_icmpeq, _if_icmpge, _if_icmpgt, _if_icmple, _if_icmplt, _if_icmpne, _ifeq, _ifge, _ifgt, _ifle, _iflt, _ifne, _ifnonnull, _ifnull, _imul, _ineg, _invokeinterface, _invokespecial, _invokestatic, _invokevirtual, _ior, _irem, _ireturn, _ishl, _ishr, _isub, _iushr, _ixor, _l2d, _l2i, _ladd, _land, _lcmp, _lconst_0, _lconst_1, _ldc_w, _ldc2_w, _ldiv, _lmul, _lneg, _lor, _lrem, _lshl, _lshr, _lsub, _lushr, _lxor, _new, _pop, _pop2, _return, _swap, CLASS_COMPILEDEXPRESSION, METHDESC_EXECUTE, METHNAME_EXECUTE, METHOD_INIT
Modifier | Constructor and Description |
---|---|
private |
AstSymbolResolver(PatternEngine engine)
Create an instance of this class which is associated with the given
pattern engine object.
|
Modifier and Type | Method and Description |
---|---|
void |
addAncestorToView(int level)
Add a specified ancestor of the copy of the current source
AST node to the filtered view of AST nodes associated with the current
ruleset run.
|
void |
addParentToView()
Add the parent of the copy of the current source AST node
to the filtered view of AST nodes associated with the current ruleset
run.
|
boolean |
addPathToViewFrom(long type)
Add to the filtered view of ASTs all of the copy nodes
which form the path from an ancestor node of type
type
to the current copy AST. |
void |
addToView()
Add the copy of the current source AST node to the filtered
view of AST nodes associated with the current ruleset run.
|
boolean |
addToView(java.lang.Long id)
Add an arbitrary AST node to the filtered view of AST nodes associated
with the current ruleset run.
|
void |
addTreeToView(int maxLevels)
Add the copy of the current source AST node and its
descendants to the set of results, descending at most
maxLevels generations deep. |
(package private) void |
cleanUp()
Clean up internal resources.
|
(package private) static AstSymbolResolver |
create(PatternEngine engine)
Create and return the context-local instance of this class.
|
(package private) static Expression |
createExpression(java.lang.String infix)
Create an expression object associated with the context-local instance of
the resolver, based upon the specified infix expression phrase.
|
java.lang.Object |
execute(java.lang.String text)
Execute a dynamically provided user expression.
|
java.lang.Object |
execute(java.lang.String text,
java.lang.Object[] args)
Execute a named user expression passing user provided named parameters
to be referenced in the expression.
|
Aast |
getAst(java.lang.Long id)
Get the AST with the specified ID.
|
Aast |
getCopyAst()
Get the AST currently under inspection within the copy tree.
|
java.lang.String |
getCurrentCondition()
Get the infix expression test, exactly as provided by the user or the
pattern profile, of the rule condition currently under test.
|
protected Scope |
getCurrentScope()
Get the rule container which defines the current scope defined for
the resolver.
|
(package private) int |
getNextChildIndex()
Get the index of the child being processed during a next child
rule.
|
PatternEngine |
getPatternEngine()
Get the pattern engine which created and uses this symbol resolver.
|
(package private) PatternWorker |
getRegisteredWorker(java.lang.String className)
Get the
PatternWorker of the specified type, if any is
already registered. |
static AstSymbolResolver |
getResolver()
Retrieve the context-local instance of this class, if it has been created.
|
(package private) RuleContainer |
getRuleScope()
Gets the symbol resolver's current container scope.
|
Aast |
getSourceAst()
Get the AST currently under inspection within the source tree.
|
Aast |
getTargetRootAst()
Get the AST which is the root of the target AST hierarchy.
|
private PatternWorker |
getWorker(java.lang.String name)
Return the pattern worker instance associated with the given name.
|
boolean |
isEndWalk()
Indicate whether the current walk should end after the current node
is processed.
|
void |
printAst()
Debug method to print a representation of the current copy AST to
stdout . |
void |
registerAst(Aast ast)
Register an AST, so that it is accessible by its unique ID with the
getAst(java.lang.Long) method. |
(package private) void |
registerTree(Aast root)
Helper to add an entire subtree (rooted at the specified AST node) to
the AST registry.
|
(package private) PatternWorker |
registerWorker(PatternWorker worker)
Register the given pattern worker under its fully qualified class
name.
|
(package private) static void |
reset()
Clears the context-local instance of this class (sets the reference to
null ). |
(package private) void |
reset(RuleContainer ruleScope)
Reset the internal state of this symbol resolver object.
|
java.lang.Object |
resolveConstant(java.lang.String qualifier,
java.lang.String constant)
Resolve the specified constant into a numeric, boolean, or string
literal value, if it is recognized.
|
(package private) void |
setAsts(Aast sourceAst,
Aast copyAst)
Set the current source and copy ASTs which will form the basis of all
AST-related symbol resolution done by this resolver.
|
(package private) void |
setCurrentCondition(java.lang.String currentCondition)
Set the current condition text.
|
void |
setEndWalk(boolean endWalk)
Set a flag indicating whether the current walk should end after the
current node is processed.
|
(package private) static void |
setLocal(AstSymbolResolver resolver)
Set the context-local instance of the resolver to the given instance.
|
(package private) void |
setNextChildIndex(int index)
Set the index of the child being processed during a next child
rule.
|
(package private) void |
setRuleScope(RuleContainer ruleScope)
Sets the symbol resolver's current scope to be the specified rule
container.
|
void |
setTargetRootAst(Aast targetRootAst)
Set the root node of the target AST hierarchy.
|
(package private) java.util.Iterator<Aast> |
view()
Return an iterator on the filtered view of ASTs currently associated
with this resolver.
|
(package private) java.util.Iterator<PatternWorker> |
workers()
Returns an iterator on all registered pattern workers.
|
checkPermission, dropLibrary, dropVariable, dropVariablePool, getVariable, registerLibrary, registerVariable, resetVariables
private static final java.lang.String TYPE
private static final java.lang.String PARENT
private static final ContextLocal<AstSymbolResolver> context
private final java.util.Map<java.lang.String,PatternWorker> workers
private java.lang.ref.WeakReference<PatternEngine> engine
private java.util.Deque<RuleContainer> resolvingContainers
private java.util.Map<java.lang.Long,Aast> astMap
private java.util.Set<Aast> view
private RuleContainer ruleScope
private java.util.Deque<Scope> funcScopes
private Aast sourceAst
private Aast copyAst
private Aast targetRootAst
private java.lang.String currentCondition
private int nextChildIndex
private boolean endWalk
private AstSymbolResolver(PatternEngine engine)
engine
- Pattern processing engine which uses this object to perform
expression symbol resolution.public static AstSymbolResolver getResolver()
java.lang.IllegalStateException
- if this method is invoked before the symbol resolver has
been created.public boolean isEndWalk()
true
if the walk will end after the current node;
false
if it will continue.public void setEndWalk(boolean endWalk)
endWalk
set to true
to cancel an existing
walk in progress. It is invoked with endWalk
set to
false
by the pattern engine after a walk has been ended
to reset this flag for the next AST to be processed.
Note: setting this flag to true
will end the walk
after all rules and actions have been processed for the current
node, but it will not prevent remaining rules and actions from being
applied to the current node. The walk termination is not disruptive,
in that it does not abruptly halt pattern engine processing, it just
causes remaining nodes in the current AST to go unprocessed.
To forcibly terminate pattern engine processing from a ruleset
(to report an unrecoverable error, for instance) use CommonAstSupport.Library.throwException(java.lang.String)
instead.
endWalk
- true
to end the walk after the current node;
false
to allow the walk to continue.static AstSymbolResolver create(PatternEngine engine)
engine
refers to a different object instance than the
one stored in the existing resolver. In the latter case, an exception
is thrown.engine
- Pattern processing engine.java.lang.IllegalStateException
- if an instance of the symbol resolver has already been
created, based upon a different pattern engine instance.static void reset()
null
). This will allow subsequent calls to create(com.goldencode.p2j.pattern.PatternEngine)
to complete successfully. This must NEVER be called while a pattern
engine is still processing. Use at your own risk!static void setLocal(AstSymbolResolver resolver)
resolver
- Symbol resolver to set as the context-local resolver.static Expression createExpression(java.lang.String infix)
infix
- Infix notation expression which forms the basis of the new
expression object.public PatternEngine getPatternEngine()
protected Scope getCurrentScope()
getCurrentScope
in class SymbolResolver
NamedFunction
is being processed, this function will be returned.
Otherwise this will be a ruleset or the pattern engine
itself.public java.lang.Object resolveConstant(java.lang.String qualifier, java.lang.String constant)
qualifier
is not
null
, it is used to identify a pattern worker from which to
request resolution of constant
to a literal. If the
qualifier is omitted (is passed as null
), this method is a
NOP. The reason for this is that in the past, this parameter was optional
but unqualified constant names are no longer supported. However, to
ensure that there is no breakage, a null
is still allowed
to be passed. It just will never return a value in that case.
Return an object of the following type (or null
):
resolveConstant
in class SymbolResolver
qualifier
- An namespace qualifier to distinguish between pattern
workers used to resolve the constant. It may be
null
, however when this is null
this method will be a NOP.
This value is case-insensitive.constant
- A string representing a constant to be resolved.null
if constant
was not recognized as a placeholder
for a literal.public void registerAst(Aast ast)
getAst(java.lang.Long)
method.ast
- AST to be registered.java.lang.NullPointerException
- if ast
has not yet been assigned a unique ID.public Aast getAst(java.lang.Long id)
id
- ID which uniquely identifies the desired AST.id
, or null
if no node is found for id
.public Aast getSourceAst()
The contract for PatternWorker
implementations, though this is
not explicitly enforced, is that this node should never be edited, and
must be considered read-only. Otherwise, the logic which controls the
iteration may be compromised. Any edits required by an action defined
by a pattern worker must be made to the copy of this node.
getCopyAst()
public Aast getCopyAst()
This node is fair game for editing during a tree/view walk, since it is not used for iteration logic.
getSourceAst()
public Aast getTargetRootAst()
null
if it has not
been set.public void setTargetRootAst(Aast targetRootAst)
targetRootAst
- Root node of target AST.public java.lang.Object execute(java.lang.String text)
text
- The text of the infix expression to be executed.ExpressionException
- if the expression cannot be compiled.public java.lang.Object execute(java.lang.String text, java.lang.Object[] args)
text
- This parameter represents the alias which identifies the named
expression to look up.args
- The array of Object
instances of the correct
data type and in the correct order to match our parameter
list. Each element of the array will be assigned into the
matching parameter in our parameter list before the expression
is executed.ExpressionException
- if a required lookup fails or if the expression cannot be
compiled.public void addToView()
public boolean addToView(java.lang.Long id)
true
if the AST is valid (and thus was added),
false
otherwise.public void addParentToView()
The parent node is not added if it is null
.
public void addAncestorToView(int level)
The node is not added if a parent in the chain of levels or at
the specified level is null
.
level
- Identifies the ancestor by the number of generations 'up' the
tree from the current node. 0 specifies the current node, 1
specifies the parent node, 2 specifies the 'grandparent'
node and so forth.public void addTreeToView(int maxLevels)
maxLevels
generations deep.maxLevels
- Number of generations to be added to the result set,
beginning with the current AST. To add only the current
AST, specify 1
(or better yet, use addToView()
).public boolean addPathToViewFrom(long type)
type
to the current copy AST. The nodes are added in root to leaf order.
If an ancestor node of type type
does not exist, no nodes
are added (not even the current one).type
- Ancestor token type which marks the beginning of the path.true
if an ancestor of type type
was found and the path of nodes was successfully added to the
filtered view, else false
.public void printAst()
stdout
. The text includes the AST's text, token name,
line number, and column number. It is indented according to its
nesting depth within the containing AST hierarchy.public java.lang.String getCurrentCondition()
null
if no rule currently is being applied.private PatternWorker getWorker(java.lang.String name)
name
- Namespace identifier.name
within the scope of the current rule container.void setCurrentCondition(java.lang.String currentCondition)
currentCondition
- Expression text in infix notation of the current rule's
condition.int getNextChildIndex()
void setNextChildIndex(int index)
index
- The index of the next child or -1 if not processing a next
child rule.java.util.Iterator<PatternWorker> workers()
We cannot simply return an iterator of the map's value collection because the order of iteration is important. The order is driven by the key set, so we return a custom iterator which uses the key set to iterate, but returns the value at each key. Also, we don't want to allow removals, so we disallow this with our iterator's implementation of remove().
PatternWorker registerWorker(PatternWorker worker)
worker
- The worker instance to be registered.worker
, or if another instance of
worker
's class was already registered, that
instance is returned instead.PatternWorker getRegisteredWorker(java.lang.String className)
PatternWorker
of the specified type, if any is
already registered.className
- PatternWorker
implementation class name.null
if
no worker of the specified type has yet been registered.void reset(RuleContainer ruleScope)
Implementation Note: it is safe to iterate over a previous view
returned by view
, even after this method is called. The
Iterator
returned by the view
method is associated
with a previous instance of the underlying collection. That instance is
replaced in this method, not cleared and re-used. Thus the iterator may
be used safely.
ruleScope
- The rule container which defines the scope of namespaces and
expression libraries currently available to the resolver. This
is needed in order to properly apply rules.void setRuleScope(RuleContainer ruleScope)
ruleScope
- Object which defines scope context for user variables and
worker libraries.RuleContainer getRuleScope()
void setAsts(Aast sourceAst, Aast copyAst)
If the copy AST specified here is the root of its tree, and the internal map of AST IDs to AST objects is empty, this method will walk once through the copy tree to register each AST, in preparation for ruleset processing against that AST.
If there is a target root AST assigned and the internal map of AST IDs to AST objects is empty (upon entry to this method), this method will walk once through the target tree to register each AST.
sourceAst
- The AST currently being inspected. It is read-only by contract,
though this is not explicitly enforced.copyAst
- A copy of the source AST currently being inspected. It exists
in a duplicate hierarchy (at least until actions are invoked
which may edit that hierarchy) to that of the source AST. It
shares all of the internal state of the source AST from which
it was copied, except that any object references to other ASTs
(i.e., parent and/or children) are actually references to
similar duplicates, and are self-contained within this AST's
duplicate hierarchy. It is to this node that any edits required
by pattern workers or rule actions should be made.void registerTree(Aast root)
root
- Root node of the tree to be added.void cleanUp()
java.util.Iterator<Aast> view()
The collection underlying this view is replaced with an empty
collection before each ruleset in the pipeline is processed. However,
it is safe to iterate over the view returned by this method after this
occurs, because a new collection is used for each pass, and the
Iterator
instance returned by this method continues to be
associated with the results collection which was in use at the time
it was called.
reset()