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
))
58 for k
, (v
, hashkey
) in all_strings
.items():
59 f
.write('string_const_singleton string_singleton_%s("%s", %sull);\n' % (v
, repr(k
)[1:-1], hashkey
))
65 class NoneConst(Node
):
73 return '(&none_singleton)'
75 class BoolConst(Node
):
76 def __init__(self
, value
):
80 return '(&bool_singleton_%s)' % self
.value
83 def __init__(self
, value
):
91 return '(&%s)' % int_name(self
.value
)
93 class StringConst(Node
):
94 def __init__(self
, value
):
96 self
.id = register_string(value
)
102 return '(&string_singleton_%s)' % self
.id
104 class Identifier(Node
):
105 def __init__(self
, name
):
115 def __init__(self
, ref_type
, *args
):
116 self
.ref_type
= ref_type
120 return '(new(allocator) %s(%s))' % (self
.ref_type
, ', '.join(str(a
) for a
in self
.args
))
123 def __init__(self
, op
, rhs
):
128 return '%s->%s()' % (self
.rhs
, self
.op
)
130 class BinaryOp(Node
):
131 def __init__(self
, op
, lhs
, rhs
):
137 return '%s->%s(%s)' % (self
.lhs
, self
.op
, self
.rhs
)
140 def __init__(self
, name
, binding
):
142 self
.binding
= binding
145 if self
.binding
== 'global':
146 return 'globals->load("%s")' % self
.name
147 elif self
.binding
== 'class':
148 return 'class_ctx->load("%s")' % self
.name
149 return 'ctx.load("%s")' % self
.name
152 def __init__(self
, name
, expr
, binding
):
155 self
.binding
= binding
158 if self
.binding
== 'global':
159 return 'globals->store("%s", %s)' % (self
.name
, self
.expr
)
160 elif self
.binding
== 'class':
161 return 'class_ctx->store("%s", %s)' % (self
.name
, self
.expr
)
162 return 'ctx.store("%s", %s)' % (self
.name
, self
.expr
)
164 class StoreAttr(Node
):
165 def __init__(self
, name
, attr
, expr
):
171 return '%s->__setattr__(%s, %s)' % (self
.name
, self
.attr
, self
.expr
)
173 class StoreSubscript(Node
):
174 def __init__(self
, expr
, index
, value
):
180 return '%s->__setitem__(%s, %s)' % (self
.expr
, self
.index
, self
.value
)
182 class DeleteSubscript(Node
):
183 def __init__(self
, expr
, index
):
188 return '%s->__delitem__(%s)' % (self
.expr
, self
.index
)
191 def __init__(self
, items
):
194 def flatten(self
, ctx
):
195 name
= ctx
.get_temp()
196 ctx
.statements
+= [Assign(name
, Ref('list'), target_type
='list')]
198 # XXX HACK: add just some C++ text instead of syntax nodes...
199 ctx
.statements
+= ['%s->append(%s)' % (name
, i
)]
206 def __init__(self
, keys
, values
):
210 def flatten(self
, ctx
):
211 name
= ctx
.get_temp()
212 ctx
.statements
+= [Assign(name
, Ref('dict'), target_type
='dict')]
213 for k
, v
in zip(self
.keys
, self
.values
):
214 # XXX HACK: add just some C++ text instead of syntax nodes...
215 ctx
.statements
+= ['%s->__setitem__(%s, %s)' % (name
, k
, v
)]
222 def __init__(self
, items
):
225 def flatten(self
, ctx
):
226 name
= ctx
.get_temp()
227 ctx
.statements
+= [Assign(name
, Ref('set'), target_type
='set')]
229 # XXX HACK: add just some C++ text instead of syntax nodes...
230 ctx
.statements
+= ['%s->add(%s)' % (name
, i
)]
237 def __init__(self
, expr
, start
, end
, step
):
244 return '%s->__slice__(%s, %s, %s)' % (self
.expr
, self
.start
, self
.end
, self
.step
)
246 class Subscript(Node
):
247 def __init__(self
, expr
, index
):
252 return '%s->__getitem__(%s)' % (self
.expr
, self
.index
)
254 class Attribute(Node
):
255 def __init__(self
, expr
, attr
):
260 return '%s->__getattr__(%s)' % (self
.expr
, self
.attr
)
263 def __init__(self
, func
, args
, kwargs
):
269 return '%s->__call__(globals, &ctx, %s, %s)' % (self
.func
, self
.args
, self
.kwargs
)
272 def __init__(self
, expr
, true_stmts
, true_expr
, false_stmts
, false_expr
):
274 self
.true_stmts
= true_stmts
275 self
.true_expr
= true_expr
276 self
.false_stmts
= false_stmts
277 self
.false_expr
= false_expr
279 def flatten(self
, ctx
):
280 self
.temp
= ctx
.get_temp()
281 ctx
.statements
+= [Assign(self
.temp
, 'NULL'), self
]
285 true_stmts
= block_str(self
.true_stmts
)
286 false_stmts
= block_str(self
.false_stmts
)
287 body
= """if ({expr}->bool_value()) {{
289 {temp} = {true_expr};
292 {temp} = {false_expr};
294 """.format(expr
=self
.expr
, temp
=self
.temp
.name
, true_stmts
=true_stmts
,
295 true_expr
=self
.true_expr
, false_stmts
=false_stmts
, false_expr
=self
.false_expr
)
299 def __init__(self
, op
, lhs_expr
, rhs_stmts
, rhs_expr
):
301 self
.lhs_expr
= lhs_expr
302 self
.rhs_stmts
= rhs_stmts
303 self
.rhs_expr
= rhs_expr
306 def flatten(self
, ctx
, statements
):
307 self
.temp
= ctx
.get_temp()
308 statements
+= [Assign(self
.temp
, self
.lhs_expr
), self
]
312 rhs_stmts
= block_str(self
.rhs_stmts
)
313 body
= """if ({op}{lhs_expr}->bool_value()) {{
317 """.format(op
='!' if self
.op
== 'or' else '', lhs_expr
=self
.lhs_expr
,
318 temp
=self
.temp
.name
, rhs_stmts
=rhs_stmts
, rhs_expr
=self
.rhs_expr
)
322 def __init__(self
, target
, expr
, target_type
='node'):
325 self
.target_type
= target_type
328 if self
.target_type
is None:
329 return '%s = %s' % (self
.target
, self
.expr
)
331 return '%s *%s = %s' % (self
.target_type
, self
.target
, self
.expr
)
334 def __init__(self
, expr
, stmts
, else_block
):
337 self
.else_block
= else_block
340 stmts
= block_str(self
.stmts
)
341 body
= """if ({expr}->bool_value()) {{
344 """.format(expr
=self
.expr
, stmts
=stmts
)
346 stmts
= block_str(self
.else_block
)
350 """.format(expr
=self
.expr
, stmts
=stmts
)
353 class ListComp(Node
):
354 def __init__(self
, target
, iter, stmts
, expr
):
360 def flatten(self
, ctx
):
362 self
.temp
= l
.flatten(ctx
)
363 ctx
.statements
+= [self
]
364 # HACK: prevent iterable from being garbage collected
365 self
.iter_store
= Store(ctx
.get_temp(), self
.iter, 'local')
369 stmts
= block_str(self
.stmts
)
371 if isinstance(self
.target
, list):
372 for i
, arg
in enumerate(self
.target
):
373 arg_unpacking
+= [Store(arg
.id, '(*__iter)->__getitem__(%s)' % i
, 'local')]
375 arg_unpacking
= [Store(self
.target
, '*__iter', 'local')]
376 arg_unpacking
= block_str(arg_unpacking
)
379 for (node_list::iterator __iter = {iter}->list_value()->begin(); __iter != {iter}->list_value()->end(); __iter++) {{
382 {temp}->append({expr});
384 """.format(iter=self
.iter, iter_store
=self
.iter_store
, arg_unpacking
=arg_unpacking
,
385 stmts
=stmts
, temp
=self
.temp
, expr
=self
.expr
)
398 class Continue(Node
):
409 def __init__(self
, target
, iter, stmts
):
414 def flatten(self
, ctx
):
415 # HACK: prevent iterable from being garbage collected
416 self
.iter_store
= Store(ctx
.get_temp(), self
.iter, 'local')
420 stmts
= block_str(self
.stmts
)
422 if isinstance(self
.target
, list):
423 for i
, (arg
, binding
) in enumerate(self
.target
):
424 arg_unpacking
+= [Store(arg
, '(*__iter)->__getitem__(%s)' % i
, binding
)]
426 arg
, binding
= self
.target
427 arg_unpacking
= [Store(arg
, '*__iter', binding
)]
428 arg_unpacking
= block_str(arg_unpacking
)
432 for (node_list::iterator __iter = {iter}->list_value()->begin(); __iter != {iter}->list_value()->end(); __iter++) {{
435 collect_garbage(&ctx, NULL);
437 """.format(iter=self
.iter, iter_store
=self
.iter_store
, arg_unpacking
=arg_unpacking
,
442 def __init__(self
, test_stmts
, test
, stmts
):
443 self
.test_stmts
= test_stmts
448 # XXX Super hack: too lazy to do this properly now
449 dup_test_stmts
= copy
.deepcopy(self
.test_stmts
)
450 assert isinstance(dup_test_stmts
[-1], Assign
)
451 dup_test_stmts
[-1].target_type
= None
453 test_stmts
= block_str(self
.test_stmts
)
454 dup_test_stmts
= block_str(dup_test_stmts
)
455 stmts
= block_str(self
.stmts
)
458 while ({test}->bool_value())
461 collect_garbage(&ctx, NULL);
464 """.format(test_stmts
=test_stmts
, dup_test_stmts
=dup_test_stmts
, test
=self
.test
, stmts
=stmts
)
468 def __init__(self
, value
):
470 if self
.value
is None:
471 self
.value
= NoneConst()
475 collect_garbage(&ctx, %s);
477 """ % (self
.value
, self
.value
)
481 def __init__(self
, expr
, lineno
):
486 body
= """if (!{expr}->bool_value()) {{
487 error("assert failed at line {lineno}");
489 """.format(expr
=self
.expr
, lineno
=self
.lineno
)
492 class Arguments(Node
):
493 def __init__(self
, args
, defaults
):
495 self
.defaults
= defaults
497 def flatten(self
, ctx
):
498 new_def
= [None] * (len(self
.args
) - len(self
.defaults
))
499 self
.defaults
= new_def
+ self
.defaults
500 self
.name_strings
= [StringConst(a
) for a
in self
.args
]
505 for i
, (arg
, default
, name
) in enumerate(zip(self
.args
, self
.defaults
, self
.name_strings
)):
507 arg_unpacking
+= [Store(arg
, 'kwargs->lookup(%s) ? kwargs->lookup(%s) '
508 ': (args->len() > %s ? args->__getitem__(%s) : %s)' %
509 (name
, name
, i
, i
, default
), 'local')]
511 arg_unpacking
+= [Store(arg
, 'args->__getitem__(%s)' % i
, 'local')]
512 return block_str(arg_unpacking
)
514 class FunctionDef(Node
):
515 def __init__(self
, name
, args
, stmts
, exp_name
, binding
):
517 self
.exp_name
= exp_name
if exp_name
else name
518 self
.exp_name
= 'fn_%s' % self
.exp_name
# make sure no name collisions
521 self
.binding
= binding
523 def flatten(self
, ctx
):
524 ctx
.functions
+= [self
]
525 return [Store(self
.name
, Ref('function_def', Identifier(self
.exp_name
)), self
.binding
)]
528 stmts
= block_str(self
.stmts
)
529 arg_unpacking
= str(self
.args
)
531 node *{name}(context *globals, context *parent_ctx, list *args, dict *kwargs) {{
532 context ctx(parent_ctx);
535 return &none_singleton;
536 }}""".format(name
=self
.exp_name
, arg_unpacking
=arg_unpacking
, stmts
=stmts
)
539 class ClassDef(Node
):
540 def __init__(self
, name
, stmts
):
544 def flatten(self
, ctx
):
545 ctx
.functions
+= [self
]
546 return [Store(self
.name
, Ref('class_def', '"%s"' % self
.name
, Identifier('_%s__create__' % self
.name
)), 'global')]
549 stmts
= block_str(self
.stmts
)
551 void _{name}__create__(class_def *class_ctx) {{
553 }}""".format(name
=self
.name
, stmts
=stmts
)