| @@ -161,23 +161,29 @@ class ForestVisitor(object): | |||||
| Use this as a base when you need to walk the forest. | 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_token_node(self, node): pass | ||||
| def visit_symbol_node_in(self, node): pass | def visit_symbol_node_in(self, node): pass | ||||
| def visit_symbol_node_out(self, node): pass | def visit_symbol_node_out(self, node): pass | ||||
| def visit_packed_node_in(self, node): pass | def visit_packed_node_in(self, node): pass | ||||
| def visit_packed_node_out(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 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 | # 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 | # the stack. It serves two purposes: to detect when we 'recurse' in and out | ||||
| @@ -220,7 +226,7 @@ class ForestVisitor(object): | |||||
| continue | continue | ||||
| if id(next_node) in visiting: | if id(next_node) in visiting: | ||||
| oc(next_node, make_get_path(next_node)) | |||||
| oc(next_node, path) | |||||
| continue | continue | ||||
| input_stack.append(next_node) | input_stack.append(next_node) | ||||
| @@ -259,7 +265,7 @@ class ForestVisitor(object): | |||||
| not isinstance(next_node, Token): | not isinstance(next_node, Token): | ||||
| next_node = iter(next_node) | next_node = iter(next_node) | ||||
| elif id(next_node) in visiting: | elif id(next_node) in visiting: | ||||
| oc(next_node, make_get_path(next_node)) | |||||
| oc(next_node, path) | |||||
| continue | continue | ||||
| input_stack.append(next_node) | input_stack.append(next_node) | ||||
| @@ -430,7 +436,7 @@ class ForestToParseTree(ForestTransformer): | |||||
| self.resolve_ambiguity = resolve_ambiguity | self.resolve_ambiguity = resolve_ambiguity | ||||
| self._on_cycle_retreat = False | 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. " | logger.warning("Cycle encountered in the SPPF at node: %s. " | ||||
| "As infinite ambiguities cannot be represented in a tree, " | "As infinite ambiguities cannot be represented in a tree, " | ||||
| "this family of derivations will be discarded.", node) | "this family of derivations will be discarded.", node) | ||||