Commit 3eadb8fa authored by Igor Dejanovic's avatar Igor Dejanovic

PEG modules refactored to use visitor pattern in semantic analysis

parent c38397ff
......@@ -974,6 +974,7 @@ def visit_parse_tree(parse_tree, visitor):
if visitor.debug:
print("ASG: First pass")
# Visit tree.
result = parse_tree.visit(visitor)
......
......@@ -13,7 +13,7 @@ from __future__ import print_function, unicode_literals
from arpeggio import *
from arpeggio import RegExMatch as _
from .peg import sem_actions
from .peg import PEGVisitor
from .peg import ParserPEG as ParserPEGOrig
__all__ = ['ParserPEG']
......@@ -49,13 +49,14 @@ def comment(): return _("#.*\n")
class ParserPEG(ParserPEGOrig):
def _from_peg(self, language_def):
parser = ParserPython(peggrammar, comment, reduce_tree=False,
debug=self.debug)
parser.root_rule_name = self.root_rule_name
parser.parse(language_def)
# Initialise cross-ref counter
parser._crossref_cnt = 0
parse_tree = parser.parse(language_def)
return parser.getASG(sem_actions=sem_actions)
# return parser.getASG(sem_actions=sem_actions)
return visit_parse_tree(parse_tree, PEGVisitor(self.root_rule_name,
self.ignore_case,
debug=self.debug))
......@@ -3,7 +3,7 @@
# Name: peg.py
# Purpose: Implementing PEG language
# Author: Igor R. Dejanovic <igor DOT dejanovic AT gmail DOT com>
# Copyright: (c) 2009 Igor R. Dejanovic <igor DOT dejanovic AT gmail DOT com>
# Copyright: (c) 2009-2014 Igor R. Dejanovic <igor DOT dejanovic AT gmail DOT com>
# License: MIT License
#######################################################################
......@@ -49,32 +49,30 @@ def rule_crossref(): return rule_name
def str_match(): return _(r'(\'(\\\'|[^\'])*\')|("[^"]*")')
def comment(): return "//", _(".*\n")
# ------------------------------------------------------------------
# PEG Semantic Actions
class SemGrammar(SemanticAction):
def first_pass(self, parser, node, children):
# Find root rule
for rule in children:
if rule.rule_name == parser.root_rule_name:
self.resolved = set()
resolved_rule = self._resolve(parser, rule)
class PEGVisitor(PTNodeVisitor):
return resolved_rule
assert False, "Root rule not found!"
def __init__(self, root_rule_name, ignore_case, *args, **kwargs):
super(PEGVisitor, self).__init__(*args, **kwargs)
self.root_rule_name = root_rule_name
self.ignore_case = ignore_case
# Used for linking phase
self.peg_rules = {
"EOF": EndOfFile()
}
def _resolve(self, parser, node):
def visit_peggrammar(self, node, children):
def _resolve(node):
def get_rule_by_name(rule_name):
if rule_name in parser.peg_rules:
return parser.peg_rules[rule_name]
if rule_name in self.peg_rules:
return self.peg_rules[rule_name]
else:
raise SemanticError("Rule \"{}\" does not exists."
.format(rule_name))
def resolve_rule_by_name(rule_name):
if parser.debug:
if self.debug:
print("Resolving crossref {}".format(rule_name))
resolved_rule = get_rule_by_name(rule_name)
while type(resolved_rule) is CrossRef:
......@@ -85,8 +83,8 @@ class SemGrammar(SemanticAction):
if resolved_rule.rule_name != rule_name:
resolved_rule = copy.copy(resolved_rule)
resolved_rule.rule_name = rule_name
parser.peg_rules[rule_name] = resolved_rule
if parser.debug:
self.peg_rules[rule_name] = resolved_rule
if self.debug:
print("Resolving: cloned to {} = > {}"
.format(resolved_rule.rule_name,
resolved_rule.name))
......@@ -97,17 +95,28 @@ class SemGrammar(SemanticAction):
resolved_rule = resolve_rule_by_name(node.target_rule_name)
if resolved_rule not in self.resolved:
self.resolved.add(resolved_rule)
self._resolve(parser, resolved_rule)
_resolve(resolved_rule)
return resolved_rule
else:
# Resolve children nodes
for i, n in enumerate(node.nodes):
node.nodes[i] = self._resolve(parser, n)
node.nodes[i] = _resolve(n)
self.resolved.add(node)
return node
# Find root rule
for rule in children:
print("RULENODE", rule.rule_name, self.root_rule_name)
if rule.rule_name == self.root_rule_name:
print("ROOT", rule.rule_name)
self.resolved = set()
resolved_rule = _resolve(rule)
return resolved_rule
assert False, "Root rule not found!"
def sem_rule(parser, node, children):
def visit_rule(self, node, children):
rule_name = children[0]
if len(children) > 2:
retval = Sequence(nodes=children[1:])
......@@ -117,25 +126,19 @@ def sem_rule(parser, node, children):
retval.rule_name = rule_name
retval.root = True
if not hasattr(parser, "peg_rules"):
parser.peg_rules = {} # Used for linking phase
parser.peg_rules["EOF"] = EndOfFile()
# Keep a map of parser rules for cross reference
# resolving.
parser.peg_rules[rule_name] = retval
self.peg_rules[rule_name] = retval
return retval
def sem_sequence(parser, node, children):
def visit_sequence(self, node, children):
if len(children) > 1:
return Sequence(nodes=children[:])
else:
# If only one child rule exists reduce.
return children[0]
def sem_ordered_choice(parser, node, children):
def visit_ordered_choice(self, node, children):
if len(children) > 1:
retval = OrderedChoice(nodes=children[:])
else:
......@@ -143,8 +146,7 @@ def sem_ordered_choice(parser, node, children):
retval = children[0]
return retval
def sem_prefix(parser, node, children):
def visit_prefix(self, node, children):
if len(children) == 2:
if children[0] == NOT():
retval = Not()
......@@ -160,8 +162,7 @@ def sem_prefix(parser, node, children):
return retval
def sem_sufix(parser, node, children):
def visit_sufix(self, node, children):
if len(children) == 2:
if children[1] == STAR():
retval = ZeroOrMore(children[0])
......@@ -178,37 +179,20 @@ def sem_sufix(parser, node, children):
return retval
def sem_rule_crossref(parser, node, children):
def visit_rule_crossref(self, node, children):
return CrossRef(node.value)
def sem_regex(parser, node, children):
def visit_regex(self, node, children):
match = RegExMatch(children[0],
ignore_case=parser.ignore_case)
ignore_case=self.ignore_case)
match.compile()
return match
def sem_strmatch(parser, node, children):
def visit_str_match(self, node, children):
match_str = node.value[1:-1]
match_str = match_str.replace("\\'", "'")
match_str = match_str.replace("\\\\", "\\")
return StrMatch(match_str, ignore_case=parser.ignore_case)
sem_actions = {
'peggrammar': SemGrammar(),
'rule': sem_rule,
'sequence': sem_sequence,
'ordered_choice': sem_ordered_choice,
'prefix': sem_prefix,
'sufix': sem_sufix,
'rule_crossref': sem_rule_crossref,
'regex': sem_regex,
'str_match': sem_strmatch,
'expression': SemanticActionSingleChild(),
}
return StrMatch(match_str, ignore_case=self.ignore_case)
class ParserPEG(Parser):
......@@ -240,6 +224,9 @@ class ParserPEG(Parser):
parser = ParserPython(peggrammar, comment, reduce_tree=False,
debug=self.debug)
parser.root_rule_name = self.root_rule_name
parser.parse(language_def)
parse_tree = parser.parse(language_def)
return parser.getASG(sem_actions=sem_actions)
# return parser.getASG(sem_actions=sem_actions)
return visit_parse_tree(parse_tree, PEGVisitor(self.root_rule_name,
self.ignore_case,
debug=self.debug))
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