Commit 2d460242 authored by Igor Dejanovic's avatar Igor Dejanovic

Fixing peg language

parent 8609d13a
...@@ -16,6 +16,17 @@ from arpeggio.export import PMDOTExporter, PTDOTExporter ...@@ -16,6 +16,17 @@ from arpeggio.export import PMDOTExporter, PTDOTExporter
__all__ = ['ParserPEG'] __all__ = ['ParserPEG']
# PEG syntax rules
def peggrammar(): return OneOrMore(rule), EOF
def rule(): return rule_name, LEFT_ARROW, ordered_choice, ";"
def ordered_choice(): return sequence, ZeroOrMore(SLASH, sequence)
def sequence(): return OneOrMore(prefix)
def prefix(): return Optional([AND,NOT]), sufix
def sufix(): return expression, Optional([QUESTION, STAR, PLUS])
def expression(): return [regex, rule_crossref,
(OPEN, ordered_choice, CLOSE),
str_match]
# PEG Lexical rules # PEG Lexical rules
def LEFT_ARROW(): return "<-" def LEFT_ARROW(): return "<-"
def SLASH(): return "/" def SLASH(): return "/"
...@@ -33,84 +44,73 @@ def rule_crossref(): return rule_name ...@@ -33,84 +44,73 @@ def rule_crossref(): return rule_name
def str_match(): return _(r'(\'(\\\'|[^\'])*\')|("[^"]*")') def str_match(): return _(r'(\'(\\\'|[^\'])*\')|("[^"]*")')
def comment(): return "//", _(".*\n") def comment(): return "//", _(".*\n")
# PEG syntax rules
def peggrammar(): return OneOrMore(rule), EOF
def rule(): return rule_name, LEFT_ARROW, ordered_choice, ";"
def ordered_choice(): return sequence, ZeroOrMore(SLASH, sequence)
def sequence(): return OneOrMore(prefix)
def prefix(): return Optional([AND,NOT]), sufix
def sufix(): return expression, Optional([QUESTION, STAR, PLUS])
def expression(): return [regex, rule_crossref,
(OPEN, ordered_choice, CLOSE),
str_match]
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# PEG Semantic Actions # PEG Semantic Actions
class PEGSemanticAction(SemanticAction): class SemGrammar(SemanticAction):
def _resolve(self, parser, rule_name):
if rule_name in parser.peg_rules: def first_pass(self, parser, node, children):
resolved_rule = parser.peg_rules[rule_name] return parser.peg_rules[parser.root_rule_name]
if type(resolved_rule) is CrossRef:
resolved_rule = self._resolve(parser, resolved_rule.rule_name)
if parser.debug: def _resolve(self, parser, node):
print("Resolving: CrossRef {} => {}".format(rule_name,
resolved_rule.name))
return resolved_rule def get_rule_by_name(rule_name):
if rule_name in parser.peg_rules:
return parser.peg_rules[rule_name]
else: else:
raise SemanticError("Rule \"{}\" does not exists." raise SemanticError("Rule \"{}\" does not exists."
.format(rule_name)) .format(n.rule_name))
def second_pass(self, parser, node):
'''
Resolving cross-references in second pass.
'''
if parser.debug:
print("Second pass:", type(node), str(node))
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):
resolved_rule = self._resolve(parser, n.rule_name) rule_name = n.rule_name
if parser.debug:
print("Resolving crossref {}".format(rule_name))
resolved_rule = get_rule_by_name(rule_name)
while type(resolved_rule) is CrossRef:
target_rule = resolved_rule.rule_name
resolved_rule = get_rule_by_name(target_rule)
# If resolved rule hasn't got the same name it # If resolved rule hasn't got the same name it
# should be cloned and preserved in the peg_rules cache # should be cloned and preserved in the peg_rules cache
if resolved_rule.rule_name != n.rule_name: if resolved_rule.rule_name != rule_name:
resolved_rule = copy.copy(resolved_rule) resolved_rule = copy.copy(resolved_rule)
resolved_rule.rule_name = n.rule_name resolved_rule.rule_name = rule_name
parser.peg_rules[resolved_rule.rule_name] = resolved_rule parser.peg_rules[rule_name] = resolved_rule
if parser.debug: if parser.debug:
print("Resolving: cloned to {} = > {}"\ print("Resolving: cloned to {} = > {}"\
.format(resolved_rule.rule_name, resolved_rule.name)) .format(resolved_rule.rule_name, resolved_rule.name))
node.nodes[i] = resolved_rule node.nodes[i] = resolved_rule
else:
resolved_rule = n
return node if not resolved_rule in self.resolved:
self.resolved.add(resolved_rule)
elif not isinstance(node, CrossRef): self._resolve(parser, resolved_rule)
raise SemanticError("Invalid type '{}'({}) after first pass."
.format(type(node), str(node)))
def second_pass(self, parser, node):
'''
Resolving cross-references in second pass.
'''
if parser.debug:
print("Second pass:", type(node), str(node))
class SemGrammar(SemanticAction): self.resolved = set()
def first_pass(self, parser, node, children): self._resolve(parser, node)
return parser.peg_rules[parser.root_rule_name] return node
peggrammar.sem = SemGrammar()
class SemRule(PEGSemanticAction): def sem_rule(parser, node, children):
def first_pass(self, parser, node, children):
rule_name = children[0] rule_name = children[0]
if len(children) > 2: if len(children) > 2:
retval = Sequence(nodes=children[1:]) retval = Sequence(nodes=children[1:])
else: else:
retval = children[1] retval = children[1]
# CrossRef already has rule_name set
# that attrib is a target rule name
if type(retval) is not CrossRef:
retval.rule_name = rule_name retval.rule_name = rule_name
retval.root = True retval.root = True
...@@ -122,29 +122,26 @@ class SemRule(PEGSemanticAction): ...@@ -122,29 +122,26 @@ class SemRule(PEGSemanticAction):
# resolving. # resolving.
parser.peg_rules[rule_name] = retval parser.peg_rules[rule_name] = retval
return retval return retval
rule.sem = sem_rule
def sem_sequence(parser, node, children):
class SemSequence(PEGSemanticAction):
def first_pass(self, parser, node, children):
if len(children) > 1: if len(children) > 1:
return Sequence(nodes=children[:]) return Sequence(nodes=children[:])
else: else:
# If only one child rule exists reduce. # If only one child rule exists reduce.
return children[0] return children[0]
sequence.sem = sem_sequence
def sem_ordered_choice(parser, node, children):
class SemOrderedChoice(PEGSemanticAction):
def first_pass(self, parser, node, children):
if len(children) > 1: if len(children) > 1:
retval = OrderedChoice(nodes=children[:]) retval = OrderedChoice(nodes=children[:])
else: else:
# If only one child rule exists reduce. # If only one child rule exists reduce.
retval = children[0] retval = children[0]
return retval return retval
ordered_choice.sem = sem_ordered_choice
def sem_prefix(parser, node, children):
class SemPrefix(PEGSemanticAction):
def first_pass(self, parser, node, children):
if len(children) == 2: if len(children) == 2:
if children[0] == NOT(): if children[0] == NOT():
retval = Not() retval = Not()
...@@ -159,10 +156,9 @@ class SemPrefix(PEGSemanticAction): ...@@ -159,10 +156,9 @@ class SemPrefix(PEGSemanticAction):
retval = children[0] retval = children[0]
return retval return retval
prefix.sem = sem_prefix
def sem_sufix(parser, node, children):
class SemSufix(PEGSemanticAction):
def first_pass(self, parser, node, children):
if len(children) == 2: if len(children) == 2:
if children[1] == STAR(): if children[1] == STAR():
retval = ZeroOrMore(children[0]) retval = ZeroOrMore(children[0])
...@@ -178,43 +174,27 @@ class SemSufix(PEGSemanticAction): ...@@ -178,43 +174,27 @@ class SemSufix(PEGSemanticAction):
retval = children[0] retval = children[0]
return retval return retval
sufix.sem = sem_sufix
def sem_rule_crossref(parser, node, children):
class SemExpression(PEGSemanticAction):
def first_pass(self, parser, node, children):
return children[0]
class SemRuleCrossRef(SemanticAction):
def first_pass(self, parser, node, children):
return CrossRef(node.value) return CrossRef(node.value)
rule_crossref.sem = sem_rule_crossref
def sem_regex(parser, node, children):
class SemRegEx(SemanticAction):
def first_pass(self, parser, node, children):
match = RegExMatch(children[0], match = RegExMatch(children[0],
ignore_case=parser.ignore_case) ignore_case=parser.ignore_case)
match.compile() match.compile()
return match return match
regex.sem = sem_regex
class SemStrMatch(SemanticAction): def sem_strmatch(parser, node, children):
def first_pass(self, parser, node, children):
match_str = node.value[1:-1] match_str = node.value[1:-1]
match_str = match_str.replace("\\'", "'") match_str = match_str.replace("\\'", "'")
match_str = match_str.replace("\\\\", "\\") match_str = match_str.replace("\\\\", "\\")
return StrMatch(match_str, ignore_case=parser.ignore_case) return StrMatch(match_str, ignore_case=parser.ignore_case)
str_match.sem = sem_strmatch
expression.sem = SemanticActionSingleChild()
peggrammar.sem = SemGrammar()
rule.sem = SemRule()
ordered_choice.sem = SemOrderedChoice()
sequence.sem = SemSequence()
prefix.sem = SemPrefix()
sufix.sem = SemSufix()
expression.sem = SemExpression()
rule_crossref.sem = SemRuleCrossRef()
regex.sem = SemRegEx()
str_match.sem = SemStrMatch()
class ParserPEG(Parser): class ParserPEG(Parser):
......
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