+#! /usr/bin/env python3
+
import os
-from parsimonious import Grammar, NodeVisitor
+from lark import Lark, Transformer
+
+
+class TagsTransformer(Transformer):
+ def and_expression(self, items):
+ left = items[0]
+ right = items[2]
+ if len(items) > 3:
+ right = self.and_expression(items[2:])
+ return ('AND', left, right)
+
+ def or_expression(self, items):
+ left = items[0]
+ right = items[2]
+ if len(items) > 3:
+ right = self.or_expression(items[2:])
+ return ('OR', left, right)
+
+ def not_expression(self, items):
+ return ('NOT', items[1])
+
+ def expression_parens(self, items):
+ return ('PARENS', items[0])
+
+ def name(self, name):
+ return ('NAME', name[0].value)
# cache
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)
+ grammar_lines = [line for line in grammar_text.splitlines()
+ if not line.startswith('#')]
+ grammar_text = '\n'.join(grammar_lines)
+ _grammar = Lark(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)
+ tree = _grammar.parse(input)
+ return TagsTransformer().transform(tree)
+
+
+if __name__ == '__main__':
+ print('----------')
+ print(parse('test'))
+ print(parse('!test'))
+ print(parse('not test'))
+ print(parse('foo or bar'))
+ print(parse('foo && bar'))
+ print(parse('foo && bar && baz'))
+ print(parse('!foo && bar && baz'))
+ print(parse('(test)'))
+ print(parse('(foo || bar)'))
+ print(parse('(foo and !bar)'))
+ print('----------')