Nix flake for RPython interpreters
Revisão | 7ec0ccb963f6940059592ce24d7c6bc667fd2718 (tree) |
---|---|
Hora | 2024-04-30 15:44:34 |
Autor | Corbin <cds@corb...> |
Commiter | Corbin |
regiux: Split parser.
@@ -1,360 +1,6 @@ | ||
1 | 1 | import sys |
2 | 2 | |
3 | -from rpython.rlib.objectmodel import we_are_translated | |
4 | -from rpython.rlib.rsre import rsre_core | |
5 | -from rpython.rlib.rsre.rpy import get_code | |
6 | - | |
7 | -import rply | |
8 | -from rply.token import BaseBox | |
9 | - | |
10 | -lg = rply.LexerGenerator() | |
11 | - | |
12 | -KEYWORDS = "IF THEN ELSE ASSERT WITH LET REC INHERIT OR IN".split() | |
13 | -for kw in KEYWORDS: lg.add(kw, kw.lower()) | |
14 | - | |
15 | -lg.add("ELLIPSIS", "\.\.\.") | |
16 | -lg.add("EQ", "\=\=") | |
17 | -lg.add("NEQ", "\!\=") | |
18 | -lg.add("LEQ", "\<\=") | |
19 | -lg.add("LE", "\<") | |
20 | -lg.add("GEQ", "\>\=") | |
21 | -lg.add("GE", "\>") | |
22 | -lg.add("AND", "\&\&") | |
23 | -lg.add("OR_OP", "\|\|") | |
24 | -lg.add("IMPL", "\-\>") | |
25 | -lg.add("UPDATE", "\/\/") | |
26 | -lg.add("CONCAT", "\+\+") | |
27 | -lg.add("PLUS", "\+") | |
28 | -lg.add("MINUS", "-") | |
29 | -lg.add("MUL", "\*") | |
30 | -lg.add("DIV", "\/") | |
31 | -lg.add("NOT", "!") | |
32 | -lg.add("HAS", "\?") | |
33 | - | |
34 | -lg.add("COLON", ":") | |
35 | -lg.add("SEMI", ";") | |
36 | -lg.add("OPEN_BRACE", "\{") | |
37 | -lg.add("CLOSE_BRACE", "\}") | |
38 | -lg.add("OPEN_BRACK", "\[") | |
39 | -lg.add("CLOSE_BRACK", "\]") | |
40 | -lg.add("OPEN_PAREN", "\(") | |
41 | -lg.add("CLOSE_PAREN", "\)") | |
42 | -lg.add("DOT", "\.") | |
43 | -lg.add("COMMA", ",") | |
44 | -lg.add("AT", "@") | |
45 | -lg.add("EQUALS", "\=") | |
46 | - | |
47 | -PATH_CHAR = "[a-zA-Z0-9\.\_\-\+]" | |
48 | -lg.add("URI", "[a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+") | |
49 | -lg.add("ID", "[a-zA-Z\_][a-zA-Z0-9\_\'\-]*") | |
50 | -lg.add("INT", "[0-9]+") | |
51 | -lg.add("FLOAT", "(([1-9][0-9]*\.[0-9]*)|(0?\.[0-9]+))([Ee][+-]?[0-9]+)?") | |
52 | -lg.add("PATH_CHAR", PATH_CHAR) | |
53 | -lg.add("PATH", "{0}*(\/{0}+)+\/?".format(PATH_CHAR)) | |
54 | -lg.add("PATH_SEG", "{0}*\/".format(PATH_CHAR)) | |
55 | -lg.add("HPATH", "\~(\/{0}+)+\/?".format(PATH_CHAR)) | |
56 | -lg.add("HPATH_START", "\~\/") | |
57 | -lg.add("SPATH", "\<{0}+(\/{0}+)*\>".format(PATH_CHAR)) | |
58 | - | |
59 | -lg.ignore("[ \t\r\n]+") | |
60 | -lg.ignore("#[^\r\n]*") | |
61 | -lg.ignore("\/\*([^*]|\*+[^*/])*\*+\/") | |
62 | - | |
63 | -lexer = lg.build() | |
64 | - | |
65 | -# Syntactic classes: | |
66 | -# * exprs | |
67 | -# * formal params | |
68 | -# * attrs | |
69 | - | |
70 | -class FormalBox(BaseBox): | |
71 | - def __init__(self, name, default): | |
72 | - self.name = name | |
73 | - self.default = default | |
74 | - def pretty(self): | |
75 | - if self.default is None: | |
76 | - return self.name | |
77 | - else: | |
78 | - return "%s ? %s" % (self.name, self.default.pretty()) | |
79 | - | |
80 | -class BindsBox(BaseBox): | |
81 | - def __init__(self, binds): self.binds = binds | |
82 | - def pretty(self): | |
83 | - binds = [bind.pretty() for bind in self.binds] | |
84 | - return "{ %s }" % " ".join(binds) | |
85 | - def getbinds(self): return self.binds | |
86 | - | |
87 | -class BindExprBox(BaseBox): | |
88 | - def __init__(self, path, expr): | |
89 | - self.path = path | |
90 | - self.expr = expr | |
91 | - def pretty(self): return "%s = %s;" % (self.path.pretty(), self.expr.pretty()) | |
92 | - | |
93 | -class BindInheritBox(BaseBox): | |
94 | - def __init__(self, attrs, scope): | |
95 | - self.attrs = attrs | |
96 | - self.scope = scope | |
97 | - def pretty(self): | |
98 | - if self.scope: | |
99 | - return "inherit (%s) %s;" % (self.scope.pretty(), self.attrs.pretty()) | |
100 | - else: return "inherit %s;" % self.attrs.pretty() | |
101 | - | |
102 | -class FormalsBox(BaseBox): | |
103 | - def __init__(self, params, hasEllipsis): | |
104 | - self.params = params | |
105 | - self.hasEllipsis = hasEllipsis | |
106 | - def pretty(self): | |
107 | - params = [param.pretty() for param in self.params] | |
108 | - if self.hasEllipsis: params.append("...") | |
109 | - return "{ %s }" % ", ".join(params) | |
110 | - def getparams(self): return self.params | |
111 | - def getellipsis(self): return self.hasEllipsis | |
112 | - | |
113 | -class VarBox(BaseBox): | |
114 | - def __init__(self, name): self.name = name | |
115 | - def pretty(self): return self.name | |
116 | - | |
117 | -class AttrPathBox(BaseBox): | |
118 | - def __init__(self, attrs): self.attrs = attrs | |
119 | - def pretty(self): return ".".join([attr.pretty() for attr in self.attrs]) | |
120 | - def getattrs(self): return self.attrs | |
121 | - | |
122 | -class AttrsBox(BaseBox): | |
123 | - def __init__(self, attrs): self.attrs = attrs | |
124 | - def pretty(self): return " ".join([attr.pretty() for attr in self.attrs]) | |
125 | - def getattrs(self): return self.attrs | |
126 | - | |
127 | -class ListBox(BaseBox): | |
128 | - def __init__(self, exprs): self.exprs = exprs | |
129 | - def pretty(self): | |
130 | - return "[ %s ]" % " ".join([expr.pretty() for expr in self.exprs]) | |
131 | - def getexprs(self): return self.exprs | |
132 | - | |
133 | -class IntBox(BaseBox): | |
134 | - def __init__(self, value): self.value = value | |
135 | - def pretty(self): return str(self.value) | |
136 | - | |
137 | -class StrBox(BaseBox): | |
138 | - def __init__(self, value): self.value = value | |
139 | - def pretty(self): return '"%s"' % self.value | |
140 | - | |
141 | -class ExprUnaryBox(BaseBox): | |
142 | - def __init__(self, expr, op): | |
143 | - self.expr = expr | |
144 | - self.op = op.getstr() | |
145 | - def pretty(self): | |
146 | - return "(%s%s)" % (self.op, self.expr.pretty()) | |
147 | - | |
148 | -class SelectBox(BaseBox): | |
149 | - def __init__(self, expr, path, alt): | |
150 | - self.expr = expr | |
151 | - self.path = path | |
152 | - self.alt = alt | |
153 | - def pretty(self): | |
154 | - if self.alt is None: | |
155 | - return "%s.%s" % (self.expr.pretty(), self.path.pretty()) | |
156 | - else: | |
157 | - return "%s.%s or %s" % (self.expr.pretty(), self.path.pretty(), self.alt.pretty()) | |
158 | - | |
159 | -class ExprBinaryBox(BaseBox): | |
160 | - def __init__(self, left, right, op): | |
161 | - self.left = left | |
162 | - self.right = right | |
163 | - self.op = op.getstr() | |
164 | - def pretty(self): | |
165 | - return "(%s %s %s)" % (self.left.pretty(), self.op, self.right.pretty()) | |
166 | - | |
167 | -class HasBox(BaseBox): | |
168 | - def __init__(self, value, path): | |
169 | - self.value = value | |
170 | - self.path = path | |
171 | - def pretty(self): | |
172 | - return "(%s ? %s)" % (self.value.pretty(), self.path.pretty()) | |
173 | - | |
174 | -class AssertBox(BaseBox): | |
175 | - def __init__(self, cond, expr): | |
176 | - self.cond = cond | |
177 | - self.expr = expr | |
178 | - def pretty(self): return "assert %s; %s" % (self.cond.pretty(), self.expr.pretty()) | |
179 | - | |
180 | -class WithBox(BaseBox): | |
181 | - def __init__(self, scope, expr): | |
182 | - self.scope = scope | |
183 | - self.expr = expr | |
184 | - def pretty(self): return "with %s; %s" % (self.scope.pretty(), self.expr.pretty()) | |
185 | - | |
186 | -class LambdaBox(BaseBox): | |
187 | - def __init__(self, binding, params, body): | |
188 | - self.binding = binding | |
189 | - self.params = params | |
190 | - self.body = body | |
191 | - def pretty(self): | |
192 | - body = self.body.pretty() | |
193 | - if self.binding and self.params: | |
194 | - return "%s@%s: %s" % (self.binding.pretty(), self.params.pretty(), body) | |
195 | - elif self.binding: return "%s: %s" % (self.binding.pretty(), body) | |
196 | - elif self.params: return "%s: %s" % (self.params.pretty(), body) | |
197 | - else: return "_: " + body | |
198 | - | |
199 | -class AppBox(BaseBox): | |
200 | - def __init__(self, func, arg): | |
201 | - self.func = func | |
202 | - self.arg = arg | |
203 | - def pretty(self): return "(%s) (%s)" % (self.func.pretty(), self.arg.pretty()) | |
204 | - | |
205 | -class IfBox(BaseBox): | |
206 | - def __init__(self, cond, seq, alt): | |
207 | - self.cond = cond | |
208 | - self.seq = seq | |
209 | - self.alt = alt | |
210 | - def pretty(self): | |
211 | - return "if %s then %s else %s" % ( | |
212 | - self.cond.pretty(), self.seq.pretty(), self.alt.pretty()) | |
213 | - | |
214 | -pg = rply.ParserGenerator(KEYWORDS + [ | |
215 | - "ID", "INT", "SPATH", "URI", | |
216 | - "AND", "IMPL", "OR_OP", | |
217 | - "EQ", "NEQ", "LE", "GE", "LEQ", "GEQ", "HAS", | |
218 | - "CONCAT", "UPDATE", | |
219 | - "DIV", "MINUS", "MUL", "PLUS", | |
220 | - "NEGATE", "NOT", | |
221 | - "COLON", "SEMI", "DOT", "COMMA", "AT", "EQUALS", "ELLIPSIS", | |
222 | - "OPEN_BRACE", "CLOSE_BRACE", "OPEN_BRACK", "CLOSE_BRACK", "OPEN_PAREN", "CLOSE_PAREN", | |
223 | -], precedence=[ | |
224 | - ("right", ["IMPL"]), | |
225 | - ("left", ["OR_OP"]), | |
226 | - ("left", ["AND"]), | |
227 | - ("nonassoc", ["EQ", "NEQ"]), | |
228 | - ("nonassoc", ["LE", "GE", "LEQ", "GEQ"]), | |
229 | - ("right", ["UPDATE"]), | |
230 | - ("left", ["NOT"]), | |
231 | - ("left", ["PLUS", "MINUS"]), | |
232 | - ("left", ["MUL", "DIV"]), | |
233 | - ("right", ["CONCAT"]), | |
234 | - ("nonassoc", ["HAS"]), | |
235 | - ("nonassoc", ["NEGATE"]), | |
236 | -]) | |
237 | - | |
238 | -class ParseError(Exception): | |
239 | - def __init__(self, token): self.token = token | |
240 | - | |
241 | -@pg.error | |
242 | -def parseError(token): raise ParseError(token) | |
243 | - | |
244 | -def constRule(rule, pb): pg.production(rule)(lambda _: pb) | |
245 | -def enclosedRule(rule, i): pg.production(rule)(lambda p: p[i]) | |
246 | -def precRule(sup, sub): enclosedRule("expr%s : expr%s" % (sup, sub), 0) | |
247 | -SPINE = "", "_function", "_if", "_op", "_app", "_select", "_simple" | |
248 | -for sup, sub in zip(SPINE, SPINE[1:]): precRule(sup, sub) | |
249 | - | |
250 | -@pg.production("expr_function : ID COLON expr_function") | |
251 | -def exprLambda(p): return LambdaBox(VarBox(p[0].getstr()), None, p[2]) | |
252 | - | |
253 | -@pg.production("expr_function : OPEN_BRACE formals CLOSE_BRACE COLON expr_function") | |
254 | -def exprLambda(p): return LambdaBox(None, p[1], p[4]) | |
255 | - | |
256 | -@pg.production("expr_function : OPEN_BRACE formals CLOSE_BRACE AT ID COLON expr_function") | |
257 | -def exprLambda(p): return LambdaBox(VarBox(p[4].getstr()), p[1], p[6]) | |
258 | - | |
259 | -@pg.production("expr_function : ID AT OPEN_BRACE formals CLOSE_BRACE COLON expr_function") | |
260 | -def exprLambda(p): return LambdaBox(VarBox(p[0].getstr()), p[3], p[6]) | |
261 | - | |
262 | -@pg.production("expr_function : ASSERT expr SEMI expr_function") | |
263 | -def exprAssert(p): return AssertBox(p[1], p[3]) | |
264 | - | |
265 | -@pg.production("expr_function : WITH expr SEMI expr_function") | |
266 | -def exprWith(p): return WithBox(p[1], p[3]) | |
267 | - | |
268 | -@pg.production("expr_if : IF expr THEN expr ELSE expr") | |
269 | -def exprIf(p): return IfBox(p[1], p[3], p[5]) | |
270 | - | |
271 | -@pg.production("expr_op : NEGATE expr_op | NOT expr_op") | |
272 | -def exprUnary(p): return ExprUnaryBox(p[1], p[0]) | |
273 | - | |
274 | -@pg.production("expr_op : expr_op AND expr_op") | |
275 | -@pg.production("expr_op : expr_op CONCAT expr_op") | |
276 | -@pg.production("expr_op : expr_op DIV expr_op") | |
277 | -@pg.production("expr_op : expr_op EQ expr_op") | |
278 | -@pg.production("expr_op : expr_op GE expr_op") | |
279 | -@pg.production("expr_op : expr_op GEQ expr_op") | |
280 | -@pg.production("expr_op : expr_op IMPL expr_op") | |
281 | -@pg.production("expr_op : expr_op LE expr_op") | |
282 | -@pg.production("expr_op : expr_op LEQ expr_op") | |
283 | -@pg.production("expr_op : expr_op MINUS expr_op") | |
284 | -@pg.production("expr_op : expr_op MUL expr_op") | |
285 | -@pg.production("expr_op : expr_op NEQ expr_op") | |
286 | -@pg.production("expr_op : expr_op OR_OP expr_op") | |
287 | -@pg.production("expr_op : expr_op PLUS expr_op") | |
288 | -@pg.production("expr_op : expr_op UPDATE expr_op") | |
289 | -def exprBinary(p): return ExprBinaryBox(p[0], p[2], p[1]) | |
290 | - | |
291 | -@pg.production("expr_op : expr_op HAS attrpath") | |
292 | -def exprHas(p): return HasBox(p[0], p[2]) | |
293 | - | |
294 | -@pg.production("expr_app : expr_app expr_select") | |
295 | -def exprApp(p): return AppBox(p[0], p[1]) | |
296 | - | |
297 | -@pg.production("expr_select : expr_simple DOT attrpath | expr_simple DOT attrpath OR expr_select") | |
298 | -def exprSelect(p): return SelectBox(p[0], p[2], p[4] if len(p) == 5 else None) | |
299 | - | |
300 | -@pg.production("expr_simple : ID") | |
301 | -def exprSimpleId(p): return VarBox(p[0].getstr()) | |
302 | - | |
303 | -@pg.production("expr_simple : INT") | |
304 | -def exprSimpleInt(p): return IntBox(int(p[0].getstr())) | |
305 | - | |
306 | -@pg.production("expr_simple : URI") | |
307 | -def exprURI(p): return StrBox(p[0].getstr()) | |
308 | - | |
309 | -enclosedRule("expr_simple : OPEN_BRACE binds CLOSE_BRACE", 1) | |
310 | -enclosedRule("expr_simple : OPEN_PAREN expr CLOSE_PAREN", 1) | |
311 | -enclosedRule("expr_simple : OPEN_BRACK expr_list CLOSE_BRACK", 1) | |
312 | -constRule("expr_list :", ListBox([])) | |
313 | - | |
314 | -@pg.production("expr_list : expr_list expr_select") | |
315 | -def exprListCons(p): return ListBox(p[0].getexprs() + [p[1]]) | |
316 | - | |
317 | -@pg.production("binds : binds attrpath EQUALS expr SEMI") | |
318 | -def bindsExpr(p): return BindsBox(p[0].getbinds() + [BindExprBox(p[1], p[3])]) | |
319 | - | |
320 | -@pg.production("binds : binds INHERIT attrs SEMI") | |
321 | -def bindsInherit(p): | |
322 | - return BindsBox(p[0].getbinds() + [BindInheritBox(p[2], None)]) | |
323 | - | |
324 | -@pg.production("binds : binds INHERIT OPEN_PAREN expr CLOSE_PAREN attrs SEMI") | |
325 | -def bindsInherit(p): | |
326 | - return BindsBox(p[0].getbinds() + [BindInheritBox(p[5], p[3])]) | |
327 | - | |
328 | -constRule("binds :", BindsBox([])) | |
329 | - | |
330 | -@pg.production("formals : formal COMMA formals") | |
331 | -def formalsComma(p): | |
332 | - return FormalsBox([p[0]] + p[2].getparams(), p[2].getellipsis()) | |
333 | - | |
334 | -@pg.production("formals : formal") | |
335 | -def formalsFormal(p): return FormalsBox([p[0]], False) | |
336 | - | |
337 | -constRule("formals :", FormalsBox([], False)) | |
338 | -constRule("formals : ELLIPSIS", FormalsBox([], True)) | |
339 | - | |
340 | -@pg.production("formal : ID | ID HAS expr") | |
341 | -def formalId(p): return FormalBox(p[0].getstr(), p[2] if len(p) > 1 else None) | |
342 | - | |
343 | -@pg.production("attrs : attrs attr") | |
344 | -def attrsAttr(p): return AttrsBox(p[0].getattrs() + [p[1]]) | |
345 | - | |
346 | -constRule("attrs :", AttrsBox([])) | |
347 | - | |
348 | -@pg.production("attrpath : attrpath DOT attr") | |
349 | -def attrpathNil(p): return AttrPathBox(p[0].getattrs() + [p[2]]) | |
350 | - | |
351 | -@pg.production("attrpath : attr") | |
352 | -def attrpathCons(p): return AttrPathBox(p) | |
353 | - | |
354 | -@pg.production("attr : ID") | |
355 | -def attrId(p): return StrBox(p[0].getstr()) | |
356 | - | |
357 | -parser = pg.build() | |
3 | +from parser import parse, ParseError | |
358 | 4 | |
359 | 5 | def entryPoint(argv): |
360 | 6 | if len(argv) < 2: |
@@ -363,8 +9,7 @@ def entryPoint(argv): | ||
363 | 9 | path = argv[1] |
364 | 10 | with open(path, "rb") as handle: expr = handle.read() |
365 | 11 | try: |
366 | - ast = parser.parse(lexer.lex(expr)) | |
367 | - print "Success" | |
12 | + ast = parse(expr) | |
368 | 13 | print "AST:", ast |
369 | 14 | print ast.pretty() |
370 | 15 | return 0 |
@@ -380,5 +25,3 @@ def entryPoint(argv): | ||
380 | 25 | def target(*args): return entryPoint, None |
381 | 26 | |
382 | 27 | if __name__ == "__main__": entryPoint(sys.argv) |
383 | - | |
384 | -# 456 + 293 = 749 |
@@ -0,0 +1,358 @@ | ||
1 | +import rply | |
2 | +from rply.token import BaseBox | |
3 | + | |
4 | +# A basic Nix parser ported from CppNix. | |
5 | +# LoC target: | |
6 | +# 456 (parser.y) + 293 (lexer.l) = 749 | |
7 | + | |
8 | +lg = rply.LexerGenerator() | |
9 | + | |
10 | +KEYWORDS = "IF THEN ELSE ASSERT WITH LET REC INHERIT OR IN".split() | |
11 | +for kw in KEYWORDS: lg.add(kw, kw.lower()) | |
12 | + | |
13 | +lg.add("ELLIPSIS", "\.\.\.") | |
14 | +lg.add("EQ", "\=\=") | |
15 | +lg.add("NEQ", "\!\=") | |
16 | +lg.add("LEQ", "\<\=") | |
17 | +lg.add("LE", "\<") | |
18 | +lg.add("GEQ", "\>\=") | |
19 | +lg.add("GE", "\>") | |
20 | +lg.add("AND", "\&\&") | |
21 | +lg.add("OR_OP", "\|\|") | |
22 | +lg.add("IMPL", "\-\>") | |
23 | +lg.add("UPDATE", "\/\/") | |
24 | +lg.add("CONCAT", "\+\+") | |
25 | +lg.add("PLUS", "\+") | |
26 | +lg.add("MINUS", "-") | |
27 | +lg.add("MUL", "\*") | |
28 | +lg.add("DIV", "\/") | |
29 | +lg.add("NOT", "!") | |
30 | +lg.add("HAS", "\?") | |
31 | + | |
32 | +lg.add("COLON", ":") | |
33 | +lg.add("SEMI", ";") | |
34 | +lg.add("OPEN_BRACE", "\{") | |
35 | +lg.add("CLOSE_BRACE", "\}") | |
36 | +lg.add("OPEN_BRACK", "\[") | |
37 | +lg.add("CLOSE_BRACK", "\]") | |
38 | +lg.add("OPEN_PAREN", "\(") | |
39 | +lg.add("CLOSE_PAREN", "\)") | |
40 | +lg.add("DOT", "\.") | |
41 | +lg.add("COMMA", ",") | |
42 | +lg.add("AT", "@") | |
43 | +lg.add("EQUALS", "\=") | |
44 | + | |
45 | +PATH_CHAR = "[a-zA-Z0-9\.\_\-\+]" | |
46 | +lg.add("URI", "[a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+") | |
47 | +lg.add("ID", "[a-zA-Z\_][a-zA-Z0-9\_\'\-]*") | |
48 | +lg.add("INT", "[0-9]+") | |
49 | +lg.add("FLOAT", "(([1-9][0-9]*\.[0-9]*)|(0?\.[0-9]+))([Ee][+-]?[0-9]+)?") | |
50 | +lg.add("PATH_CHAR", PATH_CHAR) | |
51 | +lg.add("PATH", "{0}*(\/{0}+)+\/?".format(PATH_CHAR)) | |
52 | +lg.add("PATH_SEG", "{0}*\/".format(PATH_CHAR)) | |
53 | +lg.add("HPATH", "\~(\/{0}+)+\/?".format(PATH_CHAR)) | |
54 | +lg.add("HPATH_START", "\~\/") | |
55 | +lg.add("SPATH", "\<{0}+(\/{0}+)*\>".format(PATH_CHAR)) | |
56 | + | |
57 | +lg.ignore("[ \t\r\n]+") | |
58 | +lg.ignore("#[^\r\n]*") | |
59 | +lg.ignore("\/\*([^*]|\*+[^*/])*\*+\/") | |
60 | + | |
61 | +lexer = lg.build() | |
62 | + | |
63 | +# Syntactic classes: | |
64 | +# * exprs | |
65 | +# * formal params | |
66 | +# * attrs | |
67 | + | |
68 | +class FormalBox(BaseBox): | |
69 | + def __init__(self, name, default): | |
70 | + self.name = name | |
71 | + self.default = default | |
72 | + def pretty(self): | |
73 | + if self.default is None: | |
74 | + return self.name | |
75 | + else: | |
76 | + return "%s ? %s" % (self.name, self.default.pretty()) | |
77 | + | |
78 | +class BindsBox(BaseBox): | |
79 | + def __init__(self, binds): self.binds = binds | |
80 | + def pretty(self): | |
81 | + binds = [bind.pretty() for bind in self.binds] | |
82 | + return "{ %s }" % " ".join(binds) | |
83 | + def getbinds(self): return self.binds | |
84 | + | |
85 | +class BindExprBox(BaseBox): | |
86 | + def __init__(self, path, expr): | |
87 | + self.path = path | |
88 | + self.expr = expr | |
89 | + def pretty(self): return "%s = %s;" % (self.path.pretty(), self.expr.pretty()) | |
90 | + | |
91 | +class BindInheritBox(BaseBox): | |
92 | + def __init__(self, attrs, scope): | |
93 | + self.attrs = attrs | |
94 | + self.scope = scope | |
95 | + def pretty(self): | |
96 | + if self.scope: | |
97 | + return "inherit (%s) %s;" % (self.scope.pretty(), self.attrs.pretty()) | |
98 | + else: return "inherit %s;" % self.attrs.pretty() | |
99 | + | |
100 | +class FormalsBox(BaseBox): | |
101 | + def __init__(self, params, hasEllipsis): | |
102 | + self.params = params | |
103 | + self.hasEllipsis = hasEllipsis | |
104 | + def pretty(self): | |
105 | + params = [param.pretty() for param in self.params] | |
106 | + if self.hasEllipsis: params.append("...") | |
107 | + return "{ %s }" % ", ".join(params) | |
108 | + def getparams(self): return self.params | |
109 | + def getellipsis(self): return self.hasEllipsis | |
110 | + | |
111 | +class VarBox(BaseBox): | |
112 | + def __init__(self, name): self.name = name | |
113 | + def pretty(self): return self.name | |
114 | + | |
115 | +class AttrPathBox(BaseBox): | |
116 | + def __init__(self, attrs): self.attrs = attrs | |
117 | + def pretty(self): return ".".join([attr.pretty() for attr in self.attrs]) | |
118 | + def getattrs(self): return self.attrs | |
119 | + | |
120 | +class AttrsBox(BaseBox): | |
121 | + def __init__(self, attrs): self.attrs = attrs | |
122 | + def pretty(self): return " ".join([attr.pretty() for attr in self.attrs]) | |
123 | + def getattrs(self): return self.attrs | |
124 | + | |
125 | +class ListBox(BaseBox): | |
126 | + def __init__(self, exprs): self.exprs = exprs | |
127 | + def pretty(self): | |
128 | + return "[ %s ]" % " ".join([expr.pretty() for expr in self.exprs]) | |
129 | + def getexprs(self): return self.exprs | |
130 | + | |
131 | +class IntBox(BaseBox): | |
132 | + def __init__(self, value): self.value = value | |
133 | + def pretty(self): return str(self.value) | |
134 | + | |
135 | +class StrBox(BaseBox): | |
136 | + def __init__(self, value): self.value = value | |
137 | + def pretty(self): return '"%s"' % self.value | |
138 | + | |
139 | +class ExprUnaryBox(BaseBox): | |
140 | + def __init__(self, expr, op): | |
141 | + self.expr = expr | |
142 | + self.op = op.getstr() | |
143 | + def pretty(self): | |
144 | + return "(%s%s)" % (self.op, self.expr.pretty()) | |
145 | + | |
146 | +class SelectBox(BaseBox): | |
147 | + def __init__(self, expr, path, alt): | |
148 | + self.expr = expr | |
149 | + self.path = path | |
150 | + self.alt = alt | |
151 | + def pretty(self): | |
152 | + if self.alt is None: | |
153 | + return "%s.%s" % (self.expr.pretty(), self.path.pretty()) | |
154 | + else: | |
155 | + return "%s.%s or %s" % (self.expr.pretty(), self.path.pretty(), self.alt.pretty()) | |
156 | + | |
157 | +class ExprBinaryBox(BaseBox): | |
158 | + def __init__(self, left, right, op): | |
159 | + self.left = left | |
160 | + self.right = right | |
161 | + self.op = op.getstr() | |
162 | + def pretty(self): | |
163 | + return "(%s %s %s)" % (self.left.pretty(), self.op, self.right.pretty()) | |
164 | + | |
165 | +class HasBox(BaseBox): | |
166 | + def __init__(self, value, path): | |
167 | + self.value = value | |
168 | + self.path = path | |
169 | + def pretty(self): | |
170 | + return "(%s ? %s)" % (self.value.pretty(), self.path.pretty()) | |
171 | + | |
172 | +class AssertBox(BaseBox): | |
173 | + def __init__(self, cond, expr): | |
174 | + self.cond = cond | |
175 | + self.expr = expr | |
176 | + def pretty(self): return "assert %s; %s" % (self.cond.pretty(), self.expr.pretty()) | |
177 | + | |
178 | +class WithBox(BaseBox): | |
179 | + def __init__(self, scope, expr): | |
180 | + self.scope = scope | |
181 | + self.expr = expr | |
182 | + def pretty(self): return "with %s; %s" % (self.scope.pretty(), self.expr.pretty()) | |
183 | + | |
184 | +class LambdaBox(BaseBox): | |
185 | + def __init__(self, binding, params, body): | |
186 | + self.binding = binding | |
187 | + self.params = params | |
188 | + self.body = body | |
189 | + def pretty(self): | |
190 | + body = self.body.pretty() | |
191 | + if self.binding and self.params: | |
192 | + return "%s@%s: %s" % (self.binding.pretty(), self.params.pretty(), body) | |
193 | + elif self.binding: return "%s: %s" % (self.binding.pretty(), body) | |
194 | + elif self.params: return "%s: %s" % (self.params.pretty(), body) | |
195 | + else: return "_: " + body | |
196 | + | |
197 | +class AppBox(BaseBox): | |
198 | + def __init__(self, func, arg): | |
199 | + self.func = func | |
200 | + self.arg = arg | |
201 | + def pretty(self): return "(%s) (%s)" % (self.func.pretty(), self.arg.pretty()) | |
202 | + | |
203 | +class IfBox(BaseBox): | |
204 | + def __init__(self, cond, seq, alt): | |
205 | + self.cond = cond | |
206 | + self.seq = seq | |
207 | + self.alt = alt | |
208 | + def pretty(self): | |
209 | + return "if %s then %s else %s" % ( | |
210 | + self.cond.pretty(), self.seq.pretty(), self.alt.pretty()) | |
211 | + | |
212 | +pg = rply.ParserGenerator(KEYWORDS + [ | |
213 | + "ID", "INT", "SPATH", "URI", | |
214 | + "AND", "IMPL", "OR_OP", | |
215 | + "EQ", "NEQ", "LE", "GE", "LEQ", "GEQ", "HAS", | |
216 | + "CONCAT", "UPDATE", | |
217 | + "DIV", "MINUS", "MUL", "PLUS", | |
218 | + "NEGATE", "NOT", | |
219 | + "COLON", "SEMI", "DOT", "COMMA", "AT", "EQUALS", "ELLIPSIS", | |
220 | + "OPEN_BRACE", "CLOSE_BRACE", "OPEN_BRACK", "CLOSE_BRACK", "OPEN_PAREN", "CLOSE_PAREN", | |
221 | +], precedence=[ | |
222 | + ("right", ["IMPL"]), | |
223 | + ("left", ["OR_OP"]), | |
224 | + ("left", ["AND"]), | |
225 | + ("nonassoc", ["EQ", "NEQ"]), | |
226 | + ("nonassoc", ["LE", "GE", "LEQ", "GEQ"]), | |
227 | + ("right", ["UPDATE"]), | |
228 | + ("left", ["NOT"]), | |
229 | + ("left", ["PLUS", "MINUS"]), | |
230 | + ("left", ["MUL", "DIV"]), | |
231 | + ("right", ["CONCAT"]), | |
232 | + ("nonassoc", ["HAS"]), | |
233 | + ("nonassoc", ["NEGATE"]), | |
234 | +]) | |
235 | + | |
236 | +class ParseError(Exception): | |
237 | + def __init__(self, token): self.token = token | |
238 | + | |
239 | +@pg.error | |
240 | +def parseError(token): raise ParseError(token) | |
241 | + | |
242 | +def constRule(rule, pb): pg.production(rule)(lambda _: pb) | |
243 | +def enclosedRule(rule, i): pg.production(rule)(lambda p: p[i]) | |
244 | +def precRule(sup, sub): enclosedRule("expr%s : expr%s" % (sup, sub), 0) | |
245 | +SPINE = "", "_function", "_if", "_op", "_app", "_select", "_simple" | |
246 | +for sup, sub in zip(SPINE, SPINE[1:]): precRule(sup, sub) | |
247 | + | |
248 | +@pg.production("expr_function : ID COLON expr_function") | |
249 | +def exprLambda(p): return LambdaBox(VarBox(p[0].getstr()), None, p[2]) | |
250 | + | |
251 | +@pg.production("expr_function : OPEN_BRACE formals CLOSE_BRACE COLON expr_function") | |
252 | +def exprLambda(p): return LambdaBox(None, p[1], p[4]) | |
253 | + | |
254 | +@pg.production("expr_function : OPEN_BRACE formals CLOSE_BRACE AT ID COLON expr_function") | |
255 | +def exprLambda(p): return LambdaBox(VarBox(p[4].getstr()), p[1], p[6]) | |
256 | + | |
257 | +@pg.production("expr_function : ID AT OPEN_BRACE formals CLOSE_BRACE COLON expr_function") | |
258 | +def exprLambda(p): return LambdaBox(VarBox(p[0].getstr()), p[3], p[6]) | |
259 | + | |
260 | +@pg.production("expr_function : ASSERT expr SEMI expr_function") | |
261 | +def exprAssert(p): return AssertBox(p[1], p[3]) | |
262 | + | |
263 | +@pg.production("expr_function : WITH expr SEMI expr_function") | |
264 | +def exprWith(p): return WithBox(p[1], p[3]) | |
265 | + | |
266 | +@pg.production("expr_if : IF expr THEN expr ELSE expr") | |
267 | +def exprIf(p): return IfBox(p[1], p[3], p[5]) | |
268 | + | |
269 | +@pg.production("expr_op : NEGATE expr_op | NOT expr_op") | |
270 | +def exprUnary(p): return ExprUnaryBox(p[1], p[0]) | |
271 | + | |
272 | +@pg.production("expr_op : expr_op AND expr_op") | |
273 | +@pg.production("expr_op : expr_op CONCAT expr_op") | |
274 | +@pg.production("expr_op : expr_op DIV expr_op") | |
275 | +@pg.production("expr_op : expr_op EQ expr_op") | |
276 | +@pg.production("expr_op : expr_op GE expr_op") | |
277 | +@pg.production("expr_op : expr_op GEQ expr_op") | |
278 | +@pg.production("expr_op : expr_op IMPL expr_op") | |
279 | +@pg.production("expr_op : expr_op LE expr_op") | |
280 | +@pg.production("expr_op : expr_op LEQ expr_op") | |
281 | +@pg.production("expr_op : expr_op MINUS expr_op") | |
282 | +@pg.production("expr_op : expr_op MUL expr_op") | |
283 | +@pg.production("expr_op : expr_op NEQ expr_op") | |
284 | +@pg.production("expr_op : expr_op OR_OP expr_op") | |
285 | +@pg.production("expr_op : expr_op PLUS expr_op") | |
286 | +@pg.production("expr_op : expr_op UPDATE expr_op") | |
287 | +def exprBinary(p): return ExprBinaryBox(p[0], p[2], p[1]) | |
288 | + | |
289 | +@pg.production("expr_op : expr_op HAS attrpath") | |
290 | +def exprHas(p): return HasBox(p[0], p[2]) | |
291 | + | |
292 | +@pg.production("expr_app : expr_app expr_select") | |
293 | +def exprApp(p): return AppBox(p[0], p[1]) | |
294 | + | |
295 | +@pg.production("expr_select : expr_simple DOT attrpath | expr_simple DOT attrpath OR expr_select") | |
296 | +def exprSelect(p): return SelectBox(p[0], p[2], p[4] if len(p) == 5 else None) | |
297 | + | |
298 | +@pg.production("expr_simple : ID") | |
299 | +def exprSimpleId(p): return VarBox(p[0].getstr()) | |
300 | + | |
301 | +@pg.production("expr_simple : INT") | |
302 | +def exprSimpleInt(p): return IntBox(int(p[0].getstr())) | |
303 | + | |
304 | +@pg.production("expr_simple : URI") | |
305 | +def exprURI(p): return StrBox(p[0].getstr()) | |
306 | + | |
307 | +enclosedRule("expr_simple : OPEN_BRACE binds CLOSE_BRACE", 1) | |
308 | +enclosedRule("expr_simple : OPEN_PAREN expr CLOSE_PAREN", 1) | |
309 | +enclosedRule("expr_simple : OPEN_BRACK expr_list CLOSE_BRACK", 1) | |
310 | +constRule("expr_list :", ListBox([])) | |
311 | + | |
312 | +@pg.production("expr_list : expr_list expr_select") | |
313 | +def exprListCons(p): return ListBox(p[0].getexprs() + [p[1]]) | |
314 | + | |
315 | +@pg.production("binds : binds attrpath EQUALS expr SEMI") | |
316 | +def bindsExpr(p): return BindsBox(p[0].getbinds() + [BindExprBox(p[1], p[3])]) | |
317 | + | |
318 | +@pg.production("binds : binds INHERIT attrs SEMI") | |
319 | +def bindsInherit(p): | |
320 | + return BindsBox(p[0].getbinds() + [BindInheritBox(p[2], None)]) | |
321 | + | |
322 | +@pg.production("binds : binds INHERIT OPEN_PAREN expr CLOSE_PAREN attrs SEMI") | |
323 | +def bindsInherit(p): | |
324 | + return BindsBox(p[0].getbinds() + [BindInheritBox(p[5], p[3])]) | |
325 | + | |
326 | +constRule("binds :", BindsBox([])) | |
327 | + | |
328 | +@pg.production("formals : formal COMMA formals") | |
329 | +def formalsComma(p): | |
330 | + return FormalsBox([p[0]] + p[2].getparams(), p[2].getellipsis()) | |
331 | + | |
332 | +@pg.production("formals : formal") | |
333 | +def formalsFormal(p): return FormalsBox([p[0]], False) | |
334 | + | |
335 | +constRule("formals :", FormalsBox([], False)) | |
336 | +constRule("formals : ELLIPSIS", FormalsBox([], True)) | |
337 | + | |
338 | +@pg.production("formal : ID | ID HAS expr") | |
339 | +def formalId(p): return FormalBox(p[0].getstr(), p[2] if len(p) > 1 else None) | |
340 | + | |
341 | +@pg.production("attrs : attrs attr") | |
342 | +def attrsAttr(p): return AttrsBox(p[0].getattrs() + [p[1]]) | |
343 | + | |
344 | +constRule("attrs :", AttrsBox([])) | |
345 | + | |
346 | +@pg.production("attrpath : attrpath DOT attr") | |
347 | +def attrpathNil(p): return AttrPathBox(p[0].getattrs() + [p[2]]) | |
348 | + | |
349 | +@pg.production("attrpath : attr") | |
350 | +def attrpathCons(p): return AttrPathBox(p) | |
351 | + | |
352 | +@pg.production("attr : ID") | |
353 | +def attrId(p): return StrBox(p[0].getstr()) | |
354 | + | |
355 | +parser = pg.build() | |
356 | + | |
357 | +# Top-level interface: Lex and parse UTF-8 text. | |
358 | +def parse(expr): return parser.parse(lexer.lex(expr)) |