Skip to content

Instantly share code, notes, and snippets.

@gkthiruvathukal
Created November 8, 2022 18:32
Show Gist options
  • Save gkthiruvathukal/3a24638cfe3dbff984594fe4a87a7266 to your computer and use it in GitHub Desktop.
Save gkthiruvathukal/3a24638cfe3dbff984594fe4a87a7266 to your computer and use it in GitHub Desktop.
Use Tatsu to get generic AST and create IR
#!/usr/bin/env python3
import tatsu
import json
from pprint import pprint
GRAMMAR = """@@grammar::ZQUERY
start = expression $ ;
expression
=
| or_expr
| term
;
or_expr
=
left:expression op:'|' right:term
;
term
=
| and_expr
| factor
;
and_expr
= left:term op:and_op right:factor
;
and_op
= op:'&'
| op:'!'
;
not_expr
= left:term op:'!' right:factor
;
factor
=
| '(' @:expression ')'
| z_field
;
z_field
= field:literal ':' text:literal
;
literal
= word:/"(\s+|\w+)*"/
| word:/\w+/
;
"""
from collections import namedtuple
Field = namedtuple("Field", ["field","text"])
OpNode = namedtuple("OpNode", ["op", "left", "right"])
class Semantics(object):
def literal(self, ast):
return ast.word
def z_field(self, ast):
return Field(ast.field, ast.text)
def and_expr(self, ast):
return OpNode(ast.op, ast.left, ast.right)
def and_op(self, ast):
return ast.op
def or_expr(self, ast):
return OpNode(ast.op, ast.left, ast.right)
def go():
parser = tatsu.compile(GRAMMAR)
#line = input("> ")
line = "subject:x & (title:urgent | title:whatever) | to:gkt"
# Semantics-free AST - parser can inject semantics (ZettelGeist shows how to do this)
ast = parser.parse(line)
print(ast)
ir = parser.parse(line, semantics=Semantics())
print(ir)
# Dump JSON just to get pretty-prineted "tree" representation
#print(json.dumps(ast, indent=3))
if __name__ == '__main__':
go()
@gkthiruvathukal
Copy link
Author

Output looks like this:

{'left': {'left': {'field': {'word': 'subject'}, 'text': {'word': 'x'}}, 'op': {'op': '&'}, 'right': {'left': {'field': {'word': 'title'}, 'text': {'word': 'urgent'}}, 'op': '|', 'right': {'field': {'word': 'title'}, 'text': {'word': 'whatever'}}}}, 'op': '|', 'right': {'field': {'word': 'to'}, 'text': {'word': 'gkt'}}}
OpNode(op='|', left=OpNode(op='&', left=Field(field='subject', text='x'), right=OpNode(op='|', left=Field(field='title', text='urgent'), right=Field(field='title', text='whatever'))), right=Field(field='to', text='gkt'))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment