]> git.phdru.name Git - phdru.name/cgi-bin/blog-ru/search-tags.git/blobdiff - parser/parser.py
Use parsimonious instead of grako
[phdru.name/cgi-bin/blog-ru/search-tags.git] / parser / parser.py
old mode 100755 (executable)
new mode 100644 (file)
index a1dd034..dc562dd
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# CAVEAT UTILITOR
-#
-# This file was automatically generated by Grako.
-#
-#    https://pypi.python.org/pypi/grako/
-#
-# Any changes you make to it will be overwritten the next time
-# the file is generated.
-
-
-from __future__ import print_function, division, absolute_import, unicode_literals
-
-from grako.parsing import graken, Parser
-from grako.util import re, RE_FLAGS, generic_main  # noqa
-
-
-__version__ = (2016, 7, 11, 18, 15, 20, 0)
-
-__all__ = [
-    'TagsParser',
-    'TagsSemantics',
-    'main'
-]
-
-KEYWORDS = set([])
-
-
-class TagsParser(Parser):
-    def __init__(self,
-                 whitespace=None,
-                 nameguard=None,
-                 comments_re=None,
-                 eol_comments_re=None,
-                 ignorecase=None,
-                 left_recursion=True,
-                 keywords=KEYWORDS,
-                 namechars='',
-                 **kwargs):
-        super(TagsParser, self).__init__(
-            whitespace=whitespace,
-            nameguard=nameguard,
-            comments_re=comments_re,
-            eol_comments_re=eol_comments_re,
-            ignorecase=ignorecase,
-            left_recursion=left_recursion,
-            keywords=keywords,
-            namechars=namechars,
-            **kwargs
-        )
-
-    @graken()
-    def _start_(self):
-        self._expression_()
-        self._check_eof()
-
-    @graken()
-    def _expression_(self):
-        with self._choice():
-            with self._option():
-                self._expression1_()
-                with self._ifnot():
-                    self._or_op_()
-            with self._option():
-                self._or_expression_()
-            self._error('no available options')
-
-    @graken()
-    def _or_expression_(self):
-        self._expression1_()
-        self._or_op_()
-        self._expression_()
-
-    @graken()
-    def _and_expression_(self):
-        self._expression2_()
-        self._and_op_()
-        self._expression1_()
-
-    @graken()
-    def _not_expression_(self):
-        self._not_op_()
-        self._expression3_()
-
-    @graken()
-    def _parens_expression_(self):
-        self._token('(')
-        self._expression_()
-        self._token(')')
-
-    @graken()
-    def _expression1_(self):
-        with self._choice():
-            with self._option():
-                self._expression2_()
-                with self._ifnot():
-                    self._and_op_()
-            with self._option():
-                self._and_expression_()
-            self._error('no available options')
-
-    @graken()
-    def _expression2_(self):
-        with self._choice():
-            with self._option():
-                with self._ifnot():
-                    self._not_op_()
-                self._expression3_()
-            with self._option():
-                self._not_expression_()
-            self._error('no available options')
-
-    @graken()
-    def _expression3_(self):
-        with self._choice():
-            with self._option():
-                self._parens_expression_()
-            with self._option():
-                self._name_()
-            self._error('no available options')
-
-    @graken()
-    def _and_op_(self):
-        with self._choice():
-            with self._option():
-                self._token('&&')
-            with self._option():
-                self._token('&')
-            with self._option():
-                self._token('AND')
-            with self._option():
-                self._token('and')
-            self._error('expecting one of: & && AND and')
-
-    @graken()
-    def _or_op_(self):
-        with self._choice():
-            with self._option():
-                self._token('||')
-            with self._option():
-                self._token('|')
-            with self._option():
-                self._token('OR')
-            with self._option():
-                self._token('or')
-            self._error('expecting one of: OR or | ||')
-
-    @graken()
-    def _not_op_(self):
-        with self._choice():
-            with self._option():
-                self._token('!')
-            with self._option():
-                self._token('NOT')
-            with self._option():
-                self._token('not')
-            self._error('expecting one of: ! NOT not')
-
-    @graken()
-    def _name_(self):
-        self._pattern(r'[a-z][a-z0-9_]+')
-
-
-class TagsSemantics(object):
-    def start(self, ast):
-        return ast
-
-    def expression(self, ast):
-        return ast
-
-    def or_expression(self, ast):
-        return ast
-
-    def and_expression(self, ast):
-        return ast
-
-    def not_expression(self, ast):
-        return ast
-
-    def parens_expression(self, ast):
-        return ast
-
-    def expression1(self, ast):
-        return ast
-
-    def expression2(self, ast):
-        return ast
-
-    def expression3(self, ast):
-        return ast
-
-    def and_op(self, ast):
-        return ast
-
-    def or_op(self, ast):
-        return ast
-
-    def not_op(self, ast):
-        return ast
-
-    def name(self, ast):
-        return ast
-
-
-def main(
-        filename,
-        startrule,
-        trace=False,
-        whitespace=None,
-        nameguard=None,
-        comments_re=None,
-        eol_comments_re=None,
-        ignorecase=None,
-        left_recursion=True,
-        **kwargs):
-
-    with open(filename) as f:
-        text = f.read()
-    whitespace = whitespace or None
-    parser = TagsParser(parseinfo=False)
-    ast = parser.parse(
-        text,
-        startrule,
-        filename=filename,
-        trace=trace,
-        whitespace=whitespace,
-        nameguard=nameguard,
-        ignorecase=ignorecase,
-        **kwargs)
-    return ast
-
-if __name__ == '__main__':
-    import json
-    ast = generic_main(main, TagsParser, name='Tags')
-    print('AST:')
-    print(ast)
-    print()
-    print('JSON:')
-    print(json.dumps(ast, indent=2))
-    print()
+import os
+from parsimonious import Grammar, NodeVisitor
+
+
+# cache
+_grammar = None
+
+
+def load_grammar():
+    global _grammar
+    parser_dir = os.path.dirname(__file__)
+    with open(os.path.join(parser_dir, 'grammar.ebnf'), 'rt') as grammar_file:
+        grammar_text = grammar_file.read()
+    _grammar = Grammar(grammar_text)
+
+
+def parse(input):
+    if _grammar is None:
+        load_grammar()
+    return _grammar.parse(input)
+
+
+def cleanup_children(visited_children):
+    children = [c for c in visited_children if c]
+    if len(children) == 1:
+        return children[0]
+    else:
+        return children
+
+
+class Compiler(NodeVisitor):
+    def generic_visit(self, node, visited_children):
+        return cleanup_children(visited_children)
+
+    def visit_or_expression(self, node, visited_children):
+        return ('OR', visited_children[0], visited_children[2])
+
+    def visit_and_expression(self, node, visited_children):
+        return ('AND', visited_children[0], visited_children[2])
+
+    def visit_not_expression(self, node, visited_children):
+        return ('NOT', visited_children[2])
+
+    def visit_parens_expression(self, node, visited_children):
+        return ('PARENS', visited_children[2])
+
+    def visit_name(self, node, visited_children):
+        return ('NAME', node.text)
+
+
+def compile(tree):
+    if isinstance(tree, str):
+        tree = parse(tree)
+    return Compiler().visit(tree)