Commit 94958f52 authored by Igor Dejanovic's avatar Igor Dejanovic

Bugfix in parser creation from peg description

Rules that consists of just a crossref to another rules were resolving
as a terminal rule down the chain. This fix will make a new rule as
a clone of the last rule down the chain but under a original rule name.
parent 94f4ed29
...@@ -8,8 +8,10 @@ ...@@ -8,8 +8,10 @@
####################################################################### #######################################################################
from __future__ import print_function from __future__ import print_function
import copy
from arpeggio import * from arpeggio import *
from arpeggio import RegExMatch as _ from arpeggio import RegExMatch as _
from arpeggio.export import PMDOTExporter, PTDOTExporter
__all__ = ['ParserPEG'] __all__ = ['ParserPEG']
...@@ -47,11 +49,19 @@ def expression(): return [regex, rule_crossref, ...@@ -47,11 +49,19 @@ def expression(): return [regex, rule_crossref,
# PEG Semantic Actions # PEG Semantic Actions
class PEGSemanticAction(SemanticAction): class PEGSemanticAction(SemanticAction):
def _resolve(self, parser, rule_name): def _resolve(self, parser, rule_name):
if rule_name in parser.peg_rules: if rule_name in parser.peg_rules:
resolved_rule = parser.peg_rules[rule_name]
if type(resolved_rule) is CrossRef:
resolved_rule = self._resolve(parser, resolved_rule.rule_name)
if parser.debug: if parser.debug:
print("Resolving reference {}".format(rule_name)) print("Resolving: CrossRef {} => {}".format(rule_name,
return parser.peg_rules[rule_name] resolved_rule.name))
return resolved_rule
else: else:
raise SemanticError("Rule \"{}\" does not exists." raise SemanticError("Rule \"{}\" does not exists."
.format(rule_name)) .format(rule_name))
...@@ -60,14 +70,30 @@ class PEGSemanticAction(SemanticAction): ...@@ -60,14 +70,30 @@ class PEGSemanticAction(SemanticAction):
''' '''
Resolving cross-references in second pass. Resolving cross-references in second pass.
''' '''
if isinstance(node, CrossRef): print("Second pass:", type(node), str(node))
return self._resolve(parser, node.rule_name)
elif isinstance(node, ParsingExpression): if isinstance(node, ParsingExpression):
for i, n in enumerate(node.nodes): for i, n in enumerate(node.nodes):
if isinstance(n, CrossRef): if isinstance(n, CrossRef):
node.nodes[i] = self._resolve(parser, n.rule_name) resolved_rule = self._resolve(parser, n.rule_name)
# If resolved rule hasn't got the same name it
# should be cloned and preserved in the peg_rules cache
if resolved_rule.rule != n.rule_name:
resolved_rule = copy.copy(resolved_rule)
resolved_rule.rule = n.rule_name
parser.peg_rules[resolved_rule.rule] = resolved_rule
if parser.debug:
print("Resolving: cloned to {} = > {}"\
.format(resolved_rule.rule, resolved_rule.name))
node.nodes[i] = resolved_rule
return node return node
else:
elif not isinstance(node, CrossRef):
raise SemanticError("Invalid type '{}'({}) after first pass." raise SemanticError("Invalid type '{}'({}) after first pass."
.format(type(node), str(node))) .format(type(node), str(node)))
...@@ -94,7 +120,6 @@ class SemRule(PEGSemanticAction): ...@@ -94,7 +120,6 @@ class SemRule(PEGSemanticAction):
# Keep a map of parser rules for cross reference # Keep a map of parser rules for cross reference
# resolving. # resolving.
parser.peg_rules[rule_name] = retval parser.peg_rules[rule_name] = retval
return retval return retval
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment