11"""Tree matcher based on Lark grammar"""
22
33import re
4+ from typing import List , Dict
45from collections import defaultdict
56
6- from . import Tree , Token
7+ from . import Tree , Token , Lark
78from .common import ParserConf
89from .exceptions import ConfigurationError
910from .parsers import earley
@@ -40,7 +41,7 @@ def _best_from_group(seq, group_key, cmp_key):
4041 return list (d .values ())
4142
4243
43- def _best_rules_from_group (rules ) :
44+ def _best_rules_from_group (rules : List [ Rule ]) -> List [ Rule ] :
4445 rules = _best_from_group (rules , lambda r : r , lambda r : - len (r .expansion ))
4546 rules .sort (key = lambda r : len (r .expansion ))
4647 return rules
@@ -86,19 +87,23 @@ class TreeMatcher:
8687
8788 Initialize with an instance of Lark.
8889 """
90+ rules_for_root : Dict [str , List [Rule ]]
91+ rules : List [Rule ]
92+ parser : Lark
8993
90- def __init__ (self , parser ):
94+ def __init__ (self , parser : Lark ):
9195 # XXX TODO calling compile twice returns different results!
9296 assert not parser .options .maybe_placeholders
9397
94- # XXX TODO: we just ignore the potential existence of a postlexer
95- if parser .options .postlex is None :
96- self .tokens = parser .terminals .copy ()
97- rules = parser .rules .copy ()
98- else :
99- if not hasattr (parser , 'grammar' ) and parser .options .cache :
100- raise ConfigurationError ('Unanalyzed grammar not available from cached parser, use cache_grammar=True' )
98+ if parser .options .postlex and parser .options .postlex .always_accept :
99+ # If postlexer's always_accept is used, we need to recompile the grammar with empty terminals-to-keep
100+ if not hasattr (parser , 'grammar' ):
101+ raise ConfigurationError ('Source grammar not available from cached parser, use cache_grammar=True'
102+ if parser .options .cache else "Source grammar not available!" )
101103 self .tokens , rules , _extra = parser .grammar .compile (parser .options .start , set ())
104+ else :
105+ self .tokens = list (parser .terminals )
106+ rules = list (parser .rules )
102107
103108 self .rules_for_root = defaultdict (list )
104109
@@ -109,9 +114,9 @@ def __init__(self, parser):
109114 self .rules = _best_rules_from_group (self .rules )
110115
111116 self .parser = parser
112- self ._parser_cache = {}
117+ self ._parser_cache : Dict [ str , earley . Parser ] = {}
113118
114- def _build_recons_rules (self , rules ):
119+ def _build_recons_rules (self , rules : List [ Rule ] ):
115120 "Convert tree-parsing/construction rules to tree-matching rules"
116121 expand1s = {r .origin for r in rules if r .options .expand1 }
117122
@@ -153,7 +158,7 @@ def _build_recons_rules(self, rules):
153158 yield make_recons_rule_to_term (origin , NonTerminal (alias ))
154159 yield make_recons_rule_to_term (origin , origin )
155160
156- def match_tree (self , tree , rulename ) :
161+ def match_tree (self , tree : Tree , rulename : str ) -> Tree :
157162 """Match the elements of `tree` to the symbols of rule `rulename`.
158163
159164 Parameters:
@@ -167,7 +172,7 @@ def match_tree(self, tree, rulename):
167172 UnexpectedToken: If no match was found.
168173
169174 Note:
170- It's the callers' responsibility match the tree recursively.
175+ It's the callers' responsibility to match the tree recursively.
171176 """
172177 if rulename :
173178 # validate
@@ -184,11 +189,11 @@ def match_tree(self, tree, rulename):
184189
185190 # TODO pass callbacks through dict, instead of alias?
186191 callbacks = {rule : rule .alias for rule in rules }
187- conf = ParserConf (rules , callbacks , [rulename ])
192+ conf = ParserConf (rules , callbacks , [rulename ]) # type: ignore[arg-type]
188193 parser = earley .Parser (self .parser .lexer_conf , conf , _match , resolve_ambiguity = True )
189194 self ._parser_cache [rulename ] = parser
190195
191196 # find a full derivation
192- unreduced_tree = parser .parse (ChildrenLexer (tree .children ), rulename )
197+ unreduced_tree : Tree = parser .parse (ChildrenLexer (tree .children ), rulename )
193198 assert unreduced_tree .data == rulename
194199 return unreduced_tree
0 commit comments