aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/lark/tree.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/lark/tree.py')
-rw-r--r--.venv/lib/python3.12/site-packages/lark/tree.py231
1 files changed, 231 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/lark/tree.py b/.venv/lib/python3.12/site-packages/lark/tree.py
new file mode 100644
index 00000000..0937b859
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/lark/tree.py
@@ -0,0 +1,231 @@
+try:
+ from future_builtins import filter
+except ImportError:
+ pass
+
+from copy import deepcopy
+
+
+###{standalone
+from collections import OrderedDict
+
+
+class Meta:
+ def __init__(self):
+ self.empty = True
+
+
+class Tree(object):
+ """The main tree class.
+
+ Creates a new tree, and stores "data" and "children" in attributes of the same name.
+ Trees can be hashed and compared.
+
+ Parameters:
+ data: The name of the rule or alias
+ children: List of matched sub-rules and terminals
+ meta: Line & Column numbers (if ``propagate_positions`` is enabled).
+ meta attributes: line, column, start_pos, end_line, end_column, end_pos
+ """
+ def __init__(self, data, children, meta=None):
+ self.data = data
+ self.children = children
+ self._meta = meta
+
+ @property
+ def meta(self):
+ if self._meta is None:
+ self._meta = Meta()
+ return self._meta
+
+ def __repr__(self):
+ return 'Tree(%r, %r)' % (self.data, self.children)
+
+ def _pretty_label(self):
+ return self.data
+
+ def _pretty(self, level, indent_str):
+ if len(self.children) == 1 and not isinstance(self.children[0], Tree):
+ return [indent_str*level, self._pretty_label(), '\t', '%s' % (self.children[0],), '\n']
+
+ l = [indent_str*level, self._pretty_label(), '\n']
+ for n in self.children:
+ if isinstance(n, Tree):
+ l += n._pretty(level+1, indent_str)
+ else:
+ l += [indent_str*(level+1), '%s' % (n,), '\n']
+
+ return l
+
+ def pretty(self, indent_str=' '):
+ """Returns an indented string representation of the tree.
+
+ Great for debugging.
+ """
+ return ''.join(self._pretty(0, indent_str))
+
+ def __eq__(self, other):
+ try:
+ return self.data == other.data and self.children == other.children
+ except AttributeError:
+ return False
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def __hash__(self):
+ return hash((self.data, tuple(self.children)))
+
+ def iter_subtrees(self):
+ """Depth-first iteration.
+
+ Iterates over all the subtrees, never returning to the same node twice (Lark's parse-tree is actually a DAG).
+ """
+ queue = [self]
+ subtrees = OrderedDict()
+ for subtree in queue:
+ subtrees[id(subtree)] = subtree
+ queue += [c for c in reversed(subtree.children)
+ if isinstance(c, Tree) and id(c) not in subtrees]
+
+ del queue
+ return reversed(list(subtrees.values()))
+
+ def find_pred(self, pred):
+ """Returns all nodes of the tree that evaluate pred(node) as true."""
+ return filter(pred, self.iter_subtrees())
+
+ def find_data(self, data):
+ """Returns all nodes of the tree whose data equals the given data."""
+ return self.find_pred(lambda t: t.data == data)
+
+###}
+
+ def expand_kids_by_index(self, *indices):
+ """Expand (inline) children at the given indices"""
+ for i in sorted(indices, reverse=True): # reverse so that changing tail won't affect indices
+ kid = self.children[i]
+ self.children[i:i+1] = kid.children
+
+ def expand_kids_by_data(self, *data_values):
+ """Expand (inline) children with any of the given data values. Returns True if anything changed"""
+ changed = False
+ for i in range(len(self.children)-1, -1, -1):
+ child = self.children[i]
+ if isinstance(child, Tree) and child.data in data_values:
+ self.children[i:i+1] = child.children
+ changed = True
+ return changed
+
+
+ def scan_values(self, pred):
+ """Return all values in the tree that evaluate pred(value) as true.
+
+ This can be used to find all the tokens in the tree.
+
+ Example:
+ >>> all_tokens = tree.scan_values(lambda v: isinstance(v, Token))
+ """
+ for c in self.children:
+ if isinstance(c, Tree):
+ for t in c.scan_values(pred):
+ yield t
+ else:
+ if pred(c):
+ yield c
+
+ def iter_subtrees_topdown(self):
+ """Breadth-first iteration.
+
+ Iterates over all the subtrees, return nodes in order like pretty() does.
+ """
+ stack = [self]
+ while stack:
+ node = stack.pop()
+ if not isinstance(node, Tree):
+ continue
+ yield node
+ for n in reversed(node.children):
+ stack.append(n)
+
+ def __deepcopy__(self, memo):
+ return type(self)(self.data, deepcopy(self.children, memo), meta=self._meta)
+
+ def copy(self):
+ return type(self)(self.data, self.children)
+
+ def set(self, data, children):
+ self.data = data
+ self.children = children
+
+ # XXX Deprecated! Here for backwards compatibility <0.6.0
+ @property
+ def line(self):
+ return self.meta.line
+
+ @property
+ def column(self):
+ return self.meta.column
+
+ @property
+ def end_line(self):
+ return self.meta.end_line
+
+ @property
+ def end_column(self):
+ return self.meta.end_column
+
+
+class SlottedTree(Tree):
+ __slots__ = 'data', 'children', 'rule', '_meta'
+
+
+def pydot__tree_to_png(tree, filename, rankdir="LR", **kwargs):
+ graph = pydot__tree_to_graph(tree, rankdir, **kwargs)
+ graph.write_png(filename)
+
+
+def pydot__tree_to_dot(tree, filename, rankdir="LR", **kwargs):
+ graph = pydot__tree_to_graph(tree, rankdir, **kwargs)
+ graph.write(filename)
+
+
+def pydot__tree_to_graph(tree, rankdir="LR", **kwargs):
+ """Creates a colorful image that represents the tree (data+children, without meta)
+
+ Possible values for `rankdir` are "TB", "LR", "BT", "RL", corresponding to
+ directed graphs drawn from top to bottom, from left to right, from bottom to
+ top, and from right to left, respectively.
+
+ `kwargs` can be any graph attribute (e. g. `dpi=200`). For a list of
+ possible attributes, see https://www.graphviz.org/doc/info/attrs.html.
+ """
+
+ import pydot
+ graph = pydot.Dot(graph_type='digraph', rankdir=rankdir, **kwargs)
+
+ i = [0]
+
+ def new_leaf(leaf):
+ node = pydot.Node(i[0], label=repr(leaf))
+ i[0] += 1
+ graph.add_node(node)
+ return node
+
+ def _to_pydot(subtree):
+ color = hash(subtree.data) & 0xffffff
+ color |= 0x808080
+
+ subnodes = [_to_pydot(child) if isinstance(child, Tree) else new_leaf(child)
+ for child in subtree.children]
+ node = pydot.Node(i[0], style="filled", fillcolor="#%x" % color, label=subtree.data)
+ i[0] += 1
+ graph.add_node(node)
+
+ for subnode in subnodes:
+ graph.add_edge(pydot.Edge(node, subnode))
+
+ return node
+
+ _to_pydot(tree)
+ return graph