Commit 2274c67f authored by Igor Dejanovic's avatar Igor Dejanovic

Refactoring PEG support

parent 07519b00
......@@ -8,28 +8,15 @@
#######################################################################
from __future__ import print_function
from kivy.lang import ParserException
__all__ = ['ParserPEG']
from arpeggio import *
from arpeggio import RegExMatch as _
# PEG Grammar
def grammar(): return OneOrMore(rule), EOF
def rule(): return identifier, 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,(identifier, Not(LEFT_ARROW)),
(OPEN, ordered_choice, CLOSE),
literal]
def regex(): return "r'", _(r"(\\\'|[^\'])*"),"'"
def identifier(): return _(r"[a-zA-Z_]([a-zA-Z_]|[0-9])*")
#def literal(): return [_(r"\'(\\\'|[^\'])*\'"),_(r'"[^"]*"')]
def literal(): return _(r'(\'(\\\'|[^\'])*\')|("[^"]*")')
# PEG Lexical rules
def LEFT_ARROW(): return "<-"
def SLASH(): return "/"
def STAR(): return "*"
......@@ -39,22 +26,57 @@ def AND(): return "&"
def NOT(): return "!"
def OPEN(): return "("
def CLOSE(): return ")"
def regex(): return "r'", _(r"(\\\'|[^\'])*"),"'"
def rule_identifier(): return _(r"[a-zA-Z_]([a-zA-Z_]|[0-9])*")
#def literal(): return [_(r"\'(\\\'|[^\'])*\'"),_(r'"[^"]*"')]
def literal(): return _(r'(\'(\\\'|[^\'])*\')|("[^"]*")')
def comment(): return "//", _(".*\n")
# PEG syntax rules
def grammar(): return OneOrMore(rule), EOF
def rule(): return rule_identifier, 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_identifier, Not(LEFT_ARROW)),
(OPEN, ordered_choice, CLOSE),
literal]
# ------------------------------------------------------------------
# PEG Semantic Actions
class RuleReference(object):
'''
Used for rule reference resolving in the second
pass of the semantic analysis.
'''
def __init__(self, rule_name):
self.rule_name = rule_name
class PEGSemanticAction(SemanticAction):
def _resolve(self, parser, rule_name):
if rule_name in parser.peg_rules:
if parser.debug:
print("Resolving reference {}".format(rule_name))
return parser.peg_rules[rule_name]
else:
raise SemanticError("Rule \"{}\" does not exists."
.format(rule_name))
def second_pass(self, parser, node):
if isinstance(node, Terminal):
return
for i, n in enumerate(node.nodes):
if isinstance(n, Terminal):
if n.value in parser.peg_rules:
node.nodes[i] = parser.peg_rules[n.value]
else:
raise SemanticError("Rule \"%s\" does not exists." % n)
if isinstance(node, RuleReference):
return self._resolve(parser, node.rule_name)
elif isinstance(node, ParsingExpression):
for i, n in node.nodes.items():
if isinstance(n, RuleReference):
node[i] = self._resolve(parser, n.rule_name)
return node
else:
raise SemanticError("Invalid type '{}' after first pass."
.format(type(node)))
class SemGrammar(SemanticAction):
......@@ -64,7 +86,7 @@ class SemGrammar(SemanticAction):
class SemRule(PEGSemanticAction):
def first_pass(self, parser, node, children):
rule_name = children[0].value
rule_name = children[0]
if len(children) > 4:
retval = Sequence(nodes=children[2:-1])
else:
......@@ -99,8 +121,6 @@ class SemOrderedChoice(PEGSemanticAction):
class SemPrefix(PEGSemanticAction):
def first_pass(self, parser, node, children):
if parser.debug:
print("Prefix: {} ".format(str(children)))
if len(children) == 2:
if children[0] == NOT():
retval = Not()
......@@ -118,11 +138,7 @@ class SemPrefix(PEGSemanticAction):
class SemSufix(PEGSemanticAction):
def first_pass(self, parser, node, children):
if parser.debug:
print("Sufix : {}".format(str(children)))
if len(children) == 2:
if parser.debug:
print("Sufix : {}".format(str(children[1])))
if children[1] == STAR():
retval = ZeroOrMore(children[0])
elif children[1] == QUESTION():
......@@ -141,43 +157,30 @@ class SemSufix(PEGSemanticAction):
class SemExpression(PEGSemanticAction):
def first_pass(self, parser, node, children):
if parser.debug:
print("Expression : {}".format(str(children)))
if len(children) == 1:
return children[0]
else:
return children[1]
class SemIdentifier(SemanticAction):
class SemIdentifier(PEGSemanticAction):
def first_pass(self, parser, node, children):
if parser.debug:
print("Identifier {}.".format(node.value))
return node
return super(SemIdentifier, self).first_pass(parser, node, children)
class SemRegEx(SemanticAction):
def first_pass(self, parser, node, children):
if parser.debug:
print("RegEx {}.".format(children[1].value))
return RegExMatch(children[1].value)
return RegExMatch(children[1])
class SemLiteral(SemanticAction):
def first_pass(self, parser, node, children):
if parser.debug:
print("Literal: {}".format(node.value))
match_str = node.value[1:-1]
match_str = match_str.replace("\\'", "'")
match_str = match_str.replace("\\\\", "\\")
return StrMatch(match_str)
class SemTerminal(SemanticAction):
def first_pass(self, parser, node, children):
return StrMatch(node.value)
grammar.sem = SemGrammar()
rule.sem = SemRule()
ordered_choice.sem = SemOrderedChoice()
......@@ -186,10 +189,8 @@ prefix.sem = SemPrefix()
sufix.sem = SemSufix()
expression.sem = SemExpression()
regex.sem = SemRegEx()
identifier.sem = SemIdentifier()
rule_identifier.sem = SemIdentifier()
literal.sem = SemLiteral()
for sem in [LEFT_ARROW, SLASH, STAR, QUESTION, PLUS, AND, NOT, OPEN, CLOSE]:
sem.sem = SemTerminal()
class ParserPEG(Parser):
......@@ -210,7 +211,7 @@ class ParserPEG(Parser):
return self.parser_model.parse(self)
def _from_peg(self, language_def):
parser = ParserPython(grammar, comment)
parser = ParserPython(grammar, comment, reduce_tree=False, debug=True)
parser.root_rule_name = self.root_rule_name
parser.parse(language_def)
return parser.getASG()
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