Skip to content

Commit 84a30ed

Browse files
committed
sketchy attempt at parsing expressions using pypeg2
1 parent 1be1a93 commit 84a30ed

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import re
2+
3+
import pypeg2
4+
5+
class SqlTemplatingSymbol(pypeg2.Symbol):
6+
def sql(self):
7+
return str(self.name)
8+
9+
class IntegerLiteral(SqlTemplatingSymbol):
10+
regex = re.compile(r'[0-9]+')
11+
12+
class DecimalLiteral(SqlTemplatingSymbol):
13+
regex = re.compile(r'[0-9]+\.[0-9]+')
14+
15+
def sql(self):
16+
return str(self.name) + "::DECIMAL"
17+
18+
class SingleQuotedStringLiteral(SqlTemplatingSymbol):
19+
regex = re.compile(r"'(?:\\.|[^'\n])*'")
20+
21+
class DoubleQuotedStringLiteral(SqlTemplatingSymbol):
22+
regex = re.compile(r'"(?:\\.|[^"\n])*"')
23+
24+
class Label(SqlTemplatingSymbol):
25+
regex = re.compile(r"[A-Za-z_][A-Za-z_0-9]*")
26+
27+
class SqlTemplatingList(pypeg2.List):
28+
before = ''
29+
between = ''
30+
after = ''
31+
32+
def sql(self):
33+
return self.before + self.between.join(s.sql() for s in self) + self.after
34+
35+
class ParenExpr(SqlTemplatingList):
36+
grammar = None # filled in later
37+
before = "("
38+
after = ")"
39+
40+
class FunctionName(SqlTemplatingSymbol):
41+
regex = re.compile(r'[a-z]+')
42+
43+
def __init__(self, name, namespace=None):
44+
print(f"FUNCTION NAME CHECK: {name}")
45+
if name not in ('hello'):
46+
raise ValueError("unknown function")
47+
super().__init__(name, namespace)
48+
49+
class FunctionCall(pypeg2.Concat):
50+
grammar = None # filled in later
51+
52+
def sql(self):
53+
return f"{self[0].sql()}({self[1].sql()})"
54+
55+
class Value(pypeg2.Concat):
56+
grammar = [FunctionCall, Label, DecimalLiteral, IntegerLiteral, SingleQuotedStringLiteral, DoubleQuotedStringLiteral, ParenExpr]
57+
58+
def sql(self):
59+
return self[0].sql()
60+
61+
FunctionCall.grammar = FunctionName, "(", Value, ")"
62+
63+
class UnaOp(SqlTemplatingSymbol):
64+
regex = re.compile(r"[+-]")
65+
66+
class UnaExpr(SqlTemplatingList):
67+
grammar = pypeg2.optional(UnaOp), Value
68+
69+
class PowOp(SqlTemplatingSymbol):
70+
regex = re.compile(r"\*\*")
71+
72+
class PowExpr(SqlTemplatingList):
73+
grammar = UnaExpr, pypeg2.maybe_some((PowOp, UnaExpr))
74+
75+
class MulOp(SqlTemplatingSymbol):
76+
regex = re.compile(r"[*/]")
77+
78+
class MulExpr(SqlTemplatingList):
79+
grammar = PowExpr, pypeg2.maybe_some((MulOp, PowExpr))
80+
81+
class AddOp(SqlTemplatingSymbol):
82+
regex = re.compile(r"[+-]")
83+
84+
class AddExpr(SqlTemplatingList):
85+
grammar = MulExpr, pypeg2.maybe_some((AddOp, MulExpr))
86+
87+
class NotOp(SqlTemplatingSymbol):
88+
regex = re.compile(r"not")
89+
90+
class NotExpr(SqlTemplatingList):
91+
grammar = pypeg2.maybe_some(NotOp), AddExpr
92+
93+
class AndExpr(SqlTemplatingList):
94+
grammar = NotExpr, pypeg2.maybe_some("and", NotExpr)
95+
between = ' AND '
96+
97+
class OrExpr(SqlTemplatingList):
98+
grammar = AndExpr, pypeg2.maybe_some("or", AndExpr)
99+
between = ' OR '
100+
101+
ParenExpr.grammar = "(", OrExpr, ")"
102+
103+
class Assignment(pypeg2.Concat):
104+
grammar = Label, "=", OrExpr
105+
106+
def sql(self):
107+
return self[1].sql() + " AS " + self[0].sql()
108+
109+
class Filter(pypeg2.Concat):
110+
# for backwards compatibility
111+
grammar = "__filter", "=", OrExpr
112+
113+
def sql(self):
114+
return self[0].sql()
115+
116+
class Block(pypeg2.Concat):
117+
grammar = pypeg2.some([Filter, Assignment, OrExpr])
118+
119+
def sql(self):
120+
selects = []
121+
wheres = []
122+
for s in self:
123+
if isinstance(s, Assignment):
124+
selects.append(s.sql())
125+
else:
126+
wheres.append(s.sql())
127+
128+
sql = f"SELECT {', '.join(selects)}"
129+
if wheres:
130+
sql += "WHERE { ' AND '.join(wheres) }"
131+
return sql
132+
133+
134+
block = r"""
135+
hello = "world"
136+
foo = 107+42/3.001
137+
baz = hello("quuux")
138+
ford = 10**2
139+
sdfklsdf = 10**-2
140+
"""
141+
142+
pp = pypeg2.parse(block, Block)
143+
144+
print(pp)
145+
print(pp.sql())
146+

0 commit comments

Comments
 (0)