1 ################################################################################
3 ## Pythonc--Python to C++ translator
5 ## Copyright 2011 Zach Wegner
7 ## This file is part of Pythonc.
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.
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.
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/>.
22 ################################################################################
27 stmts
= '\n'.join('%s;' % s
for s
in stmts
).splitlines()
28 return '\n'.join(' %s' % s
for s
in stmts
)
31 def register_int(value
):
36 def register_string(value
):
38 if value
in all_strings
:
39 return all_strings
[value
][0]
40 # Compute hash via FNV-1a algorithm. Python makes signed 64-bit arithmetic hard.
41 hashkey
= 14695981039346656037
44 hashkey
*= 1099511628211
45 hashkey
&= (1 << 64) - 1
46 all_strings
[value
] = (len(all_strings
), hashkey
)
47 return all_strings
[value
][0]
50 return 'int_singleton_neg%d' % -i
if i
< 0 else 'int_singleton_%d' % i
53 global all_ints
, all_strings
56 f
.write('int_const_singleton %s(%sll);\n' % (int_name(i
), i
))
65 for k
, (v
, hashkey
) in all_strings
.items():
66 c_str
= ''.join(char_escape
.get(c
, c
) for c
in k
)
67 f
.write('string_const_singleton string_singleton_%s("%s", %sull);\n' % (v
, c_str
, hashkey
))
73 class NoneConst(Node
):
81 return '(&none_singleton)'
83 class BoolConst(Node
):
84 def __init__(self
, value
):
88 return '(&bool_singleton_%s)' % self
.value
91 def __init__(self
, value
):
99 return '(&%s)' % int_name(self
.value
)
101 class StringConst(Node
):
102 def __init__(self
, value
):
104 self
.id = register_string(value
)
110 return '(&string_singleton_%s)' % self
.id
112 class Identifier(Node
):
113 def __init__(self
, name
):
123 def __init__(self
, ref_type
, *args
):
124 self
.ref_type
= ref_type
128 return '(new(allocator) %s(%s))' % (self
.ref_type
, ', '.join(str(a
) for a
in self
.args
))
131 def __init__(self
, op
, rhs
):
136 return '%s->%s()' % (self
.rhs
, self
.op
)
138 class BinaryOp(Node
):
139 def __init__(self
, op
, lhs
, rhs
):
145 return '%s->%s(%s)' % (self
.lhs
, self
.op
, self
.rhs
)
148 def __init__(self
, name
, binding
):
150 self
.scope
, self
.idx
= binding
153 if self
.scope
== 'global':
154 return 'globals->load(%s)' % self
.idx
155 elif self
.scope
== 'class':
156 return 'class_ctx->load("%s")' % self
.name
157 return 'ctx.load(%s)' % self
.idx
160 def __init__(self
, name
, expr
, binding
):
163 self
.scope
, self
.idx
= binding
166 if self
.scope
== 'global':
167 return 'globals->store(%s, %s)' % (self
.idx
, self
.expr
)
168 elif self
.scope
== 'class':
169 return 'class_ctx->store("%s", %s)' % (self
.name
, self
.expr
)
170 return 'ctx.store(%s, %s)' % (self
.idx
, self
.expr
)
172 class StoreAttr(Node
):
173 def __init__(self
, name
, attr
, expr
):
179 return '%s->__setattr__(%s, %s)' % (self
.name
, self
.attr
, self
.expr
)
181 class StoreSubscript(Node
):
182 def __init__(self
, expr
, index
, value
):
188 return '%s->__setitem__(%s, %s)' % (self
.expr
, self
.index
, self
.value
)
190 class DeleteSubscript(Node
):
191 def __init__(self
, expr
, index
):
196 return '%s->__delitem__(%s)' % (self
.expr
, self
.index
)
199 def __init__(self
, items
):
202 def flatten(self
, ctx
):
203 list_name
= ctx
.get_temp()
204 name
= ctx
.get_temp()
205 # XXX HACK: add just some C++ text instead of syntax nodes...
206 ctx
.statements
+= ['node *%s[%d]' % (list_name
, len(self
.items
))]
207 for i
, item
in enumerate(self
.items
):
208 ctx
.statements
+= ['%s[%d] = %s' % (list_name
, i
, item
)]
209 ctx
.statements
+= [Assign(name
, Ref('list', len(self
.items
), list_name
), target_type
='list')]
216 def __init__(self
, items
):
219 def flatten(self
, ctx
):
220 list_name
= ctx
.get_temp()
221 name
= ctx
.get_temp()
222 # XXX HACK: add just some C++ text instead of syntax nodes...
223 if isinstance(self
.items
, list):
224 ctx
.statements
+= ['node *%s[%d]' % (list_name
, len(self
.items
))]
225 for i
, item
in enumerate(self
.items
):
226 ctx
.statements
+= ['%s[%d] = %s' % (list_name
, i
, item
)]
227 ctx
.statements
+= [Assign(name
, Ref('tuple', len(self
.items
), list_name
), target_type
='tuple')]
229 iter_name
= ctx
.get_temp()
231 'node_list %s' % list_name
,
232 'node *%s = %s->__iter__()' % (iter_name
, self
.items
),
233 'while (node *item = %s->next()) %s.push_back(item)' % (iter_name
, iter_name
, list_name
),
234 Assign(name
, Ref('tuple', list_name
), target_type
='tuple')
242 def __init__(self
, keys
, values
):
246 def flatten(self
, ctx
):
247 name
= ctx
.get_temp()
248 ctx
.statements
+= [Assign(name
, Ref('dict'), target_type
='dict')]
249 for k
, v
in zip(self
.keys
, self
.values
):
250 # XXX HACK: add just some C++ text instead of syntax nodes...
251 ctx
.statements
+= ['%s->__setitem__(%s, %s)' % (name
, k
, v
)]
258 def __init__(self
, items
):
261 def flatten(self
, ctx
):
262 name
= ctx
.get_temp()
263 ctx
.statements
+= [Assign(name
, Ref('set'), target_type
='set')]
265 # XXX HACK: add just some C++ text instead of syntax nodes...
266 ctx
.statements
+= ['%s->add(%s)' % (name
, i
)]
273 def __init__(self
, expr
, start
, end
, step
):
280 return '%s->__slice__(%s, %s, %s)' % (self
.expr
, self
.start
, self
.end
, self
.step
)
282 class Subscript(Node
):
283 def __init__(self
, expr
, index
):
288 return '%s->__getitem__(%s)' % (self
.expr
, self
.index
)
290 class Attribute(Node
):
291 def __init__(self
, expr
, attr
):
296 return '%s->__getattr__(%s)' % (self
.expr
, self
.attr
)
299 def __init__(self
, func
, args
, kwargs
):
305 return '%s->__call__(globals, &ctx, %s, %s)' % (self
.func
, self
.args
, self
.kwargs
)
308 def __init__(self
, expr
, true_stmts
, true_expr
, false_stmts
, false_expr
):
310 self
.true_stmts
= true_stmts
311 self
.true_expr
= true_expr
312 self
.false_stmts
= false_stmts
313 self
.false_expr
= false_expr
315 def flatten(self
, ctx
):
316 self
.temp
= ctx
.get_temp()
317 ctx
.statements
+= [Assign(self
.temp
, 'NULL'), self
]
321 true_stmts
= block_str(self
.true_stmts
)
322 false_stmts
= block_str(self
.false_stmts
)
323 body
= """if ({expr}->bool_value()) {{
325 {temp} = {true_expr};
328 {temp} = {false_expr};
330 """.format(expr
=self
.expr
, temp
=self
.temp
.name
, true_stmts
=true_stmts
,
331 true_expr
=self
.true_expr
, false_stmts
=false_stmts
, false_expr
=self
.false_expr
)
335 def __init__(self
, op
, lhs_expr
, rhs_stmts
, rhs_expr
):
337 self
.lhs_expr
= lhs_expr
338 self
.rhs_stmts
= rhs_stmts
339 self
.rhs_expr
= rhs_expr
342 def flatten(self
, ctx
, statements
):
343 self
.temp
= ctx
.get_temp()
344 statements
+= [Assign(self
.temp
, self
.lhs_expr
), self
]
348 rhs_stmts
= block_str(self
.rhs_stmts
)
349 body
= """if ({op}{lhs_expr}->bool_value()) {{
353 """.format(op
='!' if self
.op
== 'or' else '', lhs_expr
=self
.lhs_expr
,
354 temp
=self
.temp
.name
, rhs_stmts
=rhs_stmts
, rhs_expr
=self
.rhs_expr
)
358 def __init__(self
, target
, expr
, target_type
='node'):
361 self
.target_type
= target_type
364 if self
.target_type
is None:
365 return '%s = %s' % (self
.target
, self
.expr
)
367 return '%s *%s = %s' % (self
.target_type
, self
.target
, self
.expr
)
370 def __init__(self
, expr
, stmts
, else_block
):
373 self
.else_block
= else_block
376 stmts
= block_str(self
.stmts
)
377 body
= """if ({expr}->bool_value()) {{
380 """.format(expr
=self
.expr
, stmts
=stmts
)
382 stmts
= block_str(self
.else_block
)
386 """.format(expr
=self
.expr
, stmts
=stmts
)
389 class Comprehension(Node
):
390 def __init__(self
, comp_type
, target
, iter, iter_name
, iter_binding
,
391 cond_stmts
, cond
, expr_stmts
, expr
, expr2
):
392 self
.comp_type
= comp_type
395 self
.iter_name
= iter_name
396 self
.iter_binding
= iter_binding
397 self
.cond_stmts
= cond_stmts
399 self
.expr_stmts
= expr_stmts
403 def flatten(self
, ctx
):
404 if self
.comp_type
== 'set':
406 elif self
.comp_type
== 'dict':
410 self
.temp
= l
.flatten(ctx
)
411 ctx
.statements
+= [Assign(self
.iter_name
, '%s->__iter__()' % self
.iter)]
412 ctx
.statements
+= [self
]
413 # HACK: prevent iterator from being garbage collected
414 self
.iter_store
= Store(self
.iter_name
, self
.iter_name
, self
.iter_binding
)
418 cond_stmts
= block_str(self
.cond_stmts
)
419 expr_stmts
= block_str(self
.expr_stmts
)
422 if isinstance(self
.target
[0], tuple):
423 for i
, (target
, binding
) in enumerate(self
.target
):
424 arg_unpacking
+= [Store(target
, 'item->__getitem__(%s)' % i
, binding
)]
426 target
, binding
= self
.target
427 arg_unpacking
= [Store(target
, 'item', binding
)]
428 arg_unpacking
= block_str(arg_unpacking
)
430 cond
= 'if (!(%s)->bool_value()) continue;' % self
.cond
433 if self
.comp_type
== 'set':
434 adder
= '%s->add(%s);' % (self
.temp
, self
.expr
)
435 elif self
.comp_type
== 'dict':
436 adder
= '%s->__setitem__(%s, %s);' % (self
.temp
, self
.expr
, self
.expr2
)
438 adder
= '%s->append(%s);' % (self
.temp
, self
.expr
)
441 while (node *item = {iter}->next()) {{
448 """.format(iter=self
.iter_name
, iter_store
=self
.iter_store
, arg_unpacking
=arg_unpacking
,
449 cond_stmts
=cond_stmts
, cond
=cond
, expr_stmts
=expr_stmts
, adder
=adder
)
462 class Continue(Node
):
473 def __init__(self
, target
, iter, stmts
, iter_name
, iter_binding
):
477 self
.iter_name
= Identifier(iter_name
)
478 self
.iter_binding
= iter_binding
480 def flatten(self
, ctx
):
481 ctx
.statements
+= [Assign(self
.iter_name
, '%s->__iter__()' % self
.iter)]
482 # HACK: prevent iterator from being garbage collected
483 self
.iter_store
= Store(self
.iter_name
, self
.iter_name
, self
.iter_binding
)
487 stmts
= block_str(self
.stmts
)
489 if isinstance(self
.target
, list):
490 for i
, (arg
, binding
) in enumerate(self
.target
):
491 arg_unpacking
+= [Store(arg
, 'item->__getitem__(%s)' % i
, binding
)]
493 arg
, binding
= self
.target
494 arg_unpacking
= [Store(arg
, 'item', binding
)]
495 arg_unpacking
= block_str(arg_unpacking
)
499 while (node *item = {iter}->next()) {{
502 collect_garbage(&ctx, NULL);
504 """.format(iter=self
.iter_name
, iter_store
=self
.iter_store
, arg_unpacking
=arg_unpacking
,
509 def __init__(self
, test_stmts
, test
, stmts
):
510 self
.test_stmts
= test_stmts
515 # XXX Super hack: too lazy to do this properly now
516 dup_test_stmts
= copy
.deepcopy(self
.test_stmts
)
517 assert isinstance(dup_test_stmts
[-1], Assign
)
518 dup_test_stmts
[-1].target_type
= None
520 test_stmts
= block_str(self
.test_stmts
)
521 dup_test_stmts
= block_str(dup_test_stmts
)
522 stmts
= block_str(self
.stmts
)
525 while ({test}->bool_value())
528 collect_garbage(&ctx, NULL);
531 """.format(test_stmts
=test_stmts
, dup_test_stmts
=dup_test_stmts
, test
=self
.test
, stmts
=stmts
)
535 def __init__(self
, value
):
537 if self
.value
is None:
538 self
.value
= NoneConst()
542 collect_garbage(&ctx, %s);
544 """ % (self
.value
, self
.value
)
548 def __init__(self
, expr
, lineno
):
553 body
= """if (!{expr}->bool_value()) {{
554 error("assert failed at line {lineno}");
556 """.format(expr
=self
.expr
, lineno
=self
.lineno
)
559 class Arguments(Node
):
560 def __init__(self
, args
, binding
, defaults
):
562 self
.binding
= binding
563 self
.defaults
= defaults
565 def flatten(self
, ctx
):
566 new_def
= [None] * (len(self
.args
) - len(self
.defaults
))
567 self
.defaults
= new_def
+ self
.defaults
568 self
.name_strings
= [StringConst(a
) for a
in self
.args
]
573 for i
, (arg
, binding
, default
, name
) in enumerate(zip(self
.args
, self
.binding
,
574 self
.defaults
, self
.name_strings
)):
576 arg_unpacking
+= [Store(arg
, 'kwargs->lookup(%s) ? kwargs->lookup(%s) '
577 ': (args->len() > %s ? args->__getitem__(%s) : %s)' %
578 (name
, name
, i
, i
, default
), binding
)]
580 arg_unpacking
+= [Store(arg
, 'args->__getitem__(%s)' % i
, binding
)]
581 return block_str(arg_unpacking
)
583 class FunctionDef(Node
):
584 def __init__(self
, name
, args
, stmts
, exp_name
, binding
, local_count
):
586 self
.exp_name
= exp_name
if exp_name
else name
587 self
.exp_name
= 'fn_%s' % self
.exp_name
# make sure no name collisions
590 self
.binding
= binding
591 self
.local_count
= local_count
593 def flatten(self
, ctx
):
594 ctx
.functions
+= [self
]
595 return [Store(self
.name
, Ref('function_def', Identifier(self
.exp_name
)), self
.binding
)]
598 stmts
= block_str(self
.stmts
)
599 arg_unpacking
= str(self
.args
)
601 node *{name}(context *globals, context *parent_ctx, tuple *args, dict *kwargs) {{
602 node *local_syms[{local_count}];
603 context ctx(parent_ctx, {local_count}, local_syms);
606 return &none_singleton;
607 }}""".format(name
=self
.exp_name
, local_count
=self
.local_count
,
608 arg_unpacking
=arg_unpacking
, stmts
=stmts
)
611 class ClassDef(Node
):
612 def __init__(self
, name
, binding
, stmts
):
614 self
.binding
= binding
617 def flatten(self
, ctx
):
618 ctx
.functions
+= [self
]
619 return [Store(self
.name
, Ref('class_def', '"%s"' % self
.name
, Identifier('_%s__create__' % self
.name
)), self
.binding
)]
622 stmts
= block_str(self
.stmts
)
624 void _{name}__create__(class_def *class_ctx) {{
626 }}""".format(name
=self
.name
, stmts
=stmts
)