Commit 84aaae8f authored by Igor Dejanovic's avatar Igor Dejanovic

Fixing comment model in peg parsers. Some cleanups and docstring fixing.

parent 2c9baecf
...@@ -1381,13 +1381,27 @@ class CrossRef(object): ...@@ -1381,13 +1381,27 @@ class CrossRef(object):
class ParserPython(Parser): class ParserPython(Parser):
def __init__(self, language_def, comment_def=None, *args, **kwargs): def __init__(self, language_def, comment_def=None, *args, **kwargs):
"""
Constructs parser from python statements and expressions.
Args:
language_def (python function): A python function that defines
the root rule of the grammar.
comment_def (python function): A python function that defines
the root rule of the comments grammar.
"""
super(ParserPython, self).__init__(*args, **kwargs) super(ParserPython, self).__init__(*args, **kwargs)
# PEG Abstract Syntax Graph # PEG Abstract Syntax Graph
self.parser_model = self._from_python(language_def) self.parser_model = self._from_python(language_def)
self.comments_model = self._from_python(comment_def) \
if comment_def else None self.comments_model = None
if comment_def:
self.comments_model = self._from_python(comment_def)
self.comments_model.root = True
self.comments_model.rule_name = comment_def.__name__
# In debug mode export parser model to dot for # In debug mode export parser model to dot for
# visualization # visualization
...@@ -1397,11 +1411,6 @@ class ParserPython(Parser): ...@@ -1397,11 +1411,6 @@ class ParserPython(Parser):
PMDOTExporter().exportFile(self.parser_model, PMDOTExporter().exportFile(self.parser_model,
"{}_parser_model.dot".format(root_rule)) "{}_parser_model.dot".format(root_rule))
# Comments should be optional and there can be more of them
if self.comments_model:
self.comments_model.root = True
self.comments_model.rule_name = comment_def.__name__
def _parse(self): def _parse(self):
return self.parser_model.parse(self) return self.parser_model.parse(self)
......
...@@ -56,7 +56,7 @@ class ParserPEG(ParserPEGOrig): ...@@ -56,7 +56,7 @@ class ParserPEG(ParserPEGOrig):
parser.root_rule_name = self.root_rule_name parser.root_rule_name = self.root_rule_name
parse_tree = parser.parse(language_def) parse_tree = parser.parse(language_def)
# return parser.getASG(sem_actions=sem_actions)
return visit_parse_tree(parse_tree, PEGVisitor(self.root_rule_name, return visit_parse_tree(parse_tree, PEGVisitor(self.root_rule_name,
self.comment_rule_name,
self.ignore_case, self.ignore_case,
debug=self.debug)) debug=self.debug))
...@@ -51,10 +51,15 @@ def comment(): return "//", _(".*\n") ...@@ -51,10 +51,15 @@ def comment(): return "//", _(".*\n")
class PEGVisitor(PTNodeVisitor): class PEGVisitor(PTNodeVisitor):
"""
Visitor that transforms parse tree to a PEG parser for the given language.
"""
def __init__(self, root_rule_name, ignore_case, *args, **kwargs): def __init__(self, root_rule_name, comment_rule_name, ignore_case,
*args, **kwargs):
super(PEGVisitor, self).__init__(*args, **kwargs) super(PEGVisitor, self).__init__(*args, **kwargs)
self.root_rule_name = root_rule_name self.root_rule_name = root_rule_name
self.comment_rule_name = comment_rule_name
self.ignore_case = ignore_case self.ignore_case = ignore_case
# Used for linking phase # Used for linking phase
self.peg_rules = { self.peg_rules = {
...@@ -104,15 +109,17 @@ class PEGVisitor(PTNodeVisitor): ...@@ -104,15 +109,17 @@ class PEGVisitor(PTNodeVisitor):
self.resolved.add(node) self.resolved.add(node)
return node return node
# Find root rule # Find root and comment rules
self.resolved = set()
comment_rule = None
for rule in children: for rule in children:
if rule.rule_name == self.root_rule_name: if rule.rule_name == self.root_rule_name:
self.resolved = set() root_rule = _resolve(rule)
resolved_rule = _resolve(rule) if rule.rule_name == self.comment_rule_name:
comment_rule = _resolve(rule)
return resolved_rule
assert False, "Root rule not found!" assert root_rule, "Root rule not found!"
return root_rule, comment_rule
def visit_rule(self, node, children): def visit_rule(self, node, children):
rule_name = children[0] rule_name = children[0]
...@@ -194,13 +201,28 @@ class PEGVisitor(PTNodeVisitor): ...@@ -194,13 +201,28 @@ class PEGVisitor(PTNodeVisitor):
class ParserPEG(Parser): class ParserPEG(Parser):
def __init__(self, language_def, root_rule_name, comment_rule_name=None, def __init__(self, language_def, root_rule_name, comment_rule_name=None,
*args, **kwargs): *args, **kwargs):
"""
Constructs parser from textual PEG definition.
Args:
language_def (str): A string describing language grammar using
PEG notation.
root_rule_name(str): The name of the root rule.
comment_rule_name(str): The name of the rule for comments.
"""
super(ParserPEG, self).__init__(*args, **kwargs) super(ParserPEG, self).__init__(*args, **kwargs)
self.root_rule_name = root_rule_name self.root_rule_name = root_rule_name
self.comment_rule_name = comment_rule_name
# PEG Abstract Syntax Graph # PEG Abstract Syntax Graph
self.parser_model = self._from_peg(language_def) self.parser_model, self.comments_model = self._from_peg(language_def)
# Comments should be optional and there can be more of them
if self.comments_model:
self.comments_model.root = True
self.comments_model.rule_name = comment_rule_name
# In debug mode export parser model to dot for # In debug mode export parser model to dot for
# visualization # visualization
...@@ -210,11 +232,6 @@ class ParserPEG(Parser): ...@@ -210,11 +232,6 @@ class ParserPEG(Parser):
PMDOTExporter().exportFile( PMDOTExporter().exportFile(
self.parser_model, "{}_peg_parser_model.dot".format(root_rule)) self.parser_model, "{}_peg_parser_model.dot".format(root_rule))
# Comments should be optional and there can be more of them
if self.comments_model:
self.comments_model.root = True
self.comments_model.rule_name = comment_rule_name
def _parse(self): def _parse(self):
return self.parser_model.parse(self) return self.parser_model.parse(self)
...@@ -224,7 +241,7 @@ class ParserPEG(Parser): ...@@ -224,7 +241,7 @@ class ParserPEG(Parser):
parser.root_rule_name = self.root_rule_name parser.root_rule_name = self.root_rule_name
parse_tree = parser.parse(language_def) parse_tree = parser.parse(language_def)
# return parser.getASG(sem_actions=sem_actions)
return visit_parse_tree(parse_tree, PEGVisitor(self.root_rule_name, return visit_parse_tree(parse_tree, PEGVisitor(self.root_rule_name,
self.comment_rule_name,
self.ignore_case, self.ignore_case,
debug=self.debug)) debug=self.debug))
...@@ -63,19 +63,21 @@ def main(debug=False): ...@@ -63,19 +63,21 @@ def main(debug=False):
# ASG should be the same as parser.parser_model because semantic # ASG should be the same as parser.parser_model because semantic
# actions will create PEG parser (tree of ParsingExpressions). # actions will create PEG parser (tree of ParsingExpressions).
asg = visit_parse_tree(parse_tree, PEGVisitor(root_rule_name='peggrammar', parser_model, comment_model = visit_parse_tree(
ignore_case=False, parse_tree, PEGVisitor(root_rule_name='peggrammar',
debug=debug)) comment_rule_name='comment',
ignore_case=False,
debug=debug))
if debug: if debug:
# This graph should be the same as peg_peg_parser_model.dot because # This graph should be the same as peg_peg_parser_model.dot because
# they define the same parser. # they define the same parser.
PMDOTExporter().exportFile(asg, PMDOTExporter().exportFile(parser_model,
"peg_peg_asg.dot") "peg_peg_new_parser_model.dot")
# If we replace parser_mode with ASG constructed parser it will still # If we replace parser_mode with ASG constructed parser it will still
# parse PEG grammars # parse PEG grammars
parser.parser_model = asg parser.parser_model = parser_model
parser.parse(peg_grammar) parser.parse(peg_grammar)
if __name__ == '__main__': if __name__ == '__main__':
......
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