diff --git a/lark/parsers/earley_forest.py b/lark/parsers/earley_forest.py index 7ce2676..c1b2b82 100644 --- a/lark/parsers/earley_forest.py +++ b/lark/parsers/earley_forest.py @@ -161,23 +161,29 @@ class ForestVisitor(object): Use this as a base when you need to walk the forest. """ + def get_cycle_in_path(self, node, path): + index = len(path) - 1 + while id(path[index]) != id(node): + index -= 1 + return path[index:] + def visit_token_node(self, node): pass def visit_symbol_node_in(self, node): pass def visit_symbol_node_out(self, node): pass def visit_packed_node_in(self, node): pass def visit_packed_node_out(self, node): pass - def on_cycle(self, node, get_path): pass + + def on_cycle(self, node, path): + """Called when a cycle is encountered. `node` is the node that causes + the cycle. `path` the list of nodes being visited: nodes that have been + entered but not exited. The first element is the root in a forest + visit, and the last element is the node visited most recently. + `path` should be treated as read-only. The utility function + `get_cycle_in_path` may be used to obtain a slice of `path` that only + contains the nodes that make up the cycle.""" + pass def visit(self, root): - def make_get_path(node): - """Create a function that will return a path from `node` to - the last visited node. Used for the `on_cycle` callback.""" - def get_path(): - index = len(path) - 1 - while id(path[index]) != id(node): - index -= 1 - return path[index:] - return get_path # Visiting is a list of IDs of all symbol/intermediate nodes currently in # the stack. It serves two purposes: to detect when we 'recurse' in and out @@ -220,7 +226,7 @@ class ForestVisitor(object): continue if id(next_node) in visiting: - oc(next_node, make_get_path(next_node)) + oc(next_node, path) continue input_stack.append(next_node) @@ -259,7 +265,7 @@ class ForestVisitor(object): not isinstance(next_node, Token): next_node = iter(next_node) elif id(next_node) in visiting: - oc(next_node, make_get_path(next_node)) + oc(next_node, path) continue input_stack.append(next_node) @@ -430,7 +436,7 @@ class ForestToParseTree(ForestTransformer): self.resolve_ambiguity = resolve_ambiguity self._on_cycle_retreat = False - def on_cycle(self, node, get_path): + def on_cycle(self, node, path): logger.warning("Cycle encountered in the SPPF at node: %s. " "As infinite ambiguities cannot be represented in a tree, " "this family of derivations will be discarded.", node)