@@ -367,7 +367,6 @@ class Lark(Serialize): | |||||
return TraditionalLexer(lexer_conf) | return TraditionalLexer(lexer_conf) | ||||
def _prepare_callbacks(self): | def _prepare_callbacks(self): | ||||
self.parser_class = get_frontend(self.options.parser, self.options.lexer) | |||||
self._callbacks = {} | self._callbacks = {} | ||||
# we don't need these callbacks if we aren't building a tree | # we don't need these callbacks if we aren't building a tree | ||||
if self.options.ambiguity != 'forest': | if self.options.ambiguity != 'forest': | ||||
@@ -382,6 +381,7 @@ class Lark(Serialize): | |||||
self._callbacks.update(_get_lexer_callbacks(self.options.transformer, self.terminals)) | self._callbacks.update(_get_lexer_callbacks(self.options.transformer, self.terminals)) | ||||
def _build_parser(self): | def _build_parser(self): | ||||
self.parser_class = get_frontend(self.options.parser, self.options.lexer) | |||||
self._prepare_callbacks() | self._prepare_callbacks() | ||||
parser_conf = ParserConf(self.rules, self._callbacks, self.options.start) | parser_conf = ParserConf(self.rules, self._callbacks, self.options.start) | ||||
return self.parser_class(self.lexer_conf, parser_conf, options=self.options) | return self.parser_class(self.lexer_conf, parser_conf, options=self.options) | ||||
@@ -421,16 +421,21 @@ class Lark(Serialize): | |||||
self.options = LarkOptions.deserialize(options, memo) | self.options = LarkOptions.deserialize(options, memo) | ||||
self.rules = [Rule.deserialize(r, memo) for r in data['rules']] | self.rules = [Rule.deserialize(r, memo) for r in data['rules']] | ||||
self.source_path = '<deserialized>' | self.source_path = '<deserialized>' | ||||
self.parser_class = get_frontend(self.options.parser, self.options.lexer) | |||||
self.lexer_conf = self.parser_class.deserialize_lexer_conf( # We need the terminals list to for _prepare_callbacks | |||||
data['parser'], | |||||
memo, | |||||
self.options) | |||||
self.terminals = self.lexer_conf.terminals | |||||
self._terminals_dict = {t.name: t for t in self.terminals} | |||||
self._prepare_callbacks() | self._prepare_callbacks() | ||||
self.parser = self.parser_class.deserialize( | self.parser = self.parser_class.deserialize( | ||||
data['parser'], | data['parser'], | ||||
memo, | memo, | ||||
self.lexer_conf, | |||||
self._callbacks, | self._callbacks, | ||||
self.options, # Not all, but multiple attributes are used | self.options, # Not all, but multiple attributes are used | ||||
) | ) | ||||
self.lexer_conf = self.parser.lexer_conf | |||||
self.terminals = self.parser.lexer_conf.terminals | |||||
self._terminals_dict = {t.name: t for t in self.terminals} | |||||
return self | return self | ||||
@classmethod | @classmethod | ||||
@@ -38,23 +38,26 @@ class MakeParsingFrontend: | |||||
parser_conf.parser_type = self.parser_type | parser_conf.parser_type = self.parser_type | ||||
lexer_conf.lexer_type = self.lexer_type | lexer_conf.lexer_type = self.lexer_type | ||||
return ParsingFrontend(lexer_conf, parser_conf, options) | return ParsingFrontend(lexer_conf, parser_conf, options) | ||||
@classmethod | @classmethod | ||||
def deserialize(cls, data, memo, callbacks, options): | |||||
lexer_conf = LexerConf.deserialize(data['lexer_conf'], memo) | |||||
parser_conf = ParserConf.deserialize(data['parser_conf'], memo) | |||||
parser = LALR_Parser.deserialize(data['parser'], memo, callbacks, options.debug) | |||||
parser_conf.callbacks = callbacks | |||||
def deserialize_lexer_conf(cls, data, memo, options): | |||||
# We need lexer_conf earley to have the terminals that we need to produce the callback list for paser_conf | |||||
# So we split deserialize into two methods | |||||
terminals = [item for item in memo.values() if isinstance(item, TerminalDef)] | terminals = [item for item in memo.values() if isinstance(item, TerminalDef)] | ||||
lexer_conf = LexerConf.deserialize(data['lexer_conf'], memo) | |||||
lexer_conf.callbacks = _get_lexer_callbacks(options.transformer, terminals) | lexer_conf.callbacks = _get_lexer_callbacks(options.transformer, terminals) | ||||
lexer_conf.re_module = regex if options.regex else re | lexer_conf.re_module = regex if options.regex else re | ||||
lexer_conf.use_bytes = options.use_bytes | lexer_conf.use_bytes = options.use_bytes | ||||
lexer_conf.g_regex_flags = options.g_regex_flags | lexer_conf.g_regex_flags = options.g_regex_flags | ||||
lexer_conf.skip_validation = True | lexer_conf.skip_validation = True | ||||
lexer_conf.postlex = options.postlex | lexer_conf.postlex = options.postlex | ||||
return lexer_conf | |||||
@classmethod | |||||
def deserialize(cls, data, memo, lexer_conf, callbacks, options): | |||||
parser_conf = ParserConf.deserialize(data['parser_conf'], memo) | |||||
parser = LALR_Parser.deserialize(data['parser'], memo, callbacks, options.debug) | |||||
parser_conf.callbacks = callbacks | |||||
return ParsingFrontend(lexer_conf, parser_conf, options, parser=parser) | return ParsingFrontend(lexer_conf, parser_conf, options, parser=parser) | ||||
@@ -174,7 +174,7 @@ class TestParsers(unittest.TestCase): | |||||
for base in (Transformer, Transformer_InPlace, Transformer_NonRecursive, Transformer_InPlaceRecursive): | for base in (Transformer, Transformer_InPlace, Transformer_NonRecursive, Transformer_InPlaceRecursive): | ||||
class T(base): | class T(base): | ||||
def add(self, children): | def add(self, children): | ||||
return sum(children) | |||||
return sum(children if isinstance(children, list) else children.children) | |||||
def NUM(self, token): | def NUM(self, token): | ||||
return int(token) | return int(token) | ||||