Browse Source

Added visitors.Transformer_NonRecursive. Improved support for big grammars (issue #550)

tags/gm/2021-09-23T00Z/github.com--lark-parser-lark/0.8.6
Erez Sh 5 years ago
parent
commit
fb00e6a134
2 changed files with 41 additions and 7 deletions
  1. +11
    -7
      lark/load_grammar.py
  2. +30
    -0
      lark/visitors.py

+ 11
- 7
lark/load_grammar.py View File

@@ -16,7 +16,7 @@ from .utils import classify, suppress, dedup_list, Str
from .exceptions import GrammarError, UnexpectedCharacters, UnexpectedToken from .exceptions import GrammarError, UnexpectedCharacters, UnexpectedToken


from .tree import Tree, SlottedTree as ST from .tree import Tree, SlottedTree as ST
from .visitors import Transformer, Visitor, v_args, Transformer_InPlace
from .visitors import Transformer, Visitor, v_args, Transformer_InPlace, Transformer_NonRecursive
inline_args = v_args(inline=True) inline_args = v_args(inline=True)


__path__ = os.path.dirname(__file__) __path__ = os.path.dirname(__file__)
@@ -139,7 +139,7 @@ RULES = {


'maybe': ['_LBRA expansions _RBRA'], 'maybe': ['_LBRA expansions _RBRA'],
'range': ['STRING _DOTDOT STRING'], 'range': ['STRING _DOTDOT STRING'],
'template_usage': ['RULE _LBRACE _template_args _RBRACE'], 'template_usage': ['RULE _LBRACE _template_args _RBRACE'],
'_template_args': ['value', '_template_args': ['value',
'_template_args _COMMA value'], '_template_args _COMMA value'],
@@ -353,7 +353,7 @@ class PrepareAnonTerminals(Transformer_InPlace):


class _ReplaceSymbols(Transformer_InPlace): class _ReplaceSymbols(Transformer_InPlace):
" Helper for ApplyTemplates " " Helper for ApplyTemplates "
def __init__(self): def __init__(self):
self.names = {} self.names = {}


@@ -361,10 +361,10 @@ class _ReplaceSymbols(Transformer_InPlace):
if len(c) == 1 and isinstance(c[0], Token) and c[0].value in self.names: if len(c) == 1 and isinstance(c[0], Token) and c[0].value in self.names:
return self.names[c[0].value] return self.names[c[0].value]
return self.__default__('value', c, None) return self.__default__('value', c, None)
def template_usage(self, c): def template_usage(self, c):
if c[0] in self.names: if c[0] in self.names:
return self.__default__('template_usage', [self.names[c[0]].name] + c[1:], None)
return self.__default__('template_usage', [self.names[c[0]].name] + c[1:], None)
return self.__default__('template_usage', c, None) return self.__default__('template_usage', c, None)


class ApplyTemplates(Transformer_InPlace): class ApplyTemplates(Transformer_InPlace):
@@ -374,7 +374,7 @@ class ApplyTemplates(Transformer_InPlace):
self.rule_defs = rule_defs self.rule_defs = rule_defs
self.replacer = _ReplaceSymbols() self.replacer = _ReplaceSymbols()
self.created_templates = set() self.created_templates = set()
def template_usage(self, c): def template_usage(self, c):
name = c[0] name = c[0]
args = c[1:] args = c[1:]
@@ -487,6 +487,10 @@ class PrepareSymbols(Transformer_InPlace):
def _choice_of_rules(rules): def _choice_of_rules(rules):
return ST('expansions', [ST('expansion', [Token('RULE', name)]) for name in rules]) return ST('expansions', [ST('expansion', [Token('RULE', name)]) for name in rules])


def nr_deepcopy_tree(t):
"Deepcopy tree `t` without recursion"
return Transformer_NonRecursive(False).transform(t)

class Grammar: class Grammar:
def __init__(self, rule_defs, term_defs, ignore): def __init__(self, rule_defs, term_defs, ignore):
self.term_defs = term_defs self.term_defs = term_defs
@@ -497,7 +501,7 @@ class Grammar:
# We change the trees in-place (to support huge grammars) # We change the trees in-place (to support huge grammars)
# So deepcopy allows calling compile more than once. # So deepcopy allows calling compile more than once.
term_defs = deepcopy(list(self.term_defs)) term_defs = deepcopy(list(self.term_defs))
rule_defs = deepcopy(self.rule_defs)
rule_defs = [(n,p,nr_deepcopy_tree(t),o) for n,p,t,o in self.rule_defs]


# =================== # ===================
# Compile Terminals # Compile Terminals


+ 30
- 0
lark/visitors.py View File

@@ -154,6 +154,36 @@ class Transformer_InPlace(Transformer):
return self._transform_tree(tree) return self._transform_tree(tree)




class Transformer_NonRecursive(Transformer):
"Non-recursive. Doesn't change the original tree."

def transform(self, tree):
q = [tree]

# Tree to postfix
rev_postfix = []
while q:
t = q.pop()
rev_postfix.append( t )
if isinstance(t, Tree):
q += t.children[::-1]

# Postfix to tree
stack = []
for x in reversed(rev_postfix):
if isinstance(x, Tree):
size = len(x.children)
args = [stack.pop() for _ in range(size)]
stack.append(self._call_userfunc(x, args))
else:
stack.append(x)

t ,= stack # We should have only one tree remaining
assert t == tree
return t



class Transformer_InPlaceRecursive(Transformer): class Transformer_InPlaceRecursive(Transformer):
"Recursive. Changes the tree in-place instead of returning new instances" "Recursive. Changes the tree in-place instead of returning new instances"
def _transform_tree(self, tree): def _transform_tree(self, tree):


Loading…
Cancel
Save