loki.ir.transformer
Visitor classes for transforming the IR
Functions
|
Determine the validty status of a given |
Classes
|
An enriched |
|
A |
|
A |
|
Visitor class to rebuild the tree and replace nodes according to a mapper. |
- class Transformer(mapper=None, invalidate_source=True, inplace=False, rebuild_scopes=False)
Bases:
VisitorVisitor class to rebuild the tree and replace nodes according to a mapper.
Given a control flow tree \(T\) and a mapper from nodes in \(T\) to a set of new nodes \(L, M : N \rightarrow L\), build a new control flow tree \(T'\) where a node \(n \in N\) is replaced with \(M(n)\).
Important
The mapping is applied before visiting any children of a node.
Removing nodes: In the special case in which \(M(n)\) is None, \(n\) is dropped from \(T'\).
One to many mapping: In the special case in which \(M(n)\) is an iterable of nodes, all nodes in \(M(n)\) are inserted into the tuple containing \(n\).
Warning
Applying a
Transformerto an IR tree rebuilds all nodes by default, which means individual nodes from the original IR are no longer found in the new tree. To update references to IR nodes, the attributeTransformer.rebuiltprovides a mapping from original to rebuilt nodes. Alternatively, withinplacethe mapping can be applied without rebuilding the tree, leaving existing references to individual IR nodes intact (as long as the mapping does not replace or remove them in the tree).- Parameters:
mapper (dict) – The mapping \(M : N \rightarrow L\).
invalidate_source (bool, optional) – If set to True, this triggers invalidating the
sourceproperty of all parent nodes of a node \(n\) if \(M(n)\) hassource=None.inplace (bool, optional) – If set to True, all updates are performed on existing
Nodeobjects, instead of rebuilding them, keeping the original tree intact.rebuild_scopes (bool, optional) – If set to True, this will also rebuild
ScopedNodein the IR. This requires updatingTypedSymbol.scopeproperties, which is expensive and thus carried out only when explicitly requested.
- rebuilt
After applying the
Transformerto an IR, this contains a mapping \(n \rightarrow n'\) for every node of the original tree \(n \in T\) to the rebuilt nodes in the new tree \(n' \in T'\).- Type:
- visit_object(o, **kwargs)
Return the object unchanged.
- visit_tuple(o, **kwargs)
Visit all elements in a tuple, injecting any one-to-many mappings.
- visit_list(o, **kwargs)
Visit all elements in a tuple, injecting any one-to-many mappings.
- visit_Node(o, **kwargs)
Handler for
Nodeobjects.It replaces
obymapper[o], if it is in the mapper, otherwise visits all children before rebuilding the node.
- visit_ScopedNode(o, **kwargs)
Handler for
ScopedNodeobjects.It replaces
obymapper[o], if it is in the mapper, otherwise its behaviour differs slightly from the defaultvisit_Node()as it rebuilds the node first, then visits all children and then updates in-place the rebuilt node. This is to make sure upwards-pointing references to this scope (such asScopedNode.parentproperties) can be updated correctly.Additionally, it passes down the currently active scope in
kwargswhen recursing to children.
- visit(o, *args, **kwargs)
Apply this
Transformerto an IR tree.
- class NestedTransformer(mapper=None, invalidate_source=True, inplace=False, rebuild_scopes=False)
Bases:
TransformerA
Transformerthat applies replacements in a depth-first fashion.- visit_tuple(o, **kwargs)
Visit all elements in a tuple, injecting any one-to-many mappings.
- visit_list(o, **kwargs)
Visit all elements in a tuple, injecting any one-to-many mappings.
- visit_Node(o, **kwargs)
Handler for
Nodeobjects.It visits all children before applying the
mapper.
- visit_ScopedNode(o, **kwargs)
Handler for
ScopedNodeobjects.Its behaviour differs slightly from the default
visit_Node()as it rebuilds the node first, then visits all children and then updates in-place the rebuilt node. This is to make sure upwards-pointing references to this scope (such asScopedNode.parentproperties) can be updated correctly.Additionally, it passes down the currently active scope in
kwargswhen recursing to children.
- class MaskedTransformer(start=None, stop=None, active=False, require_all_start=False, greedy_stop=False, **kwargs)
Bases:
TransformerAn enriched
Transformerthat can selectively include or exclude parts of the tree.For that
MaskedTransformeris selectively switched on and off while traversing the tree. Nodes are only included in the new tree while it is “switched on”. The transformer is switched on or off when it encounters nodes fromstartorstop, respectively. This can be used, e.g., to extract everything between two nodes, or to create a copy of the entire tree but without all nodes between two nodes. Multiple such ranges can be defined by providing more than onestartandstopnode, respectively.The sets
startandstopare to be understood in a Pythonic way, i.e.,startnodes will be included in the result andstopexcluded.Important
When recursing down a tree, any
InternalNodeare only included in the tree if theMaskedTransformerwas switched on before visiting thatInternalNode. Importantly, this means the node is also not included if the transformer is switched on while traversing the internal node’s body. In such a case, only the body nodes that are included are retained.Optionally as a variant, switching on can also be delayed until all nodes from
starthave been encountered by settingrequire_all_startto True.Optionally, traversal can be terminated early with
greedy_stop. If enabled, theMaskedTransformerwill stop completely to traverse the tree as soon as encountering a node fromstop.Note
Enabling
require_all_startandgreedy_stopat the same time can be useful when you require the minimum number of nodes in-between multiple start and end nodes without knowing in which order they appear.Note
MaskedTransformerrebuilds alsoScopedNodeby default (i.e., it calls the parent constructor withrebuild_scopes=True).- Parameters:
start ((iterable of)
Node, optional) – Encountering a node fromstartduring traversal switches theMaskedTransformeron and includes that node and all subsequently traversed nodes in the produced tree.stop ((iterable of)
Node, optional) – Encountering a node fromstopduring traversal switches theMaskedTransformeroff and excludes that node and all subsequently traversed nodes from the produced tree.active (bool, optional) – Switch the
MaskedTransformeron at the beginning of the traversal. By default, it is switched on only after encountering a node fromstart.require_all_start (bool, optional) – Switch the
MaskedTransformeron only after encountering all nodes fromstart. By default, it is switched on after encountering any node fromstart.greedy_stop (bool, optional) – Stop traversing the tree as soon as any node from
stopis encountered. By default, traversal continues but nodes are excluded from the new tree until a node fromstartis encountered.**kwargs (optional) – Keyword arguments that are passed to the parent class constructor.
- visit(o, *args, **kwargs)
Apply this
Transformerto an IR tree.
- visit_object(o, **kwargs)
Return the object unchanged.
- visit_Node(o, **kwargs)
Handler for
Nodeobjects.It replaces
obymapper[o], if it is in the mapper, otherwise visits all children before rebuilding the node.
- visit_ScopedNode(o, **kwargs)
Handler for
ScopedNodeobjects.It replaces
obymapper[o], if it is in the mapper, otherwise its behaviour differs slightly from the defaultvisit_Node()as it rebuilds the node first, then visits all children and then updates in-place the rebuilt node. This is to make sure upwards-pointing references to this scope (such asScopedNode.parentproperties) can be updated correctly.Additionally, it passes down the currently active scope in
kwargswhen recursing to children.
- class NestedMaskedTransformer(start=None, stop=None, active=False, require_all_start=False, greedy_stop=False, **kwargs)
Bases:
MaskedTransformerA
MaskedTransformerthat retains parents for children that are included in the produced tree.In contrast to
MaskedTransformer, any encounteredInternalNodeare included in the new tree as long as any of its children are included.- visit_object(o, **kwargs)
Return the object unchanged.
Note that we need to keep them here regardless of the transformer being active because this handler takes care of properties for inactive parents that may still be retained if other children switch on the transformer.
- visit_LeafNode(o, **kwargs)
Handler for
LeafNodethat are included in the tree if theNestedMaskedTransformeris active.
- visit_InternalNode(o, **kwargs)
Handler for
InternalNodethat are included in the tree as long as anybodynode is included.
- visit_Conditional(o, **kwargs)
Handler for
Conditionalto account for theelse_body.Note
This removes the
Conditionalifbodyis empty. In that case,else_bodyis returned (which can be empty, too).
- visit_MultiConditional(o, **kwargs)
Handler for
MultiConditionalto account for all bodies.Note
This removes the
MultiConditionalif all of thebodiesare empty. In that case,else_bodyis returned (which can be empty, too).
- visit_TypeConditional(o, **kwargs)
Handler for
MultiConditionalto account for all bodies.Note
This removes the
MultiConditionalif all of thebodiesare empty. In that case,else_bodyis returned (which can be empty, too).