some bool ops return ints, others should return bools
[pythonc.git] / syntax.py
blob151f59c4c1c757e2a96fe7e1797561255d91b6da
1 ################################################################################
2 ##
3 ## Pythonc--Python to C++ translator
4 ##
5 ## Copyright 2011 Zach Wegner
6 ##
7 ## This file is part of Pythonc.
8 ##
9 ## Pythonc is free software: you can redistribute it and/or modify
10 ## it under the terms of the GNU General Public License as published by
11 ## the Free Software Foundation, either version 3 of the License, or
12 ## (at your option) any later version.
13 ##
14 ## Pythonc is distributed in the hope that it will be useful,
15 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ## GNU General Public License for more details.
18 ##
19 ## You should have received a copy of the GNU General Public License
20 ## along with Pythonc. If not, see <http://www.gnu.org/licenses/>.
21 ##
22 ################################################################################
24 import copy
26 def block_str(stmts):
27 return '\n'.join(' %s;' % s for s in stmts)
29 all_ints = set()
30 def register_int(value):
31 global all_ints
32 all_ints |= {value}
34 all_strings = {}
35 def register_string(value):
36 global all_strings
37 if value in all_strings:
38 return all_strings[value]
39 all_strings[value] = len(all_strings)
40 return all_strings[value]
42 def int_name(i):
43 return 'int_singleton_neg%d' % -i if i < 0 else 'int_singleton_%d' % i
45 def export_consts(f):
46 global all_ints, all_strings
48 for i in all_ints:
49 f.write('int_const %s(%sll);\n' % (int_name(i), i))
51 for k, v in all_strings.items():
52 f.write('string_const string_singleton_%s("%s");\n' % (v, repr(k)[1:-1]))
54 class Node:
55 def is_atom(self):
56 return False
58 class NoneConst(Node):
59 def __init__(self):
60 pass
62 def __str__(self):
63 return '&none_singleton'
65 class BoolConst(Node):
66 def __init__(self, value):
67 self.value = value
69 def __str__(self):
70 return '&bool_singleton_%s' % self.value
72 class IntConst(Node):
73 def __init__(self, value):
74 self.value = value
75 register_int(value)
77 def __str__(self):
78 return '&%s' % int_name(self.value)
80 class StringConst(Node):
81 def __init__(self, value):
82 self.value = value
83 self.id = register_string(value)
85 def __str__(self):
86 return '&string_singleton_%s' % self.id
88 class Identifier(Node):
89 def __init__(self, name):
90 self.name = name
92 def is_atom(self):
93 return True
95 def __str__(self):
96 return self.name
98 class Ref(Node):
99 def __init__(self, ref_type, *args):
100 self.ref_type = ref_type
101 self.args = args
103 def __str__(self):
104 return '(new %s(%s))' % (self.ref_type, ', '.join(str(a) for a in self.args))
106 class UnaryOp(Node):
107 def __init__(self, op, rhs):
108 self.op = op
109 self.rhs = rhs
111 def __str__(self):
112 return '%s->%s()' % (self.rhs, self.op)
114 class BinaryOp(Node):
115 def __init__(self, op, lhs, rhs):
116 self.op = op
117 self.lhs = lhs
118 self.rhs = rhs
120 def __str__(self):
121 return '%s->%s(%s)' % (self.lhs, self.op, self.rhs)
123 class Load(Node):
124 def __init__(self, name):
125 self.name = name
127 def __str__(self):
128 return 'ctx->load("%s")' % self.name
130 class Store(Node):
131 def __init__(self, name, expr):
132 self.name = name
133 self.expr = expr
135 def __str__(self):
136 return 'ctx->store("%s", %s)' % (self.name, self.expr)
138 class StoreAttr(Node):
139 def __init__(self, name, attr, expr):
140 self.name = name
141 self.attr = attr
142 self.expr = expr
144 def __str__(self):
145 return '%s->__setattr__(%s, %s)' % (self.name, self.attr, self.expr)
147 class StoreSubscript(Node):
148 def __init__(self, expr, index, value):
149 self.expr = expr
150 self.index = index
151 self.value = value
153 def __str__(self):
154 return '%s->__setitem__(%s, %s)' % (self.expr, self.index, self.value)
156 class DeleteSubscript(Node):
157 def __init__(self, expr, index):
158 self.expr = expr
159 self.index = index
161 def __str__(self):
162 return '%s->__delitem__(%s)' % (self.expr, self.index)
164 class Global(Node):
165 def __init__(self, name):
166 self.name = name
168 def __str__(self):
169 return 'ctx->set_global("%s")' % self.name
171 class List(Node):
172 def __init__(self, items):
173 self.items = items
175 def flatten(self, ctx):
176 name = ctx.get_temp()
177 ctx.statements += [Assign(name, Ref('list'), target_type='list')]
178 for i in self.items:
179 # XXX HACK: add just some C++ text instead of syntax nodes...
180 ctx.statements += ['%s->append(%s)' % (name, i)]
181 return name
183 def __str__(self):
184 return ''
186 class Dict(Node):
187 def __init__(self, keys, values):
188 self.keys = keys
189 self.values = values
191 def flatten(self, ctx):
192 name = ctx.get_temp()
193 ctx.statements += [Assign(name, Ref('dict'), target_type='dict')]
194 for k, v in zip(self.keys, self.values):
195 # XXX HACK: add just some C++ text instead of syntax nodes...
196 ctx.statements += ['%s->__setitem__(%s, %s)' % (name, k, v)]
197 return name
199 def __str__(self):
200 return ''
202 class Set(Node):
203 def __init__(self, items):
204 self.items = items
206 def flatten(self, ctx):
207 name = ctx.get_temp()
208 ctx.statements += [Assign(name, Ref('set'), target_type='set')]
209 for i in self.items:
210 # XXX HACK: add just some C++ text instead of syntax nodes...
211 ctx.statements += ['%s->add(%s)' % (name, i)]
212 return name
214 def __str__(self):
215 return ''
217 class Slice(Node):
218 def __init__(self, expr, start, end, step):
219 self.expr = expr
220 self.start = start
221 self.end = end
222 self.step = step
224 def __str__(self):
225 return '%s->__slice__(%s, %s, %s)' % (self.expr, self.start, self.end, self.step)
227 class Subscript(Node):
228 def __init__(self, expr, index):
229 self.expr = expr
230 self.index = index
232 def __str__(self):
233 return '%s->__getitem__(%s)' % (self.expr, self.index)
235 class Attribute(Node):
236 def __init__(self, expr, attr):
237 self.expr = expr
238 self.attr = attr
240 def __str__(self):
241 return '%s->__getattr__(%s)' % (self.expr, self.attr)
243 class Call(Node):
244 def __init__(self, func, args, kwargs):
245 self.func = func
246 self.args = args
247 self.kwargs = kwargs
249 def __str__(self):
250 return '%s->__call__(ctx, %s, %s)' % (self.func, self.args, self.kwargs)
252 class IfExp(Node):
253 def __init__(self, expr, true_stmts, true_expr, false_stmts, false_expr):
254 self.expr = expr
255 self.true_stmts = true_stmts
256 self.true_expr = true_expr
257 self.false_stmts = false_stmts
258 self.false_expr = false_expr
260 def flatten(self, ctx):
261 self.temp = ctx.get_temp()
262 ctx.statements += [Assign(self.temp, 'NULL'), self]
263 return self.temp
265 def __str__(self):
266 true_stmts = block_str(self.true_stmts)
267 false_stmts = block_str(self.false_stmts)
268 body = """if (test_truth({expr})) {{
269 {true_stmts}
270 {temp} = {true_expr};
271 }} else {{
272 {false_stmts}
273 {temp} = {false_expr};
275 """.format(expr=self.expr, temp=self.temp.name, true_stmts=true_stmts,
276 true_expr=self.true_expr, false_stmts=false_stmts, false_expr=self.false_expr)
277 return body
279 class BoolOp(Node):
280 def __init__(self, op, lhs_expr, rhs_stmts, rhs_expr):
281 self.op = op
282 self.lhs_expr = lhs_expr
283 self.rhs_stmts = rhs_stmts
284 self.rhs_expr = rhs_expr
286 # XXX hack
287 def flatten(self, ctx, statements):
288 self.temp = ctx.get_temp()
289 statements += [Assign(self.temp, self.lhs_expr), self]
290 return self.temp
292 def __str__(self):
293 rhs_stmts = block_str(self.rhs_stmts)
294 body = """if ({op}test_truth({lhs_expr})) {{
295 {rhs_stmts}
296 {temp} = {rhs_expr};
298 """.format(op='!' if self.op == 'or' else '', lhs_expr=self.lhs_expr,
299 temp=self.temp.name, rhs_stmts=rhs_stmts, rhs_expr=self.rhs_expr)
300 return body
302 class Assign(Node):
303 def __init__(self, target, expr, target_type='node'):
304 self.target = target
305 self.expr = expr
306 self.target_type = target_type
308 def __str__(self):
309 if self.target_type is None:
310 return '%s = %s' % (self.target, self.expr)
311 else:
312 return '%s *%s = %s' % (self.target_type, self.target, self.expr)
314 class If(Node):
315 def __init__(self, expr, stmts, else_block):
316 self.expr = expr
317 self.stmts = stmts
318 self.else_block = else_block
320 def __str__(self):
321 stmts = block_str(self.stmts)
322 body = """if (test_truth({expr})) {{
323 {stmts}
325 """.format(expr=self.expr, stmts=stmts)
326 if self.else_block:
327 stmts = block_str(self.else_block)
328 body += """else {{
329 {stmts}
331 """.format(expr=self.expr, stmts=stmts)
332 return body
334 class ListComp(Node):
335 def __init__(self, target, iter, stmts, expr):
336 self.target = target
337 self.iter = iter
338 self.stmts = stmts
339 self.expr = expr
341 def flatten(self, ctx):
342 l = List([])
343 self.temp = l.flatten(ctx)
344 ctx.statements += [self]
345 return self.temp
347 def __str__(self):
348 stmts = block_str(self.stmts)
349 arg_unpacking = []
350 if isinstance(self.target, list):
351 for i, arg in enumerate(self.target):
352 arg_unpacking += [Store(arg.id, '(*__iter)->__getitem__(%s)' % i)]
353 else:
354 arg_unpacking = [Store(self.target, '*__iter')]
355 arg_unpacking = block_str(arg_unpacking)
356 body = """
357 for (node_list::iterator __iter = {iter}->list_value()->begin(); __iter != {iter}->list_value()->end(); __iter++) {{
358 {arg_unpacking}
359 {stmts}
360 {temp}->append({expr});
362 """.format(iter=self.iter, arg_unpacking=arg_unpacking, stmts=stmts, temp=self.temp, expr=self.expr)
363 return body
365 class Break(Node):
366 def __init__(self):
367 pass
369 def is_atom(self):
370 return True
372 def __str__(self):
373 return 'break'
375 class Continue(Node):
376 def __init__(self):
377 pass
379 def is_atom(self):
380 return True
382 def __str__(self):
383 return 'continue'
385 class For(Node):
386 def __init__(self, target, iter, stmts):
387 self.target = target
388 self.iter = iter
389 self.stmts = stmts
391 def __str__(self):
392 stmts = block_str(self.stmts)
393 arg_unpacking = []
394 if isinstance(self.target, list):
395 for i, arg in enumerate(self.target):
396 arg_unpacking += [Store(arg.id, '(*__iter)->__getitem__(%s)' % i)]
397 else:
398 arg_unpacking = [Store(self.target, '*__iter')]
399 arg_unpacking = block_str(arg_unpacking)
400 # XXX sorta weird?
401 body = """
402 for (node_list::iterator __iter = {iter}->list_value()->begin(); __iter != {iter}->list_value()->end(); __iter++) {{
403 {arg_unpacking}
404 {stmts}
406 """.format(iter=self.iter, arg_unpacking=arg_unpacking, stmts=stmts)
407 return body
409 class While(Node):
410 def __init__(self, test_stmts, test, stmts):
411 self.test_stmts = test_stmts
412 self.test = test
413 self.stmts = stmts
415 def __str__(self):
416 # XXX Super hack: too lazy to do this properly now
417 dup_test_stmts = copy.deepcopy(self.test_stmts)
418 assert isinstance(dup_test_stmts[-1], Assign)
419 dup_test_stmts[-1].target_type = None
421 test_stmts = block_str(self.test_stmts)
422 dup_test_stmts = block_str(dup_test_stmts)
423 stmts = block_str(self.stmts)
424 body = """
425 {test_stmts}
426 while (test_truth({test}))
428 {stmts}
429 {dup_test_stmts}
431 """.format(test_stmts=test_stmts, dup_test_stmts=dup_test_stmts, test=self.test, stmts=stmts)
432 return body
434 class Return(Node):
435 def __init__(self, value):
436 self.value = value
437 if self.value is None:
438 self.value = NoneConst()
440 def __str__(self):
441 return 'return %s' % self.value
443 class Assert(Node):
444 def __init__(self, expr, lineno):
445 self.expr = expr
446 self.lineno = lineno
448 def __str__(self):
449 body = """if (!test_truth({expr})) {{
450 error("assert failed at line {lineno}");
452 """.format(expr=self.expr, lineno=self.lineno)
453 return body
455 class Arguments(Node):
456 def __init__(self, args, defaults):
457 self.args = args
458 self.defaults = defaults
460 def flatten(self, ctx):
461 new_def = [None] * (len(self.args) - len(self.defaults))
462 self.defaults = new_def + self.defaults
463 self.name_strings = [StringConst(a) for a in self.args]
464 return self
466 def __str__(self):
467 arg_unpacking = []
468 for i, (arg, default, name) in enumerate(zip(self.args, self.defaults, self.name_strings)):
469 if default:
470 arg_unpacking += [Store(arg, 'kwargs->lookup(%s) ? kwargs->lookup(%s) : (args->len() > %s ? args->__getitem__(%s) : %s)' % (name, name, i, i, default))]
471 else:
472 arg_unpacking += [Store(arg, 'args->__getitem__(%s)' % i)]
473 return block_str(arg_unpacking)
475 class FunctionDef(Node):
476 def __init__(self, name, args, stmts, exp_name=None):
477 self.name = name
478 self.exp_name = exp_name if exp_name else name
479 self.exp_name = 'fn_%s' % self.exp_name # make sure no name collisions
480 self.args = args
481 self.stmts = stmts
483 def flatten(self, ctx):
484 ctx.functions += [self]
485 return [Store(self.name, Ref('function_def', Identifier(self.exp_name)))]
487 def __str__(self):
488 stmts = block_str(self.stmts)
489 arg_unpacking = str(self.args)
490 body = """
491 node *{name}(context *parent_ctx, list *args, dict *kwargs) {{
492 context *ctx = new context(parent_ctx);
493 {arg_unpacking}
494 {stmts}
495 return &none_singleton;
496 }}""".format(name=self.exp_name, arg_unpacking=arg_unpacking, stmts=stmts)
497 return body
499 class ClassDef(Node):
500 def __init__(self, name, stmts):
501 self.name = name
502 self.stmts = stmts
504 def flatten(self, ctx):
505 ctx.functions += [self]
506 return [Store(self.name, Ref('class_def', '"%s"' % self.name, Identifier('_%s__create__' % self.name)))]
508 def __str__(self):
509 stmts = block_str(self.stmts)
510 body = """
511 void _{name}__create__(class_def *ctx) {{
512 {stmts}
513 }}""".format(name=self.name, stmts=stmts)
514 return body