Browse Source

Create TreeForestTransformer

tags/gm/2021-09-23T00Z/github.com--lark-parser-lark/0.10.0
Chanic Panic 5 years ago
parent
commit
607f984523
1 changed files with 80 additions and 1 deletions
  1. +80
    -1
      lark/parsers/earley_forest.py

+ 80
- 1
lark/parsers/earley_forest.py View File

@@ -12,8 +12,10 @@ from math import isinf
from collections import deque from collections import deque
from operator import attrgetter from operator import attrgetter
from importlib import import_module from importlib import import_module
from functools import partial


from .. visitors import Discard
from ..parse_tree_builder import AmbiguousIntermediateExpander
from ..visitors import Discard
from ..lexer import Token from ..lexer import Token
from ..utils import logger from ..utils import logger
from ..tree import Tree from ..tree import Tree
@@ -497,6 +499,83 @@ class ForestToParseTree(ForestTransformer):
self._on_cycle_retreat = False self._on_cycle_retreat = False
return super(ForestToParseTree, self).visit_token_node(node) return super(ForestToParseTree, self).visit_token_node(node)


def handles_ambiguity(func):
"""Decorator for methods of subclasses of TreeForestTransformer.
Denotes that the method should receive a list of transformed derivations."""
func.handles_ambiguity = True
return func

class TreeForestTransformer(ForestToParseTree):
"""A ForestTransformer with a tree-Transformer-like interface.
By default, it will construct a tree.

Methods provided via inheritance are called based on the rule/symbol
names of nodes in the forest.

Methods that act on rules will receive a list of the results of the
transformations of the rule's children. By default, trees and tokens.

Methods that act on tokens will receive a Token.

Alternatively, methods that act on rules may be annotated with
`handles_ambiguity`. In this case, the function will receive a list
of all the transformations of all the derivations of the rule.
By default, a list of trees where each tree.data is equal to the
rule name or one of its aliases.

Non-tree transformations are made possible by override of
`__default__`, `__default_token__`, and `__default_ambig__`.
"""

def __init__(self, tree_class=Tree, prioritizer=ForestSumVisitor(), resolve_ambiguity=True):
super(TreeForestTransformer, self).__init__(tree_class, dict(), prioritizer, resolve_ambiguity)

def __default__(self, name, data):
"""Default operation on tree (for override).

Returns a tree with name with data as children.
"""
return self.tree_class(name, data)

def __default_ambig__(self, name, data):
"""Default operation on ambiguous rule (for override).

Wraps data in an '_ambig_ node if it contains more than
one element.'
"""
if len(data) > 1:
return self.tree_class('_ambig', data)
elif data:
return data[0]
raise Discard

def __default_token__(self, node):
"""Default operation on Token (for override).

Returns node
"""
return node

def transform_token_node(self, node):
return getattr(self, node.type, self.__default_token__)(node)

def _call_rule_func(self, node, data):
name = node.rule.alias or node.rule.options.template_source or node.rule.origin.name
user_func = getattr(self, name, self.__default__)
if user_func == self.__default__ or hasattr(user_func, 'handles_ambiguity'):
user_func = partial(self.__default__, name)
if not self.resolve_ambiguity:
wrapper = partial(AmbiguousIntermediateExpander, self.tree_class)
user_func = wrapper(user_func)
return user_func(data)

def _call_ambig_func(self, node, data):
name = node.s.name
user_func = getattr(self, name, self.__default_ambig__)
if user_func == self.__default_ambig__ or not hasattr(user_func, 'handles_ambiguity'):
user_func = partial(self.__default_ambig__, name)
return user_func(data)

class ForestToPyDotVisitor(ForestVisitor): class ForestToPyDotVisitor(ForestVisitor):
""" """
A Forest visitor which writes the SPPF to a PNG. A Forest visitor which writes the SPPF to a PNG.


Loading…
Cancel
Save