public abstract class Node extends Object implements NodeInterface, Cloneable
Modifier and Type | Class and Description |
---|---|
static interface |
Node.Child
Marks fields that represent child nodes of this node.
|
static interface |
Node.Children
Marks array fields that are children of this node.
|
Modifier | Constructor and Description |
---|---|
protected |
Node() |
Modifier and Type | Method and Description |
---|---|
void |
accept(NodeVisitor nodeVisitor)
Invokes the
NodeVisitor.visit(Node) method for this node and recursively also for all
child nodes. |
void |
adoptChildren() |
<T> T |
atomic(Callable<T> closure) |
void |
atomic(Runnable closure) |
Node |
copy()
Creates a shallow copy of this node.
|
Node |
deepCopy()
Creates a deep copy of this node.
|
Iterable<Node> |
getChildren()
Iterator over the children of this node.
|
NodeCost |
getCost()
Returns a rough estimate for the cost of this
Node . |
Map<String,Object> |
getDebugProperties()
Returns properties of this node interesting for debugging and can be overwritten by
subclasses to add their own custom properties.
|
String |
getDescription()
Returns a user-readable description of the purpose of the Node, or "" if no description is
available.
|
SourceSection |
getEncapsulatingSourceSection()
Retrieves the segment of guest language source code that is represented by this Node, if
present; otherwise retrieves the segment represented by the nearest AST ancestor that has
this information.
|
protected Lock |
getLock()
Returns a lock object that can be used to synchronize modifications to the AST.
|
Node |
getParent()
The current parent node of this node.
|
RootNode |
getRootNode()
Get the root node of the tree a node belongs to.
|
SourceSection |
getSourceSection()
Retrieves the segment of guest language source code that is represented by this Node.
|
<T extends Node> |
insert(T newChild)
|
<T extends Node> |
insert(T[] newChildren)
|
boolean |
isAdoptable()
Returns
true if this node can be adopted by a parent. |
boolean |
isSafelyReplaceableBy(Node newNode)
Checks if this node can be replaced by another node: tree structure & type.
|
protected void |
notifyInserted(Node node)
Notifies the framework about the insertion of one or more nodes during execution.
|
protected void |
onReplace(Node newNode,
CharSequence reason)
Intended to be implemented by subclasses of
Node to receive a notification when the
node is rewritten. |
<T extends Node> |
replace(T newNode)
Replaces this node with another node.
|
<T extends Node> |
replace(T newNode,
CharSequence reason)
Replaces this node with another node.
|
void |
reportPolymorphicSpecialize()
Notifies the runtime that this node specialized to a polymorphic state.
|
String |
toString()
Converts this node to a textual representation useful for debugging.
|
public NodeCost getCost()
Node
. This estimate can be used by
runtime systems or guest languages to implement heuristics based on Truffle ASTs. This method
is intended to be overridden by subclasses. The default implementation returns the value of
NodeInfo.cost()
of the NodeInfo
annotation declared at the subclass. If no
NodeInfo
annotation is declared the method returns NodeCost.MONOMORPHIC
as a
default value.public SourceSection getSourceSection()
null
. If your node represents a
segment of the source code, override this method and return a eagerly or lazily computed
source section value. This method is not designed to be invoked on compiled code paths. May
be called on any thread and without a language context being active.
Simple example implementation using a simple implementation using a field:
abstract class SimpleNode extendsNode
{ privateSourceSection
sourceSection; void setSourceSection(SourceSection
sourceSection) { this.sourceSection = sourceSection; } @Override
publicSourceSection
getSourceSection() { return sourceSection; } }
Recommended implementation computing the source section lazily from primitive fields:
abstract class RecommendedNode extendsNode
{ private static final int NO_SOURCE = -1; private int sourceCharIndex = NO_SOURCE; private int sourceLength; public abstractObject
execute(VirtualFrame
frame); // invoked by the parser to set the source void setSourceSection(int charIndex, int length) { assert sourceCharIndex == NO_SOURCE : "source should only be set once"; this.sourceCharIndex = charIndex; this.sourceLength = length; } @Override
public finalSourceSection
getSourceSection() { if (sourceCharIndex == NO_SOURCE) { // AST node without source return null; }RootNode
rootNode = getRootNode(); if (rootNode == null) { // not yet adopted yet return null; }Source
source = rootNode.getSourceSection().getSource(); return source.createSection(sourceCharIndex, sourceLength); } }
public SourceSection getEncapsulatingSourceSection()
public boolean isAdoptable()
true
if this node can be adopted by a parent. This method is intended to
be overriden by subclasses. If nodes need to be statically shared that they must not be
adoptable, because otherwise the parent reference might cause a memory leak. If a node is not
adoptable then then it is guaranteed that the parent
pointer remains
null
at all times, even if the node is tried to be adopted by a parent.
Implementations of Node.isAdoptable()
are required to fold to a constant result when
compiled with a constant receiver.
public final <T extends Node> T[] insert(T[] newChildren)
adopted
by a
parent
. The new children need to be assigned to its children
field after insert was called.newChildren
- the array of new children whose parent should be updatedpublic final <T extends Node> T insert(T newChild)
adopted
by a
parent
. The new child needs to be assigned to its child
field after insert was called.newChild
- the new child whose parent should be updatedprotected final void notifyInserted(Node node)
instrumentable
nodes remain unchanged after their root node is first
executed
. Insertions
don't need to be notified if it is known that none of the inserted nodes are
instrumentable
.
The provided Node
and its children must be adopted
in the
AST before invoking this method. The caller must ensure that this method is invoked only once
for a given node and its children.
Example usage:
class MyRootNode extendsRootNode
{ protected MyRootNode(MyLanguage language) { super(language); } @Child InstrumentableLanguageNode child; @Override
publicObject
execute(VirtualFrame
frame) { if (child == null) {CompilerDirectives
.transferToInterpreterAndInvalidate(); child = insert(new InstrumentableLanguageNode()); notifyInserted(child); } return child.execute(frame); } }
node
- the node tree that got inserted.public final void adoptChildren()
public Map<String,Object> getDebugProperties()
public final Node getParent()
public final <T extends Node> T replace(T newNode, CharSequence reason)
Node.getSourceSection()
) associated with this node, it is transferred to the new node.newNode
- the new node that is the replacementreason
- a description of the reason for the replacementpublic final <T extends Node> T replace(T newNode)
Node.getSourceSection()
) associated with this node, it is transferred to the new node.newNode
- the new node that is the replacementpublic final boolean isSafelyReplaceableBy(Node newNode)
protected void onReplace(Node newNode, CharSequence reason)
Node
to receive a notification when the
node is rewritten. This method is invoked before the actual replace has happened.newNode
- the replacement nodereason
- the reason the replace suppliedpublic final void accept(NodeVisitor nodeVisitor)
NodeVisitor.visit(Node)
method for this node and recursively also for all
child nodes.nodeVisitor
- the visitorpublic final Iterable<Node> getChildren()
public Node copy()
public Node deepCopy()
public final RootNode getRootNode()
RootNode
or null
if there is none.public final void reportPolymorphicSpecialize()
allowed
, create a deep copy of the RootNode
hosting this node and gather context sensitive profiling feedback.public String toString()
public final void atomic(Runnable closure)
public final <T> T atomic(Callable<T> closure)
protected final Lock getLock()
public String getDescription()