fix cpp generation for 'import .. as'
[shedskin:mainline.git] / cpp.py
1 '''
2 *** SHED SKIN Python-to-C++ Compiler 0.0.28 ***
3 Copyright 2005-2008 Mark Dufour; License GNU GPL version 3 (See LICENSE)
4
5 cpp.py: output C++ code
6
7 output equivalent C++ code, using templates and virtuals to support data, parametric and OO polymorphism.
8
9 class generateVisitor: inherits visitor pattern from compiler.visitor.ASTVisitor, to recursively generate C++ code for each syntactical Python construct. the constraint graph, with inferred types, is first 'merged' back to program dimensions (getgx().merged_inh). 
10
11 typesetreprnew(): returns the C++ (or annotation) type declaration, taking into consideration detected data/parametric polymorphism (via analyze_virtuals() and template_detect()).
12
13 '''
14
15 from compiler import *
16 from compiler.ast import *
17 from compiler.visitor import *
18
19 from shared import *
20
21 import textwrap, string
22
23 from backward import *
24
25 # --- code generation visitor; use type information; c++ templates
26 class generateVisitor(ASTVisitor):
27     def __init__(self, module):
28         self.output_base = os.path.join(getgx().output_dir, module.filename[:-3])
29         self.out = file(self.output_base+'.cpp','w')
30         self.indentation = ''
31         self.consts = {}
32         self.mergeinh = merged(getgx().types, inheritance=True) 
33         self.module = module
34         self.name = module.ident
35         self.filling_consts = False
36         self.constant_nr = 0
37
38     def insert_consts(self, declare): # XXX ugly
39         if not self.consts: return
40         self.filling_consts = True
41
42         if declare: suffix = '.hpp'
43         else: suffix = '.cpp'
44
45         lines = file(self.output_base+suffix,'r').readlines()
46         newlines = [] 
47         j = -1
48         for (i,line) in enumerate(lines):
49             if line.startswith('namespace '):
50                 j = i+1
51             newlines.append(line)
52         
53             if i == j:
54                 pairs = []
55                 done = set()
56                 for (node, name) in self.consts.items():
57                     if not name in done and node in self.mergeinh and self.mergeinh[node]: # XXX
58                         ts = typesetreprnew(node, inode(node).parent)
59                         if declare: ts = 'extern '+ts
60                         pairs.append((ts, name))
61                         done.add(name)
62
63                 newlines.extend(self.group_declarations(pairs))
64                 newlines.append('\n')
65
66         newlines2 = [] 
67         j = -1
68         for (i,line) in enumerate(newlines):
69             if line.startswith('void __init() {'):
70                 j = i
71             newlines2.append(line)
72         
73             if i == j:
74                 todo = {}
75                 for (node, name) in self.consts.items():
76                     if not name in todo:
77                         todo[int(name[6:])] = node
78                 todolist = todo.keys()
79                 todolist.sort()
80                 for number in todolist:
81                     if self.mergeinh[todo[number]]: # XXX
82                         name = 'const_'+str(number)
83                         self.start('    '+name+' = ')
84                         self.visit(todo[number], inode(todo[number]).parent)
85                         newlines2.append(self.line+';\n')
86
87                 newlines2.append('\n')
88         
89         file(self.output_base+suffix,'w').writelines(newlines2)
90         self.filling_consts = False
91         
92     def insert_includes(self): # XXX ugly
93         includes = get_includes(self.module)
94         prop_includes = set(self.module.prop_includes) - set(includes)
95         if not prop_includes: return
96  
97         #print 'insert', self.module, prop_includes
98
99         lines = file(self.output_base+'.hpp','r').readlines()
100         newlines = []
101  
102         prev = ''
103         for line in lines:
104             if prev.startswith('#include') and not line.strip():
105                 for include in prop_includes:
106                     newlines.append('#include "%s"\n' % include)
107             newlines.append(line)
108             prev = line
109  
110         file(self.output_base+'.hpp','w').writelines(newlines)
111
112     # --- group pairs of (type, name) declarations, while paying attention to '*'
113     def group_declarations(self, pairs):
114         group = {}
115         for (type, name) in pairs:
116             group.setdefault(type, []).append(name)
117         
118         result = []
119         for (type, names) in group.items():
120             names.sort(cmp)
121             if type.endswith('*'):
122                 result.append(type+(', *'.join(names))+';\n')
123             else:
124                 result.append(type+(', '.join(names))+';\n')
125
126         return result
127
128     def header_file(self):
129         self.out = file(self.output_base+'.hpp','w')
130         self.visit(self.module.ast, True)
131         self.out.close()
132
133     def classes(self, node):
134         return set([t[0].ident for t in inode(node).types()])
135
136     def output(self, text):
137         print >>self.out, self.indentation+text
138
139     def start(self, text=None):
140         self.line = self.indentation
141         if text: self.line += text
142     def append(self, text):
143         self.line += text
144     def eol(self, text=None):
145         if text: self.append(text)
146         if self.line.strip():
147             print >>self.out, self.line+';'
148
149     def indent(self):
150         self.indentation += 4*' '
151     def deindent(self):
152         self.indentation = self.indentation[:-4]
153
154     def connector(self, node, func):
155         if singletype(node, module): return '::'
156
157         elif func and func.listcomp:
158             return '->'
159         elif isinstance(node, Name) and not lookupvar(node.name, func): # XXX
160             return '::'
161
162         return '->'
163
164     def declaredefs(self, vars, declare): # XXX use group_declarations
165         decl = {}
166         for (name,var) in vars:
167             if singletype(var, module) or var.invisible: # XXX buh
168                 continue
169             typehu = typesetreprnew(var, var.parent)
170             if not typehu or typehu == 'void *': continue 
171
172             decl.setdefault(typehu, []).append(self.cpp_name(name))
173         decl2 = []
174         for (t,names) in decl.items():
175             names.sort(cmp)
176             prefix=''
177             if declare: prefix='extern '
178             if t.endswith('*'):
179                 decl2.append(prefix+t+(', *'.join(names)))
180             else:
181                 decl2.append(prefix+t+(', '.join(names)))
182         return ';\n'.join(decl2)
183
184     def constant_constructor(self, node):
185         if isinstance(node, (UnarySub, UnaryAdd)):
186             node = node.expr
187         if isinstance(node, Const) and type(node.value) in [int, float, str]:
188             return False
189
190         return self.constant_constructor_rec(node)
191        
192     def constant_constructor_rec(self, node):
193         if isinstance(node, (UnarySub, UnaryAdd)):
194             node = node.expr
195
196         # --- determine whether built-in constructor call builds a (compound) constant, e.g. [(1,),[1,(1,2)]]
197         if isinstance(node, (List, Tuple, Dict)):
198             return not False in [self.constant_constructor_rec(child) for child in node.getChildNodes()]
199
200         # --- strings may also be constants of course
201         elif isinstance(node, Const) and type(node.value) in [int, float, str]:
202             if type(node.value) == str:
203                 self.get_constant(node)
204             return True
205
206         return False
207
208     def find_constants(self):
209         # --- determine (compound, non-str) constants
210         for callfunc, _ in getmv().callfuncs:
211             if isinstance(callfunc.node, Getattr) and callfunc.node.attrname in ['__ne__', '__eq__', '__contains__']:
212                 for node in [callfunc.node.expr, callfunc.args[0]]:
213                     if self.constant_constructor(node):
214                         self.get_constant(node)
215
216         for node in getmv().for_in_iters:
217             if self.constant_constructor(node):
218                 self.get_constant(node)
219
220         for node in self.mergeinh:
221             if isinstance(node, Subscript):
222                 if self.constant_constructor(node.expr):
223                     self.get_constant(node.expr)
224
225         #for node in self.mergeinh:
226         #    if isinstance(node, (Mul, Add)): # XXX extend, arbitrary methods on constructor? (getitem, find..)
227         #        for child in [node.left, node.right]:
228         #            if self.constant_constructor(child):
229         #                self.consts[child] = self.get_constant(child)
230
231     def get_constant(self, node):
232         parent = inode(node).parent
233         while isinstance(parent, function) and parent.listcomp: # XXX
234             parent = parent.parent
235         if isinstance(parent, function) and parent.inherited:
236             return
237
238         for other in self.consts:
239             if node is other or self.equal_constructor_rec(node, other):
240                 return self.consts[other]
241         
242         self.consts[node] = 'const_'+str(self.constant_nr)
243         self.constant_nr += 1
244
245         return self.consts[node]
246     
247     def equal_constructor_rec(self, a, b):
248         if isinstance(a, (UnarySub, UnaryAdd)) and isinstance(b, (UnarySub, UnaryAdd)):
249             return self.equal_constructor_rec(a.expr, b.expr)
250
251         if isinstance(a, Const) and isinstance(b, Const):
252             for c in (int, float, str):
253                 if isinstance(a.value, c) and isinstance(b.value, c):
254                     return a.value == b.value
255         
256         for c in (List, Tuple, Dict):
257             if isinstance(a, c) and isinstance(b, c) and len(a.getChildNodes()) == len(b.getChildNodes()): 
258                 return not 0 in [self.equal_constructor_rec(d,e) for (d,e) in zip(a.getChildNodes(), b.getChildNodes())]
259
260         return 0
261
262     def ext_supported(self, types):
263         if [t for t in types if not isinstance(t[0], class_)]:
264             return False
265         if [t for t in types if not t[0].mv.module.ident == 'builtin' or t[0].ident not in ['int_', 'float_', 'str_', 'list', 'tuple', 'tuple2', 'dict', 'set', 'none']]:
266             return False
267         return True
268
269     def visitModule(self, node, declare=False):
270         # --- header file
271         if declare: 
272             define = '_'.join(self.module.mod_path).upper()+'_HPP'
273             print >>self.out, '#ifndef __'+define
274             print >>self.out, '#define __'+define+'\n'
275
276             # --- include header files
277             if self.module.dir == '': depth = 0
278             else: depth = self.module.dir.count('/')+1
279             #print >>self.out, '#include "'+depth*'../'+'builtin_.hpp"'
280
281             includes = get_includes(self.module)
282             if 'getopt.hpp' in includes: # XXX
283                 includes.add('os/__init__.hpp')
284                 includes.add('os/path.hpp')
285                 includes.add('stat.hpp')
286             if 'os/__init__.hpp' in includes: # XXX
287                 includes.add('os/path.hpp')
288                 includes.add('stat.hpp')
289             for include in includes:
290                 print >>self.out, '#include "'+include+'"'
291             if includes: print >>self.out
292
293             # --- namespaces
294             print >>self.out, 'using namespace __shedskin__;'
295             for n in self.module.mod_path:
296                 print >>self.out, 'namespace __'+n+'__ {'
297             print >>self.out
298                  
299             skip = False
300             for child in node.node.getChildNodes():
301                 if isinstance(child, From): 
302                     skip = True
303                     mod_id = '__'+'__::__'.join(child.modname.split('.'))+'__'
304
305                     for (name, pseudonym) in child.names:
306                         if name == '*':
307                             for func in getgx().modules[child.modname].funcs.values():
308                                 if func.cp: 
309                                     print >>self.out, 'using '+mod_id+'::'+self.cpp_name(func.ident)+';';
310                             for var in getgx().modules[child.modname].mv.globals.values():
311                                 if not var.invisible and not var.imported and not var.name.startswith('__') and var.types():
312                                     print >>self.out, 'using '+mod_id+'::'+self.cpp_name(var.name)+';';
313                             for cl in getgx().modules[child.modname].classes:
314                                 print >>self.out, 'using '+mod_id+'::'+cl+';';
315
316                             continue
317
318                         if not name in self.module.mv.globals or [t for t in self.module.mv.globals[name].types() if not isinstance(t[0], module)]:
319                             print >>self.out, 'using '+mod_id+'::'+self.nokeywords(name)+';'
320             if skip: print >>self.out
321
322             # class declarations
323             gotcl = False
324             for child in node.node.getChildNodes():
325                 if isinstance(child, Class): 
326                     gotcl = True
327                     cl = defclass(child.name)
328                     print >>self.out, template_repr(cl)+'class '+self.nokeywords(cl.ident)+';'
329
330             # --- lambda typedefs
331             if gotcl: print >>self.out
332             self.func_pointers(True)
333
334             # globals
335             defs = self.declaredefs(list(getmv().globals.items()), declare=True);
336             if defs:
337                 self.output(defs+';')
338                 print >>self.out
339
340             # --- class definitions
341             for child in node.node.getChildNodes():
342                 if isinstance(child, Class): self.visitClass(child, True)
343
344             # --- variables
345             #if self.module != getgx().main_module:
346                 #print >>self.out
347                 #for v in self.module.mv.globals.values():
348                 #    print 'uh', v
349                 #    if not v.invisible and not v.imported and not v.name in self.module.funcs:
350                 #        print >>self.out, 'extern '+typesetreprnew(v, None)+' '+v.name+';'
351                 #if self.module.mv.globals.values(): print >>self.out
352
353             # --- defaults
354             if self.module.mv.defaults.items(): 
355                 for default, nr in self.module.mv.defaults.items():
356                     print >>self.out, 'extern '+typesetreprnew(default, None)+' '+('default_%d;'%nr)
357                 print >>self.out
358                     
359             # function declarations
360             if self.module != getgx().main_module:
361                 print >>self.out, 'void __init();'
362             for child in node.node.getChildNodes():
363                 if isinstance(child, Function): 
364                     func = getmv().funcs[child.name]
365                     if not self.inhcpa(func):
366                     #if not hmcpa(func) and (not func in getgx().inheritance_relations or not [1 for f in getgx().inheritance_relations[func] if hmcpa(f)]): # XXX merge with visitFunction
367                         pass
368                     elif not func.mv.module.builtin and not func.ident in ['min','max','zip','sum','__zip2','enumerate']: # XXX latter for test 116
369                         self.visitFunction(func.node, declare=True)
370             print >>self.out
371
372             for n in self.module.mod_path:
373                 print >>self.out, '} // module namespace'
374             print >>self.out, '#endif'
375             return
376
377         # --- external dependencies 
378         if self.module.filename.endswith('__init__.py'): # XXX nicer check
379             print >>self.out, '#include "__init__.hpp"\n'
380         else:
381             #print >>self.out, '#include "'+'/'.join(self.module.mod_path+[self.module.ident])+'.hpp"\n'
382             print >>self.out, '#include "%s.hpp"\n' % self.module.ident
383
384         # --- comments
385         if node.doc:
386             self.do_comment(node.doc)
387             print >>self.out
388
389         # --- namespace
390         for n in self.module.mod_path:
391             print >>self.out, 'namespace __'+n+'__ {'
392         print >>self.out
393
394         # --- globals
395         defs = self.declaredefs(list(getmv().globals.items()), declare=False);
396         if defs:
397             self.output(defs+';')
398             print >>self.out
399
400         # --- constants: __eq__(const) or ==/__eq(List())
401         self.find_constants()
402
403         # --- defaults
404         if self.module.mv.defaults.items(): 
405             for default, nr in self.module.mv.defaults.items():
406                 print >>self.out, typesetreprnew(default, None)+' '+('default_%d;'%nr)
407             print >>self.out
408
409         # --- list comprehensions
410         self.listcomps = {}
411         for (listcomp,lcfunc,func) in getmv().listcomps:
412             self.listcomps[listcomp] = (lcfunc, func)
413         for (listcomp,lcfunc,func) in getmv().listcomps: # XXX cleanup
414             if lcfunc.mv.module.builtin:
415                 continue
416
417             parent = func
418             while isinstance(parent, function) and parent.listcomp: 
419                 parent = parent.parent
420
421             if isinstance(parent, function):
422                 if not self.inhcpa(parent) or parent.inherited:
423                     continue
424
425             self.listcomp_func(listcomp)
426
427         # --- lambdas
428         for l in getmv().lambdas.values():
429             if l.ident not in getmv().funcs:
430                 self.visit(l.node)
431
432         # --- classes 
433         for child in node.node.getChildNodes():
434             if isinstance(child, Class): self.visitClass(child, False)
435
436         # --- __init
437         self.output('void __init() {')
438         self.indent()
439         if self.module == getgx().main_module and not getgx().extension_module: self.output('__name__ = new str("__main__");\n')
440         else: self.output('__name__ = new str("%s");\n' % self.module.ident)
441
442         if getmv().classes:
443             for cl in getmv().classes.values():
444                 self.output('cl_'+cl.cpp_name+' = new class_("%s", %d, %d);' % (cl.cpp_name, cl.low, cl.high))
445
446                 for var in cl.parent.vars.values():
447                     if var.initexpr:
448                         self.start()
449                         self.visitm(cl.ident+'::'+self.cpp_name(var.name)+' = ', var.initexpr, None)
450                         self.eol()
451
452             print >>self.out
453
454         for child in node.node.getChildNodes():
455             if isinstance(child, Function): 
456                 for default in child.defaults:
457                     if default in getmv().defaults:
458                         self.start('')
459                         self.visitm('default_%d = ' % getmv().defaults[default], default, ';')
460                         self.eol()
461             elif isinstance(child, Class):
462                 for child2 in child.code.getChildNodes():
463                     if isinstance(child2, Function): 
464                         for default in child2.defaults:
465                             if default in getmv().defaults:
466                                 self.start('')
467                                 self.visitm('default_%d = ' % getmv().defaults[default], default, ';')
468                                 self.eol()
469
470             if isinstance(child, Discard):
471                 if isinstance(child.expr, Const) and child.expr.value == None: # XXX merge with visitStmt
472                     continue
473                 if isinstance(child.expr, Const) and type(child.expr.value) == str:
474                     continue
475
476                 self.start('')
477                 self.visit(child)
478                 self.eol()
479
480             elif not isinstance(child, (Class, Function)):
481                 self.do_comments(child)
482                 self.visit(child)
483
484         self.deindent()
485         self.output('}\n')
486
487         for child in node.node.getChildNodes():
488             if isinstance(child, Function): 
489                 self.do_comments(child)
490                 self.visit(child)
491
492         # --- close namespace
493         for n in self.module.mod_path:
494             print >>self.out, '} // module namespace'
495         print >>self.out
496
497         # --- c++ main/extension module setup
498         if self.module == getgx().main_module: 
499             if getgx().extension_module:
500                 print >>self.out, 'extern "C" {'
501                 print >>self.out, '#include <Python.h>\n'
502                 
503                 funcs = [] # select functions that are called and have copyable arg/return types
504                 for func in self.module.funcs.values():
505                     if not hmcpa(func): # not called
506                         continue 
507                     builtins = True
508                     for formal in func.formals:
509                         if not self.ext_supported(self.mergeinh[func.vars[formal]]):
510                             builtins = False
511     
512                     if builtins and self.ext_supported(self.mergeinh[func.retnode.thing]):
513                         funcs.append(func)
514
515                 for func in funcs:
516                     print >>self.out, 'PyObject *%s(PyObject *self, PyObject *args) {' % self.cpp_name(func.ident)
517                     print >>self.out, '    if(PyTuple_Size(args) < %d || PyTuple_Size(args) > %d) {' % (len(func.formals)-len(func.defaults), len(func.formals))
518                     print >>self.out, '        PyErr_SetString(PyExc_Exception, "invalid number of arguments");'
519                     print >>self.out, '        return 0;'
520                     print >>self.out, '    }\n' 
521                     print >>self.out, '    try {'
522
523                     for i, formal in enumerate(func.formals):
524                         self.start('')
525                         self.append('        %(type)sarg_%(num)d = (PyTuple_Size(args) > %(num)d) ? __to_ss<%(type)s>(PyTuple_GetItem(args, %(num)d)) : ' % {'type' : typesetreprnew(func.vars[formal], func), 'num' : i})
526                         if i >= len(func.formals)-len(func.defaults):
527                             defau = func.defaults[i-(len(func.formals)-len(func.defaults))]
528                             cast = assign_needs_cast(defau, None, func.vars[formal], func)
529                             if cast:
530                                 self.append('(('+typesetreprnew(func.vars[formal], func)+')')
531
532                             if defau in func.mv.defaults:
533                                 if self.mergeinh[defau] == set([(defclass('none'),0)]):
534                                     self.append('0')
535                                 else:
536                                     self.append('%s::default_%d' % ('__'+func.mv.module.ident+'__', func.mv.defaults[defau]))
537                             else:
538                                 self.visit(defau, func)
539
540                             if cast:
541                                 self.append(')')
542                         else:
543                             self.append('0')
544                         self.eol()
545                     print >>self.out
546
547                     print >>self.out, '        return __to_py(__'+self.module.ident+'__::'+self.cpp_name(func.ident)+'('+', '.join(['arg_%d' % i for i in range(len(func.formals))])+'));\n' 
548                     print >>self.out, '    } catch (Exception *e) {'
549                     print >>self.out, '        PyErr_SetString(__to_py(e), e->msg->unit.c_str());'
550                     print >>self.out, '        return 0;'
551                     print >>self.out, '    }'
552
553                     print >>self.out, '}\n'
554
555                 print >>self.out, 'static PyMethodDef %sMethods[] = {' % self.module.ident
556                 for func in funcs:
557                     print >>self.out, '    {(char *)"%(id)s", %(id2)s, METH_VARARGS, (char *)""},' % {'id': func.ident, 'id2': self.cpp_name(func.ident)}
558                 print >>self.out, '    {NULL, NULL, 0, NULL}        /* Sentinel */\n};\n'
559
560             if getgx().extension_module:
561                 print >>self.out, 'PyMODINIT_FUNC init%s(void) {' % self.module.ident
562
563                 vars = []
564                 for (name,var) in getmv().globals.items():
565                     if singletype(var, module) or var.invisible: # XXX merge declaredefs 
566                         continue
567                     typehu = typesetreprnew(var, var.parent)
568                     if not typehu or typehu == 'void *': continue 
569                     if name.startswith('__'): continue
570                     if not self.ext_supported(self.mergeinh[var]): continue
571
572                     vars.append(var)
573
574                 for var in vars:
575                     print >>self.out, '    __'+self.module.ident+'__::'+self.cpp_name(var.name)+' = 0;'
576                 if vars: print >>self.out
577             else:
578                 print >>self.out, 'int main(int argc, char **argv) {'
579
580             print >>self.out, '    __shedskin__::__init();'
581
582             for mod in getgx().modules.values(): # XXX
583 #            for mod in getmv().imports.values():
584                 if mod != getgx().main_module and mod.ident != 'builtin':
585                     if mod.ident == 'sys':
586                         if getgx().extension_module:
587                             print >>self.out, '    __sys__::__init(0, 0);'
588                         else:
589                             print >>self.out, '    __sys__::__init(argc, argv);'
590                     else:
591                         print >>self.out, '    __'+'__::__'.join([n for n in mod.mod_path])+'__::__init();' # XXX sep func
592
593             print >>self.out, '    __'+self.module.ident+'__::__init();'
594             if getgx().extension_module:
595                 print >>self.out, '\n    PyObject *mod = Py_InitModule((char *)"%s", %sMethods);\n' % (self.module.ident, self.module.ident)
596                 for var in vars:
597                     varname = self.cpp_name(var.name)
598                     if [1 for t in self.mergeinh[var] if t[0].ident in ['int_', 'float_']]:
599                         print >>self.out, '    PyModule_AddObject(mod, (char *)"%(name)s", __to_py(%(var)s));' % {'name' : var.name, 'var': '__'+self.module.ident+'__::'+varname}
600                     else:
601                         print >>self.out, '    if(%(var)s) PyModule_AddObject(mod, (char *)"%(name)s", __to_py(%(var)s));' % {'name' : var.name, 'var': '__'+self.module.ident+'__::'+varname}
602
603                 print >>self.out
604             else:
605                 print >>self.out, '    __shedskin__::__exit();'
606              
607             print >>self.out, '}'
608
609             if getgx().extension_module:
610                 print >>self.out, '\n} // extern "C"'
611
612     def do_comment(self, s):
613         if not s: return
614         doc = s.split('\n')
615         self.output('/**')
616         if doc[0].strip():
617             self.output(doc[0])
618         # re-indent the rest of the doc string
619         rest = textwrap.dedent('\n'.join(doc[1:])).splitlines()
620         for l in rest:
621             self.output(l)
622         self.output('*/')
623
624     def do_comments(self, child):
625         if child in getgx().comments:
626             for n in getgx().comments[child]:
627                 self.do_comment(n)
628
629     def visitContinue(self, node, func=None):
630         self.start('continue')
631         self.eol()
632
633     def bool_test(self, node, func):
634         if [1 for t in self.mergeinh[node] if isinstance(t[0], class_) and t[0].ident == 'int_']:
635             self.visit(node, func)
636         else:
637             self.visitm('__bool(', node, ')', func)
638
639     def visitWhile(self, node, func=None):
640         print >>self.out
641
642         if node.else_:
643             self.output('%s = 0;' % getmv().tempcount[node.else_])
644          
645         self.start('while (')
646         self.bool_test(node.test, func)
647         self.append(') {')
648         print >>self.out, self.line
649
650         self.indent()
651         getgx().loopstack.append(node)
652         self.visit(node.body, func)
653         getgx().loopstack.pop()
654         self.deindent()
655
656         self.output('}')
657
658         if node.else_:
659             self.output('if (!%s) {' % getmv().tempcount[node.else_])
660             self.indent()
661             self.visit(node.else_, func)
662             self.deindent()
663             self.output('}')
664
665     def visitClass(self, node, declare):
666         cl = getmv().classes[node.name]
667
668         # --- .cpp file: output class methods
669         if not declare:
670             if cl.template_vars:  # XXX
671                 self.output('class_ *cl_'+cl.cpp_name+';\n')
672                 return
673
674             if cl.virtuals:
675                 self.virtuals(cl, declare)
676
677             if node in getgx().comments:
678                 self.do_comments(node)
679             else:
680                 self.output('/**\nclass %s\n*/\n' % cl.ident)
681             self.output('class_ *cl_'+cl.cpp_name+';\n')
682
683             #if '__init__' in cl.funcs and cl.descendants() and len(cl.funcs['__init__'].formals) != 1:
684             #    self.output(cl.ident+'::'+cl.ident+'() {}')
685
686             # --- method definitions
687             for func in cl.funcs.values():
688                 if func.node: 
689                     self.visitFunction(func.node, cl, declare)
690             if cl.has_init:
691                 self.visitFunction(cl.funcs['__init__'].node, cl, declare, True)
692             if cl.has_copy and not 'copy' in cl.funcs and not cl.template_vars:
693                 self.copy_method(cl, '__copy__', declare)
694             if cl.has_deepcopy and not 'deepcopy' in cl.funcs and not cl.template_vars:
695                 self.copy_method(cl, '__deepcopy__', declare)
696             
697             # --- class variable declarations
698             if cl.parent.vars: # XXX merge with visitModule
699                 for var in cl.parent.vars.values():
700                     if getgx().merged_inh[var]:
701                         self.start(typesetreprnew(var, cl.parent)+cl.ident+'::'+self.cpp_name(var.name)) 
702                         self.eol()
703                 print >>self.out
704
705             return
706
707         # --- .hpp file: class declaration
708         self.output('extern class_ *cl_'+cl.cpp_name+';') 
709
710         # --- header
711         if cl.bases: 
712             pyobjbase = []
713         else:
714             pyobjbase = ['public pyobj']
715
716         self.output(template_repr(cl)+'class '+self.nokeywords(cl.ident)+' : '+', '.join(pyobjbase+['public '+b.ident for b in cl.bases])+' {')
717         self.do_comment(node.doc)
718         self.output('public:')
719         self.indent()
720
721         # --- class variables 
722         if cl.parent.vars:
723             for var in cl.parent.vars.values():
724                 if getgx().merged_inh[var]:
725                     self.output('static '+typesetreprnew(var, cl.parent)+self.cpp_name(var.name)+';') 
726             print >>self.out
727
728         # --- instance variables
729         for var in cl.vars.values():
730             if var.invisible: continue # var.name in cl.virtualvars: continue
731
732             # var is masked by ancestor var
733             vars = set()
734             for ancestor in cl.ancestors():
735                 vars.update(ancestor.vars)
736                 #vars.update(ancestor.virtualvars)
737             if var.name in vars:
738                 continue
739
740             # virtual
741             if var.name in cl.virtualvars:
742                 ident = var.name
743                 subclasses = cl.virtualvars[ident]
744
745                 merged = set()
746                 for m in [getgx().merged_inh[subcl.vars[ident]] for subcl in subclasses if ident in subcl.vars and subcl.vars[ident] in getgx().merged_inh]: # XXX
747                     merged.update(m)
748             
749                 ts = self.padme(typestrnew({(1,0): merged}, cl, True, cl))
750                 if ts != 'void *':
751                     self.output(ts+self.cpp_name(ident)+';') 
752
753
754             # non-virtual
755             elif typesetreprnew(var, cl) != 'void *': # XXX invisible?
756                 self.output(typesetreprnew(var, cl)+self.cpp_name(var.name)+';') 
757
758         if [v for v in cl.vars if not v.startswith('__')]:
759             print >>self.out
760             
761         # --- constructor 
762         if [c for c in cl.ancestors() if c.ident == 'Exception']:
763             if cl.funcs['__init__'].inherited:
764                 self.output(self.nokeywords(cl.ident)+'(str *msg=0) : %s(msg) {\n        __class__ = cl_'%cl.bases[0].ident+cl.cpp_name+';\n    }')
765         elif not '__init__' in cl.funcs or len(cl.funcs['__init__'].formals) > 1: # XXX template vars
766             self.output(self.nokeywords(cl.ident)+'() {\n        __class__ = cl_'+cl.cpp_name+';\n    }')
767         elif cl.descendants() and len(cl.funcs['__init__'].formals) != 1: # XXX
768             self.output(cl.ident+'();')
769
770         # --- virtual methods
771         if cl.virtuals:
772             self.virtuals(cl, declare)
773
774         # --- regular methods
775         for func in cl.funcs.values():
776             if func.node:
777                 self.visitFunction(func.node, cl, declare)
778
779         if cl.has_init:
780             self.visitFunction(cl.funcs['__init__'].node, cl, declare, True)
781
782         if cl.has_copy and not 'copy' in cl.funcs:
783             self.copy_method(cl, '__copy__', declare)
784         if cl.has_deepcopy and not 'deepcopy' in cl.funcs:
785             self.copy_method(cl, '__deepcopy__', declare)
786         
787         self.deindent()
788         self.output('};\n')
789
790     def copy_method(self, cl, name, declare): # XXX merge?
791         header = cl.template()+' *'
792         if not declare:
793             header += cl.template()+'::'
794         header += name+'('
795         self.start(header)
796         
797         if name == '__deepcopy__':
798             self.append('dict<void *, pyobj *> *memo')
799         self.append(')')
800
801         if (cl.template_vars and declare) or (not cl.template_vars and not declare):
802             print >>self.out, self.line+' {'
803             self.indent()
804             self.output(cl.template()+' *c = new '+cl.template()+'();')
805             if name == '__deepcopy__':
806                 self.output('memo->__setitem__(this, c);')
807            
808             for var in cl.vars.values():
809                 if typesetreprnew(var, cl) != 'void *' and not var.invisible:
810                     if name == '__deepcopy__':
811                         self.output('c->%s = __deepcopy(%s);' % (var.name, var.name))
812                     else:
813                         self.output('c->%s = %s;' % (var.name, var.name))
814             self.output('return c;')
815
816             self.deindent()
817             self.output('}\n')
818         else:
819             self.eol()
820
821     def padme(self, x): 
822         if not x.endswith('*'): return x+' '
823         return x
824
825     def virtuals(self, cl, declare):
826         for ident, subclasses in cl.virtuals.items():
827             if not subclasses: continue
828
829             # --- merge arg/return types
830             formals = []
831             retexpr = False
832
833             for subcl in subclasses:
834                 if ident not in subcl.funcs: continue
835
836                 func = subcl.funcs[ident]
837                 sig_types = []
838
839                 if func.returnexpr:
840                     retexpr = True
841                     if func.retnode.thing in self.mergeinh:
842                         sig_types.append(self.mergeinh[func.retnode.thing]) # XXX mult returns; some targets with return some without..
843                     else:
844                         sig_types.append(set()) # XXX
845
846                 for name in func.formals[1:]:
847                     var = func.vars[name]
848                     sig_types.append(self.mergeinh[var])
849                 formals.append(sig_types)
850
851             merged = []
852             for z in zip(*formals):
853                 merge = set()
854                 for types in z: merge.update(types)
855                 merged.append(merge)
856                 
857             formals = list(subclasses)[0].funcs[ident].formals[1:]
858             ftypes = [self.padme(typestrnew({(1,0): m}, func.parent, True, func.parent)) for m in merged] 
859
860             # --- prepare for having to cast back arguments (virtual function call means multiple targets)
861             for subcl in subclasses:
862                 subcl.funcs[ident].ftypes = ftypes
863
864             # --- virtual function declaration
865             if declare:
866                 self.start('virtual ')
867                 if retexpr: 
868                     self.append(ftypes[0])
869                     ftypes = ftypes[1:]
870                 else:
871                     self.append('void ')
872                 self.append(self.cpp_name(ident)+'(')
873
874                 self.append(', '.join([t+f for (t,f) in zip(ftypes, formals)]))
875
876                 if ident in cl.funcs and self.inhcpa(cl.funcs[ident]):
877                     self.eol(')')
878                 else:
879                     self.eol(') = 0')
880
881                 if ident in cl.funcs: cl.funcs[ident].declared = True
882
883     def inhcpa(self, func):
884         return hmcpa(func) or (func in getgx().inheritance_relations and [1 for f in getgx().inheritance_relations[func] if hmcpa(f)])
885
886     def visitSlice(self, node, func=None):
887         if node.flags == 'OP_DELETE':
888             self.start()
889             self.visit(inode(node.expr).fakefunc, func)
890             self.eol()
891         else:
892             self.visit(inode(node.expr).fakefunc, func)
893
894     def visitLambda(self, node, parent=None):
895         self.append(getmv().lambdaname[node])
896
897     def visitTuple(self, node, func=None):
898         if not self.filling_consts and node in self.consts:
899             self.append(self.consts[node])
900             return
901
902         temp = self.filling_consts
903         self.filling_consts = False
904
905         ts = typesetreprnew(node, func)
906         self.append('(new '+ts[:-2])
907         self.children_args(node, ts, func)
908         self.append(')')
909
910         self.filling_consts = temp
911
912     def children_args(self, node, ts, func=None): 
913         self.append('(')
914         if len(node.getChildNodes()): 
915             self.append(str(len(node.getChildNodes()))+', ')
916
917         double = set(ts[ts.find('<')+1:-3].split(', ')) == set(['double']) # XXX whaa
918
919         for child in node.getChildNodes():
920             if double and self.mergeinh[child] == set([(defclass('int_'), 0)]):
921                 self.append('(double)(')
922
923             if child in getmv().tempcount:
924                 #print 'jahoor tempcount', child
925                 self.append(getmv().tempcount[child])
926             else:
927                 self.visit(child, func)
928
929             if double and self.mergeinh[child] == set([(defclass('int_'), 0)]):
930                 self.append(')')
931
932             if child != node.getChildNodes()[-1]:
933                 self.append(', ')
934         self.append(')')
935
936     def visitDict(self, node, func=None):
937         if not self.filling_consts and node in self.consts:
938             self.append(self.consts[node])
939             return
940
941         temp = self.filling_consts
942         self.filling_consts = False
943         self.append('(new '+typesetreprnew(node, func)[:-2]+'(')
944         if node.items:
945             self.append(str(len(node.items))+', ')
946
947         for (key, value) in node.items:
948             self.visitm('new tuple2'+typesetreprnew(node, func)[4:-2]+'(2,', key, ',', value, ')', func)
949             if (key, value) != node.items[-1]:
950                 self.append(', ')
951         self.append('))')
952         self.filling_consts = temp
953
954     def visitList(self, node, func=None):
955         if not self.filling_consts and node in self.consts:
956             self.append(self.consts[node])
957             return
958
959         temp = self.filling_consts
960         self.filling_consts = False
961
962         ts = typesetreprnew(node, func)
963         self.append('(new '+ts[:-2])
964         self.children_args(node, ts, func)
965         self.append(')')
966
967         self.filling_consts = temp
968
969     def visitAssert(self, node, func=None):
970         self.start('ASSERT(')
971         self.visitm(node.test, ', ', func)
972         if len(node.getChildNodes()) > 1:
973             self.visit(node.getChildNodes()[1], func)
974         else:
975             self.append('0')
976         self.eol(')')
977
978     def visitm(self, *args):
979         if args and isinstance(args[-1], function):
980             func = args[-1]
981         else:
982             func = None
983
984         for arg in args[:-1]:
985             if not arg: return
986             if isinstance(arg, str):
987                 self.append(arg)
988             else:
989                 self.visit(arg, func)
990
991     def visitRaise(self, node, func=None):
992         self.start('throw (')
993         # --- raise class [, constructor args]
994         if isinstance(node.expr1, Name) and not lookupvar(node.expr1.name, func): # XXX var = MyException
995             self.append('new %s(' % node.expr1.name)
996             if node.expr2:
997                 if isinstance(node.expr2, Tuple) and node.expr2.nodes:
998                     for n in node.expr2.nodes:
999                         self.visit(n, func)
1000                         if n != node.expr2.nodes[-1]: self.append(', ') # XXX visitcomma(nodes)
1001                 else:
1002                     self.visit(node.expr2, func)
1003             self.append(')')
1004         # --- raise instance
1005         else:
1006             self.visit(node.expr1, func)
1007         self.eol(')')
1008  
1009     def visitTryExcept(self, node, func=None):
1010         # try
1011         self.start('try {')
1012         print >>self.out, self.line
1013         self.indent()
1014         if node.else_:
1015             self.output('%s = 0;' % getmv().tempcount[node.else_])
1016         self.visit(node.body, func)
1017         if node.else_:
1018             self.output('%s = 1;' % getmv().tempcount[node.else_])
1019         self.deindent()
1020         self.start('}')
1021
1022         # except
1023         for handler in node.handlers:
1024             if isinstance(handler[0], Tuple):
1025                 pairs = [(n, handler[1], handler[2]) for n in handler[0].nodes]
1026             else:
1027                 pairs = [(handler[0], handler[1], handler[2])]
1028
1029             for (h0, h1, h2) in pairs:
1030                 if not h0:
1031                     arg = 'Exception *'
1032                 elif isinstance(h0, Name):
1033                     arg = h0.name+' *'
1034                 else: # XXX flow & visit
1035                     arg = '__'+h0.expr.name+'__::'+h0.attrname+' *'
1036                 if h1:
1037                     arg += h1.name
1038
1039                 self.append(' catch (%s) {' % arg) 
1040                 print >>self.out, self.line
1041
1042                 self.indent()
1043                 self.visit(h2, func)
1044                 self.deindent()
1045                 self.start('}')
1046
1047         print >>self.out, self.line
1048
1049         # else
1050         if node.else_: 
1051             self.output('if(%s) { // else' % getmv().tempcount[node.else_])
1052             self.indent()
1053             self.visit(node.else_, func)
1054             self.deindent()
1055             self.output('}')
1056             
1057     def fastfor(self, node, assname, neg, func=None):
1058         ivar, evar = getmv().tempcount[node.assign], getmv().tempcount[node.list]
1059
1060         self.start('FAST_FOR%s('%neg+assname+',')
1061
1062         if len(node.list.args) == 1: 
1063             self.append('0,')
1064             if node.list.args[0] in getmv().tempcount: # XXX in visit?
1065                 self.append(getmv().tempcount[node.list.args[0]])
1066             else:
1067                 self.visit(node.list.args[0], func)
1068             self.append(',')
1069         else: 
1070             if node.list.args[0] in getmv().tempcount: # XXX in visit?
1071                 self.append(getmv().tempcount[node.list.args[0]])
1072             else:
1073                 self.visit(node.list.args[0], func)
1074             self.append(',')
1075             if node.list.args[1] in getmv().tempcount: # XXX in visit?
1076                 self.append(getmv().tempcount[node.list.args[1]])
1077             else:
1078                 self.visit(node.list.args[1], func)
1079             self.append(',')
1080
1081         if len(node.list.args) != 3:
1082             self.append('1')
1083         else:
1084             if node.list.args[2] in getmv().tempcount: # XXX in visit?
1085                 self.append(getmv().tempcount[node.list.args[2]])
1086             else:
1087                 self.visit(node.list.args[2], func)
1088         self.append(',%s,%s)' % (ivar[2:],evar[2:]))
1089         #print 'ie', ivar, evar 
1090
1091         print >>self.out, self.line
1092
1093     def visitFor(self, node, func=None):
1094         if isinstance(node.assign, AssName):
1095             if node.assign.name != '_':
1096                 assname = node.assign.name
1097             else:
1098                 assname = getmv().tempcount[(node.assign,1)]
1099         elif isinstance(node.assign, AssAttr): 
1100             self.start('')
1101             self.visitAssAttr(node.assign, func)
1102             assname = self.line.strip()
1103         else:
1104             assname = getmv().tempcount[node.assign]
1105
1106         print >>self.out
1107
1108         if node.else_:
1109             self.output('%s = 0;' % getmv().tempcount[node.else_])
1110
1111         # --- for i in range(..) -> for( i=l, u=expr; i < u; i++ ) .. 
1112         if fastfor(node):
1113             if len(node.list.args) == 3 and not const_literal(node.list.args[2]):
1114                 self.fastfor_switch(node, func)
1115                 self.indent()
1116                 self.fastfor(node, assname, '', func)
1117                 self.forbody(node, func)
1118                 self.deindent()
1119                 self.output('} else {')
1120                 self.indent()
1121                 self.fastfor(node, assname, '_NEG', func)
1122                 self.forbody(node, func)
1123                 self.deindent()
1124                 self.output('}')
1125             else:
1126                 neg=''
1127                 if len(node.list.args) == 3 and const_literal(node.list.args[2]) and isinstance(node.list.args[2], UnarySub):
1128                     neg = '_NEG'
1129
1130                 self.fastfor(node, assname, neg, func)
1131                 self.forbody(node, func)
1132
1133         # --- otherwise, apply macro magic
1134         else:
1135             assname = self.cpp_name(assname)
1136                 
1137             pref = ''
1138             if not [t for t in self.mergeinh[node.list] if t[0] != defclass('tuple2')]:
1139                 pref = '_T2' # XXX generalize to listcomps
1140
1141             if not [t for t in self.mergeinh[node.list] if t[0] not in (defclass('tuple'), defclass('list'))]:
1142                 pref = '_SEQ'
1143
1144             if pref == '': tail = getmv().tempcount[(node,1)][2:]
1145             else: tail = getmv().tempcount[node][2:]+','+getmv().tempcount[node.list][2:]
1146
1147             if node.list in self.consts:
1148                 self.output('FOR_IN%s(%s, %s, %s)' % (pref, assname, self.consts[node.list], tail))
1149             else:
1150                 self.start('FOR_IN%s(%s,' % (pref, assname))
1151                 self.visit(node.list, func)
1152                 print >>self.out, self.line+','+tail+')'
1153
1154             self.forbody(node, func)
1155
1156         print >>self.out
1157
1158     def forbody(self, node, func=None):
1159         self.indent()
1160
1161         if isinstance(node.assign, (AssTuple, AssList)):
1162             self.tuple_assign(node.assign, getmv().tempcount[node.assign], func)
1163
1164         getgx().loopstack.append(node)
1165         self.visit(node.body, func)
1166         getgx().loopstack.pop()
1167         self.deindent()
1168
1169         self.output('END_FOR')
1170
1171         if node.else_:
1172             self.output('if (!%s) {' % getmv().tempcount[node.else_])
1173             self.indent()
1174             self.visit(node.else_, func)
1175             self.deindent()
1176             self.output('}')
1177
1178     def func_pointers(self, print_them):
1179         getmv().lambda_cache = {}
1180         getmv().lambda_signum = {}
1181
1182         for func in getmv().lambdas.values():
1183             argtypes = [typesetreprnew(func.vars[formal], func).rstrip() for formal in func.formals]
1184             signature = '_'.join(argtypes)
1185
1186             if func.returnexpr:
1187                 rettype = typesetreprnew(func.retnode.thing,func)
1188             else:
1189                 rettype = 'void '
1190             signature += '->'+rettype
1191
1192             if signature not in getmv().lambda_cache: 
1193                 nr = len(getmv().lambda_cache)
1194                 getmv().lambda_cache[signature] = nr
1195                 if print_them:
1196                     print >>self.out, 'typedef %s(*lambda%d)(' % (rettype, nr) + ', '.join(argtypes)+');'
1197
1198             getmv().lambda_signum[func] = getmv().lambda_cache[signature]
1199
1200         if getmv().lambda_cache and print_them: print >>self.out
1201
1202     # --- function/method header
1203     def func_header(self, func, declare, is_init=False):
1204         method = isinstance(func.parent, class_)
1205         if method: 
1206             formals = [f for f in func.formals if f != 'self'] 
1207         else:
1208             formals = [f for f in func.formals] 
1209
1210         ident = func.ident
1211         self.start()
1212
1213         # --- function/method template
1214         header = ''
1215 #        if func.ident != '__init__' and func in getgx().inheritance_relations: #XXX cleanup
1216 #            for child in getgx().inheritance_relations[func]:
1217 #                if func.ident in child.parent.funcs and not child.parent.funcs[func.ident].inherited:
1218 #                    header += 'virtual '
1219 #                    break
1220
1221         if method and not declare:
1222             header = template_repr(func.parent)
1223         header += template_repr(func)
1224             
1225         # --- return expression
1226         if func.ident in ['__hash__']:
1227             header += 'int '
1228         elif func.returnexpr: 
1229             header += typesetreprnew(func.retnode.thing, func) # XXX mult
1230         else:
1231             if ident.startswith('__init__') and not is_init: 
1232                 ident = self.nokeywords(func.parent.ident)
1233             else:
1234                 header += 'void '
1235                 ident = self.cpp_name(ident)
1236
1237         ftypes = [typesetreprnew(func.vars[f], func) for f in formals]
1238
1239         # if arguments type too precise (e.g. virtually called) cast them back 
1240         oldftypes = ftypes
1241         if func.ftypes:
1242             ftypes = func.ftypes[1:]
1243
1244         # --- method header
1245         if method and not declare:
1246             if func.parent.template_vars:
1247                 header += self.nokeywords(func.parent.ident)+'<'+','.join(func.parent.template_vars.keys())+'>::'
1248             else:
1249                 header += self.nokeywords(func.parent.ident)+'::'
1250         
1251         if func.ident != '__init__':
1252             ident = self.cpp_name(ident)
1253         header += ident
1254
1255         # --- cast arguments if necessary (explained above)
1256         casts = []
1257         if func.ftypes:
1258             #print 'cast', oldftypes, formals, ftypes
1259
1260             for i in range(min(len(oldftypes), len(ftypes))): # XXX this is 'cast on specialize'.. how about generalization?
1261                 if oldftypes[i] != ftypes[i]:
1262                     #print 'cast!', oldftypes[i], ftypes[i+1]
1263                     casts.append(oldftypes[i]+formals[i]+' = ('+oldftypes[i]+')__'+formals[i]+';')
1264                     if not declare:
1265                         formals[i] = '__'+formals[i]
1266
1267         formals2 = formals[:]
1268         for (i,f) in enumerate(formals2): # XXX
1269             formals2[i] = self.cpp_name(f)
1270
1271         formaldecs = [o+f for (o,f) in zip(ftypes, formals2)]
1272
1273         if declare and isinstance(func.parent, class_) and func.ident in func.parent.staticmethods:
1274             header = 'static '+header
1275
1276         # --- output 
1277         self.append(header+'('+', '.join(formaldecs)+')')
1278         if declare and not (is_method(func) and func.parent.template_vars) and not func.template_vars: # XXX general func
1279             self.eol()
1280             return
1281         else:
1282             if func.ident == '__init__':
1283                 if func.inherited:
1284                     self.append(' : '+func.parent.bases[0].ident+'('+','.join([f for f in func.formals if f != 'self'])+')') # XXX
1285                 elif func.parent_constr:
1286                     target = func.parent.bases[0].funcs['__init__'] # XXX use general pairing function (connect_actual..?)
1287
1288                     pc = func.parent_constr
1289                     if len(pc) < len(target.formals):
1290                         pc += target.defaults[-len(target.formals)+len(pc):]
1291
1292                     self.append(' : '+pc[0]+'(')
1293                     if len(pc) > 1:
1294                         for n in pc[1:-1]:
1295                             self.visitm(n, ',', func)
1296                         self.visitm(pc[-1], func)
1297                     self.append(')')
1298         
1299             print >>self.out, self.line+' {'
1300             self.indent()
1301                     
1302             if not declare and func.doc: 
1303                 self.do_comment(func.doc)
1304                 
1305             for cast in casts: 
1306                 self.output(cast)
1307             self.deindent()
1308
1309     def nokeywords(self, name):
1310         if name in getgx().cpp_keywords:
1311             return getgx().ss_prefix+name
1312         return name
1313
1314     def cpp_name(self, name, func=None):
1315         if name in [cl.ident for cl in getgx().allclasses]:
1316             return '_'+name
1317         elif name+'_' in [cl.ident for cl in getgx().allclasses]:
1318             return '_'+name
1319         elif name in self.module.funcs and func and isinstance(func.parent, class_) and name in func.parent.funcs: 
1320             return '__'+func.mv.module.ident+'__::'+name
1321
1322         return self.nokeywords(name)
1323
1324     def visitFunction(self, node, parent=None, declare=False, is_init=False):
1325         # locate right func instance
1326         if parent and isinstance(parent, class_):
1327             func = parent.funcs[node.name]
1328         elif node.name in getmv().funcs:
1329             func = getmv().funcs[node.name]
1330         else:
1331             func = getmv().lambdas[node.name]
1332
1333         if func.invisible or (func.inherited and not func.ident == '__init__'):
1334             return
1335         if func.mv.module.builtin or func.ident in ['min','max','zip','sum','__zip2','enumerate']: # XXX latter for test 116
1336             return
1337         if declare and func.declared: # XXX
1338             return
1339         if not declare and ((is_method(func) and func.parent.template_vars) or func.template_vars): # XXX general func
1340             return
1341
1342         # check whether function is called at all (possibly via inheritance)
1343         if not self.inhcpa(func):
1344             if func.ident in ['__iadd__', '__isub__', '__imul__']:
1345                 return
1346             error(repr(func)+' not called!', node, warning=True)
1347             if not (declare and func.ident in func.parent.virtuals):
1348                 return
1349               
1350         if func.isGenerator and ((declare and func.template_vars) or not declare):
1351             templatestr=''
1352             if func.template_vars: templatestr = 'template <'+','.join(['class '+f for f in func.template_vars])+'> '
1353             self.output('%sclass __gen_%s : public %s {' % (templatestr, func.ident, typesetreprnew(func.retnode.thing, func)[:-2]))
1354             self.output('public:')
1355             self.indent()
1356             pairs = [(typesetreprnew(func.vars[f], func), self.cpp_name(f)) for f in func.vars]
1357             self.output(self.indentation.join(self.group_declarations(pairs)))
1358             self.output('int __last_yield;\n')
1359
1360             args = []
1361             for f in func.formals:
1362                 args.append(typesetreprnew(func.vars[f], func)+self.cpp_name(f))
1363             self.output(('__gen_%s(' % func.ident) + ','.join(args)+') {')
1364             self.indent()
1365             for f in func.formals:
1366                 self.output('this->%s = %s;' % (self.cpp_name(f),self.cpp_name(f)))
1367             self.output('__last_yield = -1;')
1368             self.deindent()
1369             self.output('}\n')
1370
1371             self.output('%s next() {' % typesetreprnew(func.retnode.thing, func)[7:-3])
1372             self.indent()
1373             self.output('switch(__last_yield) {')
1374             self.indent()
1375             for (i,n) in enumerate(func.yieldNodes):
1376                 self.output('case %d: goto __after_yield_%d;' % (i,i))
1377             self.output('default: break;')
1378             self.deindent()
1379             self.output('}')
1380
1381             for child in func.node.code.getChildNodes():
1382                 self.visit(child, func)
1383             self.output('throw new StopIteration();')
1384             self.deindent()
1385             self.output('}\n')
1386
1387             self.deindent()
1388             self.output('};\n')
1389
1390         self.func_header(func, declare, is_init)
1391         if declare and not (is_method(func) and func.parent.template_vars) and not func.template_vars: # XXX general func
1392             return
1393
1394         self.indent()
1395
1396         if func.isGenerator:
1397             templatestr=''
1398             if func.template_vars: templatestr = '<'+','.join(func.template_vars)+'>'
1399             self.output('return new __gen_%s%s(%s);\n' % (func.ident, templatestr, ','.join([self.cpp_name(f) for f in func.formals]))) # XXX formals
1400             self.deindent()
1401             self.output('}\n')
1402             return
1403
1404         if func.ident.startswith('__init__'):
1405             if func.parent:
1406                 if not func.parent.has_init or not is_init:
1407                     self.output('this->__class__ = cl_'+parent.cpp_name+';')
1408
1409                 if func.parent.has_init and not is_init:
1410                     self.output('__init__('+','.join(func.formals[1:])+');')
1411                     self.deindent();
1412                     self.output('}\n')
1413                     return
1414
1415             if func.inherited:
1416                 self.deindent()
1417                 self.output('}\n')
1418                 return
1419
1420         # --- local declarations
1421         pairs = []
1422         for (name, var) in func.vars.items():
1423             if var.invisible: continue
1424
1425             if name not in func.formals:
1426                 #print 'declare', var, self.mergeinh[var], getgx().merged_inh[var]
1427
1428                 name = self.cpp_name(name)
1429                 ts = typesetreprnew(var, func)
1430             
1431                 pairs.append((ts, name))
1432
1433         self.output(self.indentation.join(self.group_declarations(pairs)))
1434
1435         # --- function body
1436         self.visit(node.code, func)
1437         if func.fakeret:
1438             self.visit(func.fakeret, func)
1439         
1440         # --- add Return(None) (sort of) if function doesn't already end with a Return
1441         if node.getChildNodes():
1442             lastnode = node.getChildNodes()[-1]
1443             if not func.ident == '__init__' and not func.fakeret and not isinstance(lastnode, Return) and not (isinstance(lastnode, Stmt) and isinstance(lastnode.nodes[-1], Return)): # XXX use Stmt in moduleVisitor
1444                 self.output('return 0;')
1445
1446         self.deindent()
1447         self.output('}\n')
1448
1449     def visitYield(self, node, func):
1450         self.output('__last_yield = %d;' % func.yieldNodes.index(node))
1451         self.start()
1452         self.visitm('return ', node.value, func)
1453         self.eol()
1454         self.output('__after_yield_%d:;' % func.yieldNodes.index(node))
1455         self.start()
1456         
1457     def visitNot(self, node, func=None): 
1458         self.append('(!')
1459         if unboxable(self.mergeinh[node.expr]):
1460             self.visit(node.expr, func)
1461         else:
1462             self.visitm('__bool(', node.expr, ')', func)
1463         self.append(')')
1464
1465     def visitBackquote(self, node, func=None):
1466         self.visit(inode(node.expr).fakefunc, func)
1467
1468     def zeropointernone(self, node):
1469         return [t for t in self.mergeinh[node] if t[0].ident == 'none']
1470
1471     def visitIf(self, node, func=None):
1472         for test in node.tests:
1473             self.start()
1474             if test == node.tests[0]:
1475                 self.append('if (')
1476             else:
1477                 self.append('else if (')
1478
1479             self.bool_test(test[0], func)
1480
1481             print >>self.out, self.line+') {'
1482
1483             self.indent()
1484             self.visit(test[1], func)
1485             self.deindent()
1486
1487             self.output('}')
1488
1489         if node.else_:
1490             self.output('else {')
1491             self.indent()
1492             self.visit(node.else_, func)
1493             self.deindent()
1494             self.output('}')
1495
1496     def visitIfExp(self, node, func=None):
1497         self.visitm('((', node.test, ')?(', node.then, '):(', node.else_, '))', func)
1498
1499     def visitBreak(self, node, func=None):
1500         if getgx().loopstack[-1].else_ in getmv().tempcount:
1501             self.output('%s = 1;' % getmv().tempcount[getgx().loopstack[-1].else_])
1502         self.output('break;')
1503
1504     def visitStmt(self, node, func=None):
1505         for b in node.nodes:
1506             if isinstance(b, Discard):
1507                 if isinstance(b.expr, Const) and b.expr.value == None:
1508                     continue
1509                 if isinstance(b.expr, Const) and type(b.expr.value) == str: 
1510                     self.do_comment(b.expr.value)
1511                     continue
1512                 self.start('')
1513                 self.visit(b, func)
1514                 self.eol()
1515             else:
1516                 self.visit(b, func)
1517
1518     def visitOr(self, node, func=None):
1519         if not self.mixingboolean(node, '||', func): # allow type mixing, as result may not be used
1520             self.booleanOp(node, node.nodes, '__OR', func)
1521
1522     def visitAnd(self, node, func=None):
1523         if not self.mixingboolean(node, '&&', func): # allow type mixing, as result may not be used
1524             self.booleanOp(node, node.nodes, '__AND', func)
1525
1526     def mixingboolean(self, node, op, func):
1527         mixing = False
1528         for n in node.nodes:
1529             if self.booleancast(node, n, func) is None:
1530                 mixing = True
1531         if not mixing: return False
1532
1533         self.append('(')
1534         for n in node.nodes:
1535             if self.mergeinh[n] != set([(defclass('int_'),0)]):
1536                 self.visitm('__bool(', n, ')', func)
1537             else:
1538                 self.visit(n, func)
1539             if n != node.nodes[-1]:
1540                 self.append(' '+op+' ')
1541         self.append(')')
1542         return True
1543
1544     def booleancast(self, node, child, func=None):
1545         if typesetreprnew(child, func) == typesetreprnew(node, func):
1546             return '' # exactly the same types: no casting necessary
1547         elif assign_needs_cast(child, func, node, func) or (self.mergeinh[child] == set([(defclass('none'),0)]) and self.mergeinh[node] != set([(defclass('none'),0)])): # cast None or almost compatible types
1548             return '('+typesetreprnew(node, func)+')'
1549         else:
1550             return None # local dynamic typing
1551
1552     def castup(self, node, child, func=None):
1553         cast = self.booleancast(node, child, func)
1554         if cast: self.visitm('('+cast, child, ')', func)
1555         else: self.visit(child, func)
1556
1557     def booleanOp(self, node, nodes, op, func=None):
1558         if len(nodes) > 1:
1559             self.append(op+'(')
1560             self.castup(node, nodes[0], func)
1561             self.append(', ')
1562             self.booleanOp(node, nodes[1:], op, func)
1563             self.append(', '+getmv().tempcount[nodes[0]][2:]+')')
1564         else:
1565             self.castup(node, nodes[0], func)
1566
1567     def visitCompare(self, node, func=None):
1568         if len(node.ops) > 1:
1569             self.append('(')
1570
1571         self.done = set() # (tvar=fun())
1572
1573         left = node.expr
1574         for op, right in node.ops:
1575             if op == '>': msg, short, pre = '__gt__', '>', None # XXX map = {}!
1576             elif op == '<': msg, short, pre = '__lt__', '<', None
1577             elif op == 'in': msg, short, pre = '__contains__', None, None
1578             elif op == 'not in': msg, short, pre = '__contains__', None, '!'
1579             elif op == '!=': msg, short, pre = '__ne__', '!=', None
1580             elif op == '==': msg, short, pre = '__eq__', '==', None
1581             elif op == 'is': msg, short, pre = None, '==', None
1582             elif op == 'is not': msg, short, pre = None, '!=', None
1583             elif op == '<=': msg, short, pre = '__le__', '<=', None
1584             elif op == '>=': msg, short, pre = '__ge__', '>=', None
1585             else: return
1586
1587             # --- comparison to [], (): convert to ..->empty() # XXX {}, __ne__
1588             if msg in ['__eq__', '__ne__']:
1589                 leftcl, rightcl = polymorphic_t(self.mergeinh[left]), polymorphic_t(self.mergeinh[right])
1590
1591                 if len(leftcl) == 1 and leftcl == rightcl and leftcl.pop().ident in ['list', 'tuple', 'tuple2', 'dict']:
1592                     for (a,b) in [(left, right), (right, left)]:
1593                         if isinstance(b, (List, Tuple, Dict)) and len(b.nodes) == 0:
1594                             if msg == '__ne__': self.append('!(')
1595                             self.visit2(a, func)
1596                             self.append('->empty()')
1597                             if msg == '__ne__': self.append(')')
1598                             return
1599
1600             # --- 'x in range(n)' -> x > 0 && x < n # XXX not in, range(a,b)
1601             if msg == '__contains__':
1602                 #op = node.ops[0][1] # XXX a in range(8): a doesn't have to be an int variable..; eval order
1603                 if isinstance(right, CallFunc) and isinstance(right.node, Name) and right.node.name in ['range']: #, 'xrange']:
1604                     if len(right.args) == 1:
1605                         l, u = '0', right.args[0]
1606                     else:
1607                         l, u = right.args[0], right.args[1]
1608                     if pre: self.append(pre)
1609                     self.visitm('(', left, '>=', l, '&&', left, '<', u, ')', func)
1610                 else:
1611                     self.visitBinary(right, left, msg, short, func, pre)
1612
1613             else:
1614                 self.visitBinary(left, right, msg, short, func, pre)
1615
1616             if right != node.ops[-1][1]:
1617                 self.append('&&')
1618             left = right
1619
1620         if len(node.ops) > 1:
1621             self.append(')')
1622
1623     def visitAugAssign(self, node, func=None):
1624         #print 'gen aug', node, inode(node).assignhop
1625
1626         if isinstance(node.node, Subscript):
1627             self.start()
1628             if set([t[0].ident for t in self.mergeinh[node.node.expr] if isinstance(t[0], class_)]) in [set(['dict']), set(['defaultdict'])] and node.op == '+=':
1629                 self.visitm(node.node.expr, '->__addtoitem__(', inode(node).subs, ', ', node.expr, ')', func)
1630                 self.eol()
1631                 return
1632             
1633             self.visitm(inode(node).temp1+' = ', node.node.expr, func)
1634             self.eol()
1635             self.start()
1636             self.visitm(inode(node).temp2+' = ', inode(node).subs, func)
1637             self.eol()
1638         self.visit(inode(node).assignhop, func)
1639
1640     def visitAdd(self, node, func=None):
1641         str_nodes = self.rec_string_addition(node)
1642         if str_nodes and len(str_nodes) > 2:
1643             self.append('__add_strs(%d, ' % len(str_nodes))
1644             for (i, node) in enumerate(str_nodes):
1645                 self.visit(node, func)
1646                 if i < len(str_nodes)-1:
1647                     self.append(', ')
1648             self.append(')')
1649         else:
1650             self.visitBinary(node.left, node.right, augmsg(node, 'add'), '+', func)
1651
1652     def rec_string_addition(self, node):
1653         if isinstance(node, Add):
1654             l, r = self.rec_string_addition(node.left), self.rec_string_addition(node.right)
1655             if l and r: 
1656                 return l+r
1657         elif self.mergeinh[node] == set([(defclass('str_'),0)]):
1658             return [node]
1659
1660         return None
1661
1662     def visitBitand(self, node, func=None):
1663         self.visitBitop(node, augmsg(node, 'and'), '&', func)
1664
1665     def visitBitor(self, node, func=None):
1666         self.visitBitop(node, augmsg(node, 'or'), '|', func)
1667
1668     def visitBitxor(self, node, func=None):
1669         self.visitBitop(node, augmsg(node, 'xor'), '^', func)
1670
1671     def visitBitop(self, node, msg, inline, func=None):
1672         self.visitBitpair(Bitpair(node.nodes, msg, inline), func)
1673
1674     def visitBitpair(self, node, func=None):
1675         if len(node.nodes) == 1:
1676             self.visit(node.nodes[0], func)
1677         else:
1678             self.visitBinary(node.nodes[0], Bitpair(node.nodes[1:], node.msg, node.inline), node.msg, node.inline, func)
1679
1680     def visitRightShift(self, node, func=None):
1681         self.visitBinary(node.left, node.right, augmsg(node, 'rshift'), '>>', func)
1682
1683     def visitLeftShift(self, node, func=None):
1684         self.visitBinary(node.left, node.right, augmsg(node, 'lshift'), '<<', func)
1685
1686     def visitMul(self, node, func=None):
1687         self.visitBinary(node.left, node.right, augmsg(node, 'mul'), '*', func)
1688
1689     def visitDiv(self, node, func=None):
1690         self.visitBinary(node.left, node.right, augmsg(node, 'div'), '/', func)
1691
1692     def visitInvert(self, node, func=None): # XXX visitUnarySub merge, template function __invert?
1693         if unboxable(self.mergeinh[node.expr]):
1694             self.visitm('~', node.expr, func)
1695         else:
1696             self.visitCallFunc(inode(node.expr).fakefunc, func)
1697
1698     def visitFloorDiv(self, node, func=None):
1699         self.visitBinary(node.left, node.right, augmsg(node, 'floordiv'), '//', func)
1700         #self.visitm('__floordiv(', node.left, ', ', node.right, ')', func)
1701
1702     def visitPower(self, node, func=None):
1703         self.power(node.left, node.right, None, func)
1704
1705     def power(self, left, right, mod, func=None):
1706         if mod: self.visitm('__power(', left, ', ', right, ', ', mod, ')', func)
1707         else: 
1708             if self.mergeinh[left].intersection(set([(defclass('int_'),0),(defclass('float_'),0)])) and isinstance(right, Const) and type(right.value) == int and right.value in [2,3]:
1709                 self.visitm(('__power%d(' % int(right.value)), left, ')', func)
1710             else:
1711                 self.visitm('__power(', left, ', ', right, ')', func)
1712
1713     def visitSub(self, node, func=None):
1714         self.visitBinary(node.left, node.right, augmsg(node, 'sub'), '-', func)
1715
1716     def par(self, node, thingy):
1717         if (isinstance(node, Const) and not isinstance(node.value, (int, float))) or not isinstance(node, (Name, Const)):
1718             return thingy 
1719         return ''
1720
1721     def visitBinary(self, left, right, middle, inline, func=None, prefix=''): # XXX cleanup please
1722         ltypes = self.mergeinh[left]
1723         #lclasses = set([t[0] for t in ltypes])
1724         origright = right
1725         if isinstance(right, Bitpair):
1726             right = right.nodes[0]
1727         rtypes = self.mergeinh[right]
1728         ul, ur = unboxable(ltypes), unboxable(rtypes)
1729
1730         inttype = set([(defclass('int_'),0)]) # XXX new type?
1731         floattype = set([(defclass('float_'),0)]) # XXX new type?
1732
1733         #print 'jow', left, right, ltypes, rtypes, middle, inline, inttype, floattype
1734
1735         # --- inline mod/div
1736         if (floattype.intersection(ltypes) or inttype.intersection(ltypes)):
1737             if inline in ['%'] or (inline in ['/'] and not (floattype.intersection(ltypes) or floattype.intersection(rtypes))):
1738                 self.append({'%': '__mods', '/': '__divs'}[inline]+'(')
1739                 self.visit2(left, func)
1740                 self.append(', ')
1741                 self.visit2(origright, func)
1742                 self.append(')')
1743                 return
1744
1745         # --- inline floordiv # XXX merge above?
1746         if (inline and ul and ur) and inline in ['//']:
1747             self.append({'//': '__floordiv'}[inline]+'(')
1748             self.visit2(left, func)
1749             self.append(',')
1750             self.visit2(right, func)
1751             self.append(')')
1752             return
1753
1754         # --- inline other
1755         if (inline and ul and ur) or not middle or (isinstance(left, Name) and left.name == 'None') or (isinstance(origright, Name) and origright.name == 'None'): # XXX not middle, cleanup?
1756             self.append('(')
1757             self.visit2(left, func)
1758             self.append(inline)
1759             self.visit2(origright, func)
1760             self.append(')')
1761             return
1762             
1763         # --- prefix '!'
1764         postfix = '' 
1765         if prefix: 
1766             self.append('('+prefix)
1767             postfix = ')'
1768
1769         # --- comparison
1770         if middle in ['__eq__', '__ne__', '__gt__', '__ge__', '__lt__', '__le__']:
1771             self.append(middle[:-2]+'(')
1772             self.visit2(left, func)
1773             self.append(', ')
1774             self.visit2(origright, func)
1775             self.append(')'+postfix)
1776             return
1777         
1778         # --- 'a.__mul__(b)': use template to call to b.__mul__(a), while maintaining evaluation order
1779         if inline == '*' and ul and not ur:
1780             self.append('__mul(')
1781             self.visit2(left, func)
1782             self.append(', ')
1783             self.visit2(origright, func)
1784             self.append(')'+postfix)
1785             return
1786
1787         # --- default: left, connector, middle, right
1788         self.append(self.par(left, '('))
1789         self.visit2(left, func)
1790         self.append(self.par(left, ')'))
1791         if middle == '==':
1792             self.append('==(')
1793         else:
1794             self.append(self.connector(left, func)+middle+'(')
1795         self.refer(origright, func, visit2=True) # XXX bleh
1796         self.append(')'+postfix)
1797
1798     def visit2(self, node, func): # XXX use temp vars in comparisons, e.g. (t1=fun())
1799         if node in getmv().tempcount:
1800             if node in self.done:
1801                 self.append(getmv().tempcount[node])
1802             else:
1803                 self.visitm('('+getmv().tempcount[node]+'=', node, ')', func)
1804                 self.done.add(node)
1805         else:
1806             self.visit(node, func)
1807
1808     def visitUnarySub(self, node, func=None):
1809         self.visitm('(', func)
1810         if unboxable(self.mergeinh[node.expr]):
1811             self.visitm('-', node.expr, func)
1812         else:
1813             self.visitCallFunc(inode(node.expr).fakefunc, func)
1814         self.visitm(')', func)
1815
1816     def visitUnaryAdd(self, node, func=None):
1817         self.visitm('(', func)
1818         if unboxable(self.mergeinh[node.expr]):
1819             self.visitm('+', node.expr, func)
1820         else:
1821             self.visitCallFunc(inode(node.expr).fakefunc, func)
1822         self.visitm(')', func)
1823
1824     def refer(self, node, func, visit2=False):
1825         if isinstance(node, str):
1826             var = lookupvar(node, func)
1827             return node
1828
1829         if isinstance(node, Name) and not node.name in ['None','True','False']:
1830             var = lookupvar(node.name, func)
1831         if visit2:
1832             self.visit2(node, func)
1833         else:
1834             self.visit(node, func)
1835
1836     def bastard(self, ident, objexpr):
1837         if ident in ['__getfirst__','__getsecond__']:
1838            lcp = lowest_common_parents(polymorphic_t(self.mergeinh[objexpr]))
1839            if [cl for cl in lcp if cl.ident != 'tuple2']:
1840                return True
1841         return False
1842
1843     def library_func(self, funcs, modname, clname, funcname):
1844         for func in funcs:
1845             if not func.mv.module.builtin or func.mv.module.ident != modname:
1846                 continue
1847
1848             if clname != None:
1849                 if not func.parent or func.parent.ident != clname:
1850                     continue
1851
1852             return func.ident == funcname
1853
1854         return False
1855
1856     def add_args_arg(self, node, funcs):
1857         ''' append argument that describes which formals are actually filled in '''
1858
1859         if self.library_func(funcs, 'datetime', 'time', 'replace') or \
1860            self.library_func(funcs, 'datetime', 'datetime', 'replace'):
1861
1862             formals = funcs[0].formals[1:] # skip self
1863             formal_pos = dict([(v,k) for k,v in enumerate(formals)])
1864             positions = []
1865
1866             for i, arg in enumerate(node.args):
1867                 if isinstance(arg, Keyword):
1868                     positions.append(formal_pos[arg.name])
1869                 else:
1870                     positions.append(i)
1871
1872             if positions:
1873                 self.append(str(reduce(lambda a,b: a|b, [(1<<x) for x in positions]))+', ')
1874             else:
1875                 self.append('0, ')
1876
1877     def visitCallFunc(self, node, func=None): 
1878         objexpr, ident, direct_call, method_call, constructor, mod_var, parent_constr = analyze_callfunc(node)
1879
1880         funcs = callfunc_targets(node, self.mergeinh)
1881
1882         if self.library_func(funcs, 're', None, 'findall') or \
1883            self.library_func(funcs, 're', 're_object', 'findall'):
1884             error("assuming 'findall' returns list of strings", node, warning=True)
1885
1886         if self.library_func(funcs, 'socket', 'socket', 'settimeout') or \
1887            self.library_func(funcs, 'socket', 'socket', 'gettimeout'):
1888             error("socket.set/gettimeout do not accept/return None", node, warning=True)
1889
1890         if self.library_func(funcs, 'builtin', None, 'sorted'):
1891             if [arg for arg in node.args if isinstance(arg, Keyword) and arg.name=='key'] or \
1892                len([arg for arg in node.args if not isinstance(arg, Keyword)]) >= 3:
1893                 error("'key' argument of 'sorted' is not supported", node, warning=True)
1894
1895         if self.library_func(funcs, 'builtin', 'list', 'sort'):
1896             if [arg for arg in node.args if isinstance(arg, Keyword) and arg.name=='key'] or \
1897                len([arg for arg in node.args if not isinstance(arg, Keyword)]) >= 2:
1898                 error("'key' argument of 'list.sort' is not supported", node, warning=True)
1899
1900         if self.bastard(ident, objexpr):
1901             ident = '__getitem__'
1902
1903         # --- target expression
1904
1905         if node.node in self.mergeinh and [t for t in self.mergeinh[node.node] if isinstance(t[0], function)]: # anonymous function
1906             self.visitm(node.node, '(', func)
1907
1908         elif constructor:
1909             self.append('(new '+self.nokeywords(typesetreprnew(node, func)[:-2])+'(')
1910
1911         elif parent_constr:
1912             if ident.startswith('__init__'):
1913                 return
1914             self.append(func.parent.bases[0].ident+'::'+node.node.attrname+'(') # XXX
1915
1916         elif direct_call: # XXX no namespace (e.g., math.pow), check nr of args
1917             if ident == 'float' and node.args and self.mergeinh[node.args[0]] == set([(defclass('float_'), 0)]):
1918                 self.visit(node.args[0], func)
1919                 return
1920             if ident in ['abs', 'int', 'float', 'str', 'dict', 'tuple', 'list', 'type', 'bool', 'cmp', 'sum']:
1921                 self.append('__'+ident+'(')
1922             elif ident == 'iter':
1923                 self.append('___iter(') # XXX
1924             elif ident == 'pow' and direct_call.mv.module.ident == 'builtin':
1925                 if len(node.args)==3: third = node.args[2]
1926                 else: third = None
1927                 self.power(node.args[0], node.args[1], third, func)
1928                 return
1929             elif ident == 'hash':
1930                 self.append('hasher(') # XXX cleanup
1931             elif ident == 'isinstance' and isinstance(node.args[1], Name) and node.args[1].name in ['float','int']:
1932                 error("'isinstance' cannot be used with ints or floats; assuming always true", node, warning=True)
1933                 self.append('1')
1934                 return
1935             elif ident == 'round':
1936                 self.append('___round(')
1937             elif ident in ['min','max']:
1938                 self.append('__'+ident+'(')
1939                 if len(node.args) > 3:
1940                     self.append(str(len(node.args))+', ')
1941             else:
1942                 if ident in self.module.mv.ext_funcs: # XXX using as? :P
1943                      ident = self.module.mv.ext_funcs[ident].ident
1944
1945                 if isinstance(node.node, Name): # XXX ugly
1946                     self.append(self.cpp_name(ident, func))
1947                 else:
1948                     self.visit(node.node)
1949                 self.append('(')
1950
1951         elif method_call:
1952 #            if isinstance(objexpr, Const) and objexpr.value == '' and ident == 'join' and isinstance(node.args[0], CallFunc) and \
1953 #                  isinstance(node.args[0].node, Name) and node.args[0].node.name == 'sorted' and \
1954 #                  self.mergeinh[node.args[0].args[0]] == set([(defclass('str_'), 0)]): # ''.join(sorted(str))
1955 #                #print 'nnee', objexpr, ident, self.mergeinh[node.args[0].args[0]], node.args
1956 #                self.visitm(node.args[0].args[0], '->sorted()', func)
1957 #                return
1958 #            else:
1959                 for cl, _ in self.mergeinh[objexpr]:
1960                     if cl.ident != 'none' and ident not in cl.funcs:
1961                         conv = {'int_': 'int', 'float_': 'float', 'str_': 'str', 'class_': 'class', 'none': 'none'}
1962                         clname = conv.get(cl.ident, cl.ident)
1963                         error("class '%s' has no method '%s'" % (clname, ident), node, warning=True)
1964                 self.visitm(node.node, '(', func)
1965
1966         else:
1967             error("unbound identifier '"+ident+"'", node)
1968
1969         if constructor and self.mergeinh[node] and 'Exception' in [c.ident for c in list(self.mergeinh[node])[0][0].ancestors()]: # XXX self.mergeinh[node], try getopt
1970             if node.args:
1971                 for n in node.args[:-1]:
1972                     self.visit(n, func)
1973                     self.append(',')
1974                 self.visit(node.args[-1], func)
1975             self.append('))')
1976             return
1977
1978         elif not funcs:
1979             if constructor: self.append(')')
1980             self.append(')')
1981             return
1982
1983         # --- arguments 
1984         target = funcs[0] # XXX
1985
1986         for f in funcs:
1987             if len(f.formals) != len(target.formals) or (f.varargs and not target.varargs) or (not f.varargs and target.varargs): # incompatible signatures 
1988                 error('calling functions with different numbers of arguments', node, warning=True)
1989                 self.append(')')
1990                 return
1991
1992         if ident in ['__getfirst__','__getsecond__']:
1993             self.append(')')
1994             return
1995
1996         if target.mv.module.builtin and target.mv.module.ident == 'path' and ident=='join': # XXX
1997             pairs = [(arg, target.formals[0]) for arg in node.args]
1998             self.append('%d, ' % len(node.args))
1999         elif ident in ['max','min']: 
2000             pairs = [(arg, target.formals[0]) for arg in node.args]
2001         else:
2002             args = node.args
2003             if node.star_args:
2004                 args = [node.star_args]+args
2005         
2006             pairs = connect_actual_formal(node, target, parent_constr, check_error=True)
2007
2008             if constructor and ident=='defaultdict' and node.args:
2009                 pairs = pairs[1:]
2010
2011         double = False
2012         if ident in ['min', 'max']:
2013             for arg in node.args:
2014                 if (defclass('float_'),0) in self.mergeinh[arg]:
2015                     double = True
2016
2017         self.add_args_arg(node, funcs)
2018
2019         for (arg, formal) in pairs:
2020             if isinstance(arg, tuple):
2021                 # --- pack arguments as tuple
2022                 self.append('new '+typesetreprnew(formal, target)[:-2]+'(')
2023                 
2024                 if len(arg) > 0: 
2025                     self.append(str(len(arg))+',')
2026
2027                     # XXX merge with children args, as below
2028                     for a in arg:
2029                         self.refer(a, func)
2030                         if a != arg[-1]:
2031                             self.append(',')
2032                 self.append(')')
2033
2034             elif isinstance(formal, tuple):
2035                 # --- unpack tuple 
2036                 self.append(', '.join(['(*'+arg.name+')['+str(i)+']' for i in range(len(formal))]))
2037
2038             else:
2039                 # --- connect regular argument to formal
2040                 cast = False
2041                 if double and self.mergeinh[arg] == set([(defclass('int_'),0)]):
2042                     cast = True
2043                     self.append('((double)(')
2044                 elif not target.mv.module.builtin and assign_needs_cast(arg, func, formal, target): # XXX builtin (dict.fromkeys?)
2045                     #print 'cast!', node, arg, formal
2046                     cast = True
2047                     self.append('(('+typesetreprnew(formal, target)+')(')
2048
2049                 if arg in target.mv.defaults: 
2050                     if self.mergeinh[arg] == set([(defclass('none'),0)]):
2051                         self.append('0')
2052                     elif target.mv.module == getmv().module:
2053                         self.append('default_%d' % (target.mv.defaults[arg]))
2054                     else:
2055                         self.append('%s::default_%d' % ('__'+'__::__'.join(target.mv.module.mod_path)+'__', target.mv.defaults[arg]))
2056
2057                 elif arg in self.consts:
2058                     self.append(self.consts[arg])
2059                 else:
2060                     if constructor and ident in ['set', 'frozenset'] and typesetreprnew(arg, func) in ['list<void *> *', 'tuple<void *> *', 'pyiter<void *> *', 'pyseq<void *> *', 'pyset<void *>']: # XXX to needs_cast
2061                         pass # XXX assign_needs_cast
2062                     else:
2063                         self.refer(arg, func)
2064
2065                 if cast: self.append('))')
2066
2067             if (arg, formal) != pairs[-1]:
2068                 self.append(', ')
2069
2070         if constructor and ident == 'frozenset':
2071             if pairs: self.append(',')
2072             self.append('1')
2073         self.append(')')
2074         if constructor:
2075             self.append(')')
2076
2077     def visitReturn(self, node, func=None):
2078         if func.isGenerator:
2079             self.output('throw new StopIteration();')
2080             return
2081
2082         self.start('return ')
2083
2084         cast = False
2085         if assign_needs_cast(node.value, func, func.retnode.thing, func):
2086             #print 'cast!', node
2087             cast = True
2088             self.append('(('+typesetreprnew(func.retnode.thing, func)+')(')
2089
2090         elif isinstance(node.value, Name) and node.value.name == 'self': # XXX integrate with assign_needs_cast!? # XXX self?
2091             lcp = lowest_common_parents(polymorphic_t(self.mergeinh[func.retnode.thing])) # XXX simplify
2092             if lcp:
2093                 cl = lcp[0] # XXX simplify
2094                 if not (cl == func.parent or cl in func.parent.ancestors()): 
2095                     self.append('('+cl.ident+' *)')
2096
2097         self.visit(node.value, func)
2098         if cast: self.append('))')
2099         self.eol()
2100
2101     def tuple_assign(self, lvalue, rvalue, func): 
2102         temp = getmv().tempcount[lvalue]
2103
2104         if isinstance(lvalue, tuple): nodes = lvalue
2105         else: nodes = lvalue.nodes
2106
2107         # --- nested unpacking assignment: a, (b,c) = d, e
2108         if [item for item in nodes if not isinstance(item, AssName)]:
2109             self.start(temp+' = ')
2110             if isinstance(rvalue, str):
2111                 self.append(rvalue)
2112             else:
2113                 self.visit(rvalue, func)
2114             self.eol()
2115
2116             for i, item in enumerate(nodes):
2117                 ident, arg = get_ident(Const(i)), ''
2118                 if ident == '__getitem__':
2119                     arg = str(i)
2120                 selector = '%s->%s(%s)' % (temp, ident, arg)
2121
2122                 if isinstance(item, AssName):
2123                     if item.name != '_':
2124                         self.output('%s = %s;' % (item.name, selector)) 
2125                 elif isinstance(item, (AssTuple, AssList)): # recursion
2126                     self.tuple_assign(item, selector, func)
2127                 elif isinstance(item, Subscript):
2128                     self.assign_pair(item, selector, func) 
2129                 elif isinstance(item, AssAttr):
2130                     self.assign_pair(item, selector, func) 
2131                     self.eol(' = '+selector)
2132
2133         # --- non-nested unpacking assignment: a,b,c = d 
2134         else: 
2135             self.start()
2136             self.visitm(temp, ' = ', rvalue, func)
2137             self.eol()
2138
2139             for (n, item) in enumerate(lvalue.nodes):
2140                 if item.name != '_': 
2141                     self.start()
2142                     if isinstance(rvalue, Const): sel = '__getitem__(%d)' % n
2143                     elif len(lvalue.nodes) > 2: sel = '__getfast__(%d)' % n
2144                     elif n == 0: sel = '__getfirst__()' # XXX merge
2145                     else: sel = '__getsecond__()'
2146                     self.visitm(item, ' = ', temp, '->'+sel, func)
2147                     self.eol()
2148             
2149     def subs_assign(self, lvalue, func):
2150         if defclass('list') in [t[0] for t in self.mergeinh[lvalue.expr]]:
2151             #if isinstance(lvalue.expr, Name):
2152             self.append('ELEM((')
2153             self.refer(lvalue.expr, func)
2154             self.append('),')
2155             self.visit(lvalue.subs[0], func)
2156             #else:
2157             #    self.append(getmv().tempcount[lvalue.expr]+' = ')
2158             #    self.refer(lvalue.expr, func)
2159             #    self.eol()
2160             #    self.start('')
2161             #    self.append('ELEM('+getmv().tempcount[lvalue.expr]+',')
2162             #    self.visit(lvalue.subs[0], func)
2163             self.append(')')
2164
2165         else:
2166             if len(lvalue.subs) > 1:
2167                 subs = inode(lvalue.expr).faketuple
2168             else:
2169                 subs = lvalue.subs[0]
2170             self.visitm(lvalue.expr, self.connector(lvalue.expr, func), '__setitem__(', subs, ', ', func)
2171
2172     def visitAssign(self, node, func=None):
2173         #print 'assign', node
2174
2175         #temp vars
2176         if len(node.nodes) > 1 or isinstance(node.expr, Tuple):
2177             if isinstance(node.expr, Tuple):
2178                 if [n for n in node.nodes if isinstance(n, AssTuple)]: # XXX a,b=d[i,j]=..?
2179                     for child in node.expr.nodes:
2180                         if not (child,0,0) in getgx().cnode: # (a,b) = (1,2): (1,2) never visited
2181                             continue
2182                         if not isinstance(child, Const) and not (isinstance(child, Name) and child.name == 'None'):
2183                             self.start(getmv().tempcount[child]+' = ')
2184                             self.visit(child, func)
2185                             self.eol()
2186             elif not isinstance(node.expr, Const) and not (isinstance(node.expr, Name) and node.expr.name == 'None'):
2187                 self.start(getmv().tempcount[node.expr]+' = ')
2188                 self.visit(node.expr, func)
2189                 self.eol()
2190
2191         # a = (b,c) = .. = expr
2192         right = node.expr
2193         for left in node.nodes:
2194             pairs = assign_rec(left, node.expr)
2195             tempvars = len(pairs) > 1
2196
2197             for (lvalue, rvalue) in pairs:
2198                 self.start('') # XXX remove?
2199                 
2200                 # expr[expr] = expr
2201                 if isinstance(lvalue, Subscript) and not isinstance(lvalue.subs[0], Sliceobj):
2202                     self.assign_pair(lvalue, rvalue, func)
2203                     continue
2204
2205                 # expr.attr = expr
2206                 elif isinstance(lvalue, AssAttr):
2207                     lcp = lowest_common_parents(polymorphic_t(self.mergeinh[lvalue.expr]))
2208                     if len(lcp) == 1 and isinstance(lcp[0], class_) and lvalue.attrname in lcp[0].properties:
2209                         self.visitm(lvalue.expr, '->'+lcp[0].properties[lvalue.attrname][1]+'(', rvalue, ')', func)
2210                         self.eol()
2211                         continue
2212
2213                     self.assign_pair(lvalue, rvalue, func)
2214                     self.append(' = ')
2215
2216                 # name = expr: if name non-escaping, allocate list (comprehension) on stack
2217                 elif isinstance(lvalue, AssName):
2218                     if lvalue.name != '_':
2219                         self.visit(lvalue, func)
2220                         self.append(' = ')
2221
2222                 # (a,(b,c), ..) = expr
2223                 elif isinstance(lvalue, (AssTuple, AssList)):
2224                     self.tuple_assign(lvalue, rvalue, func)
2225                     continue
2226             
2227                 # expr[a:b] = expr
2228                 elif isinstance(lvalue, Slice):
2229                     if isinstance(rvalue, Slice) and lvalue.upper == rvalue.upper == None and lvalue.lower == rvalue.lower == None:
2230                         self.visitm(lvalue.expr, self.connector(lvalue.expr, func), 'units = ', rvalue.expr, self.connector(rvalue.expr, func), 'units', func)
2231                     else:
2232                         self.visitSlice(lvalue, func)
2233                     self.eol()
2234                     continue
2235
2236                 # expr[a:b:c] = expr
2237                 elif isinstance(lvalue, Subscript) and isinstance(lvalue.subs[0], Sliceobj):
2238                     self.visit(inode(lvalue.expr).fakefunc, func)
2239                     self.eol()
2240                     continue
2241
2242                 # --- cast incompatible types (XXX conversion in cases)
2243                 cast = False
2244                 if isinstance(lvalue, AssName) and lvalue.name != '_': # XXX hm
2245                     var = lookupvar(lvalue.name, func) 
2246                 
2247                     if assign_needs_cast(rvalue, func, var, func):
2248                         #print 'cast!', lvalue, rvalue
2249                         cast = True
2250                         self.append('(('+typesetreprnew(var, func)+')(')
2251
2252                 if rvalue in getmv().tempcount:
2253                     self.append(getmv().tempcount[rvalue])
2254                 else:
2255                     self.visit(rvalue, func)
2256                 if cast: self.append('))')
2257                 self.eol()
2258
2259     def assign_pair(self, lvalue, rvalue, func):
2260         self.start('')
2261
2262         # expr[expr] = expr
2263         if isinstance(lvalue, Subscript) and not isinstance(lvalue.subs[0], Sliceobj):
2264             self.subs_assign(lvalue, func)
2265             if defclass('list') in [t[0] for t in self.mergeinh[lvalue.expr]]:
2266                 self.append(' = ')
2267
2268             if isinstance(rvalue, str):
2269                 self.append(rvalue)
2270             elif rvalue in getmv().tempcount:
2271                 self.append(getmv().tempcount[rvalue])
2272             else:
2273                 self.visit(rvalue, func)
2274
2275             if not defclass('list') in [t[0] for t in self.mergeinh[lvalue.expr]]:
2276                 self.append(')')
2277             self.eol()
2278
2279         # expr.x = expr
2280         elif isinstance(lvalue, AssAttr):
2281             self.visitAssAttr(lvalue, func)
2282
2283     def listcomp_func(self, node):
2284         # --- [x*y for (x,y) in z if c]
2285         lcfunc, func = self.listcomps[node]
2286
2287         # --- formals: target, z if not Name, out-of-scopes 
2288         args = []
2289
2290         for qual in node.quals:
2291             if not fastfor(qual) and not isinstance(qual.list, Name): # XXX ugly!!
2292                 getmv().tempcount[qual.list] = varname = '__'+str(len(getmv().tempcount)) 
2293                 args.append(typesetreprnew(qual.list, lcfunc)+varname) 
2294
2295         for name in lcfunc.misses:
2296             if lookupvar(name, func).parent:
2297                 args.append(typesetreprnew(lookupvar(name, lcfunc), lcfunc)+self.cpp_name(name))
2298
2299         ts = typesetreprnew(node, lcfunc) 
2300         if not ts.endswith('*'): ts += ' '
2301         trepr = ''
2302         if lcfunc.tvars:
2303             trepr = 'template<'+', '.join(['class '+tvar.name for tvar in lcfunc.tvars])+'> ' 
2304         self.output(trepr+'static inline '+ts+lcfunc.ident+'('+', '.join(args)+') {')
2305         self.indent()
2306
2307         # --- local: (x,y), result
2308         decl = {}
2309         for (name,var) in lcfunc.vars.items(): # XXX merge with visitFunction 
2310             name = self.cpp_name(name)
2311             decl.setdefault(typesetreprnew(var, lcfunc), []).append(name)
2312         for ts, names in decl.items():
2313             if ts.endswith('*'):
2314                 self.output(ts+', *'.join(names)+';')
2315             else:
2316                 self.output(ts+', '.join(names)+';')
2317
2318         self.output(typesetreprnew(node, lcfunc)+'result = new '+typesetreprnew(node, lcfunc)[:-2]+'();')
2319         print >>self.out
2320          
2321         self.listcomp_rec(node, node.quals, lcfunc)
2322       
2323         # --- return result
2324         self.output('return result;')
2325         self.deindent();
2326         self.output('}\n')
2327
2328     def fastfor_switch(self, node, func):
2329         self.start()
2330         for arg in node.list.args:
2331             if arg in getmv().tempcount:
2332                 self.start()
2333                 self.visitm(getmv().tempcount[arg], ' = ', arg, func)
2334                 self.eol()
2335         self.start('if(')
2336         if node.list.args[2] in getmv().tempcount:
2337             self.append(getmv().tempcount[node.list.args[2]])
2338         else:
2339             self.visit(node.list.args[2])
2340         self.append('>0) {')
2341         print >>self.out, self.line
2342
2343     # --- nested for loops: loop headers, if statements
2344     def listcomp_rec(self, node, quals, lcfunc):
2345         if not quals:
2346             if len(node.quals) == 1 and not fastfor(node.quals[0]) and not node.quals[0].ifs and not [t for t in self.mergeinh[node.quals[0].list] if t[0] not in (defclass('tuple'), defclass('list'))]:
2347                 self.start('result->units['+getmv().tempcount[node.quals[0]]+'] = ')
2348                 self.visit(node.expr, lcfunc)
2349             else:
2350                 self.start('result->append(')
2351                 self.visit(node.expr, lcfunc)
2352                 self.append(')')
2353             self.eol()
2354             return
2355
2356         qual = quals[0]
2357
2358         # iter var
2359         if isinstance(qual.assign, AssName):
2360             if qual.assign.name != '_':
2361                 var = lookupvar(qual.assign.name, lcfunc)
2362             else:
2363                 var = lookupvar(getmv().tempcount[(qual.assign,1)], lcfunc)
2364         else:
2365             var = lookupvar(getmv().tempcount[qual.assign], lcfunc)
2366
2367         iter = self.cpp_name(var.name)
2368
2369         # for in
2370         if fastfor(qual):
2371             if len(qual.list.args) == 3 and not const_literal(qual.list.args[2]):
2372                 self.fastfor_switch(qual, lcfunc)
2373                 self.indent()
2374                 self.fastfor(qual, iter, '', lcfunc)
2375                 self.listcompfor_body(node, quals, iter, lcfunc)
2376                 self.deindent()
2377                 self.output('} else {')
2378                 self.indent()
2379                 self.fastfor(qual, iter, '_NEG', lcfunc)
2380                 self.listcompfor_body(node, quals, iter, lcfunc)
2381                 self.deindent()
2382                 self.output('}')
2383             else:
2384                 neg=''
2385                 if len(qual.list.args) == 3 and const_literal(qual.list.args[2]) and isinstance(qual.list.args[2], UnarySub): 
2386                     neg = '_NEG'
2387                 self.fastfor(qual, iter, neg, lcfunc)
2388                 self.listcompfor_body(node, quals, iter, lcfunc)
2389
2390         else:
2391             pref = ''
2392             if not [t for t in self.mergeinh[qual.list] if t[0] not in (defclass('tuple'), defclass('list'))]:
2393                 pref = '_SEQ'
2394
2395             if not isinstance(qual.list, Name):
2396                 itervar = getmv().tempcount[qual.list]
2397             else:
2398                 itervar = self.cpp_name(qual.list.name)
2399
2400             if len(node.quals) == 1 and not qual.ifs and pref == '_SEQ':
2401                 self.output('result->resize(len('+itervar+'));')
2402
2403             if pref == '': tail = getmv().tempcount[(qual,1)][2:]
2404             else: tail = getmv().tempcount[qual.list][2:]+','+getmv().tempcount[qual][2:]
2405
2406             self.start('FOR_IN'+pref+'('+iter+','+itervar+','+tail)
2407             print >>self.out, self.line+')'
2408
2409             self.listcompfor_body(node, quals, iter, lcfunc)
2410
2411     def listcompfor_body(self, node, quals, iter, lcfunc):
2412         qual = quals[0]
2413
2414         self.indent()
2415
2416         if isinstance(qual.assign, (AssTuple, AssList)):
2417             self.tuple_assign(qual.assign, iter, lcfunc)
2418
2419         # if statements
2420         if qual.ifs: 
2421             self.start('if (')
2422             self.indent()
2423             for cond in qual.ifs:
2424                 self.bool_test(cond.test, lcfunc)
2425                 if cond != qual.ifs[-1]:
2426                     self.append(' && ')
2427             self.append(') {')
2428             print >>self.out, self.line
2429
2430         # recurse
2431         self.listcomp_rec(node, quals[1:], lcfunc)
2432
2433         # --- nested for loops: loop tails
2434         if qual.ifs: 
2435             self.deindent();
2436             self.output('}')
2437         self.deindent();
2438         self.output('END_FOR\n')
2439
2440     def visitListComp(self, node, func=None): #, target=None):
2441         lcfunc, _ = self.listcomps[node]
2442         args = []
2443         temp = self.line
2444
2445         for qual in node.quals:
2446             if not fastfor(qual) and not isinstance(qual.list, Name):
2447                 self.line = ''
2448                 self.visit(qual.list, func)
2449                 args.append(self.line)
2450
2451         for name in lcfunc.misses:
2452             var = lookupvar(name, func)
2453             if var.parent:
2454                 if name == 'self' and not func.listcomp: # XXX parent?
2455                     args.append('this')
2456                 else:
2457                     args.append(self.cpp_name(name))
2458
2459         self.line = temp
2460         self.append(lcfunc.ident+'('+', '.join(args)+')')
2461
2462     def visitSubscript(self, node, func=None):
2463         if node.flags == 'OP_DELETE':
2464             self.start()
2465             if isinstance(node.subs[0], Sliceobj):
2466                 self.visitCallFunc(inode(node.expr).fakefunc, func)
2467                 self.eol()
2468                 return
2469
2470             self.visitCallFunc(inode(node.expr).fakefunc, func)
2471             #self.visitm(node.expr, '->__delitem__(', node.subs[0], ')', func) # XXX
2472             self.eol()
2473             return
2474
2475         self.visitCallFunc(inode(node.expr).fakefunc, func)
2476         return
2477
2478     def visitMod(self, node, func=None):
2479         if [t for t in self.mergeinh[node.left] if t[0].ident != 'str_']:
2480             self.visitBinary(node.left, node.right, '__mod__', '%', func)
2481             return
2482
2483         elif not isinstance(node.left, Const):
2484             error('left-hand string in mod operation should be constant', node.left, warning=True)
2485             self.visitm(node.left, '%', node.right, func)
2486             return
2487
2488         self.visitm('__mod(', node.left, func)
2489
2490         # pair conversion flags to mod args
2491         # XXX error("unsupported format character", node)
2492
2493         flags = [] # XXX use in getmv().visitMod
2494         state = 0
2495         for i, c in enumerate(node.left.value):
2496             if c == '%':
2497                 state = 1-state
2498                 continue
2499             if state == 0:
2500                 continue
2501             if c in 'diouxXeEfFgGcrs':
2502                 flags.append(c)
2503                 state = 0
2504
2505         if state == 1:
2506             error("incomplete format", node, warning=True)
2507
2508         # str % t
2509         if node.right in self.mergeinh and ('tuple' in [t[0].ident for t in self.mergeinh[node.right]] or 'tuple2' in [t[0].ident for t in self.mergeinh[node.right]]):
2510             self.visitm(', ', node.right, func)
2511
2512         else:
2513             # str % (..)
2514             if isinstance(node.right, Tuple):
2515                 nodes = node.right.nodes
2516
2517             # str % non-t
2518             else:
2519                 nodes = [node.right]
2520
2521             if len(flags) != len(nodes):
2522                 error("wrong number of format arguments", node, warning=True)
2523
2524             for (f, n) in zip(flags, nodes):
2525                 if f == 'c' and 'int_' in [t[0].ident for t in self.mergeinh[n]]:
2526                     self.visitm(', chr(', n, ')', func)
2527                 elif f in 'eEfFgG' and 'float_' not in [t[0].ident for t in self.mergeinh[n]]:
2528                     self.visitm(', __float(', n, ')', func)
2529                 elif f in 'diouxX' and (not 'int_' in [t[0].ident for t in self.mergeinh[n]] or 'float_' in [t[0].ident for t in self.mergeinh[n]]):
2530                     self.visitm(', __int(', n, ')', func)
2531                 elif f in 'sr' and 'float_' in [t[0].ident for t in self.mergeinh[n]]:
2532                     self.visitm(', new float_(', n, ')', func)
2533                 elif f in 'sr' and 'int_' in [t[0].ident for t in self.mergeinh[n]]:
2534                     self.visitm(', new int_(', n, ')', func)
2535                 else:
2536                     self.visitm(', ', n, func)
2537
2538         self.append(')')
2539
2540     def visitPrintnl(self, node, func=None):
2541         self.visitPrint(node, func, '\\n')
2542
2543     def visitPrint(self, node, func=None, newline=None):
2544         fstring = []
2545         self.line = ''
2546
2547         for n in node.nodes:
2548             self.append(', ')
2549
2550             types = [t[0].ident for t in self.mergeinh[n]]
2551             if 'float_' in types: fstring.append('%h') 
2552             elif 'int_' in types: fstring.append('%d')
2553             else: fstring.append('%s')
2554
2555             self.visit(n, func)
2556
2557         fmt = ' '.join(fstring).replace('\n', '\\n')
2558         if newline: fmt += newline
2559
2560         line = self.line
2561         if not newline: self.start('printc(')
2562         else: self.start('print(')
2563         if node.dest:
2564             self.visitm(node.dest, ', ', func)
2565         line = '"'+fmt+'"'+line+')'
2566         self.eol(line)
2567
2568     def visitGetattr(self, node, func=None):
2569         module = lookupmodule(node.expr, inode(node).mv.imports)
2570         cl = lookupclass(node.expr, inode(node).mv.imports)
2571
2572         if cl and node.attrname in cl.staticmethods: # staticmethod
2573             ident = cl.ident
2574             if cl.ident in ['dict', 'defaultdict']: # own namespace because of template vars
2575                 self.append('__'+cl.ident+'__::')
2576             elif isinstance(node.expr, Getattr):
2577                 submod = lookupmodule(node.expr.expr, inode(node).mv.imports)
2578                 self.append(namespace(submod)+'::'+ident+'::')
2579             else:
2580                 self.append(ident+'::')
2581
2582         elif module and not (isinstance(node.expr, Name) and lookupvar(node.expr.name, func)): # XXX forbid redef?
2583             self.append(namespace(module)+'::') 
2584
2585         else:
2586             if not isinstance(node.expr, (Name)):
2587                 self.append('(')
2588             if isinstance(node.expr, Name) and not lookupvar(node.expr.name, func): # XXX XXX
2589                 self.append(node.expr.name)
2590             else:
2591                 if module:
2592                     self.append(namespace(module)) 
2593                 else:
2594                     self.visit(node.expr, func)
2595             if not isinstance(node.expr, (Name)):
2596                 self.append(')')
2597
2598             self.append(self.connector(node.expr, func))
2599
2600         if self.bastard(node.attrname, node.expr):
2601             ident = '__getitem__'
2602         else:
2603             ident = node.attrname
2604
2605         lcp = lowest_common_parents(polymorphic_t(self.mergeinh[node.expr]))
2606         if len(lcp) == 1 and isinstance(lcp[0], class_) and node.attrname in lcp[0].properties:
2607             self.append(lcp[0].properties[node.attrname][0]+'()')
2608             return
2609
2610         if ident == '__getitem__':
2611             lcp = lowest_common_parents(polymorphic_t(self.mergeinh[node.expr]))
2612             if len(lcp) == 1 and lcp[0] == defclass('list'):
2613                 ident = '__getfast__'
2614
2615         self.append(self.cpp_name(ident))
2616
2617     def visitAssAttr(self, node, func=None): # XXX stack/static
2618         module = lookupmodule(node.expr, inode(node).mv.imports)
2619         if module and not (isinstance(node.expr, Name) and lookupvar(node.expr.name, func)):
2620             self.append(namespace(module)+'::'+self.cpp_name(node.attrname))
2621         else:
2622             if isinstance(node.expr, Name) and not lookupvar(node.expr.name, func): # XXX XXX
2623                 self.append(node.expr.name)
2624             else:
2625                 self.visit(node.expr, func)
2626             self.append(self.connector(node.expr, func)+self.cpp_name(node.attrname))
2627
2628     def visitAssName(self, node, func=None):
2629         self.append(self.cpp_name(node.name))
2630
2631     def visitName(self, node, func=None, add_cl=True):
2632         map = {'True': '1', 'False': '0', 'self': 'this'}
2633         if node.name == 'None':
2634             self.append('0')
2635         elif node.name == 'self' and ((func and func.listcomp) or not isinstance(func.parent, class_)):
2636             self.append('self')
2637         elif node.name in map:
2638             self.append(map[node.name])
2639
2640         else: # XXX clean up
2641             if not self.mergeinh[node] and not inode(node).parent in getgx().inheritance_relations:
2642                 error("variable '"+node.name+"' has no type", node, warning=True)
2643                 self.append(node.name)
2644             elif singletype(node, module):
2645                 self.append('__'+singletype(node, module).ident+'__')
2646             else:
2647                 if (defclass('class_'),0) in self.mergeinh[node]:
2648                     self.append('cl_'+node.name)
2649                 elif add_cl and [t for t in self.mergeinh[node] if isinstance(t[0], static_class)]:
2650                     self.append('cl_'+node.name)
2651                 else:
2652                     self.append(self.cpp_name(node.name))
2653                 
2654     def expandspecialchars(self, value):
2655         value = list(value)
2656         replace = dict(['\\\\', '\nn', '\tt', '\rr', '\ff', '\bb', '\vv', '""'])
2657
2658         for i in range(len(value)):
2659             if value[i] in replace: 
2660                 value[i] = '\\'+replace[value[i]]
2661             elif value[i] not in string.printable:
2662                 value[i] = '\\'+oct(ord(value[i])).zfill(4)[1:]
2663              
2664         return ''.join(value)
2665
2666     def visitConst(self, node, func=None):
2667         if not self.filling_consts and isinstance(node.value, str): 
2668             self.append(self.get_constant(node))
2669             return
2670
2671         if node.value == None: 
2672             self.append('0')
2673             return
2674
2675         t = list(inode(node).types())[0]
2676
2677         if t[0].ident == 'int_':
2678             self.append(str(node.value)) 
2679         elif t[0].ident == 'float_': 
2680             if str(node.value) in ['inf', '1.#INF', 'Infinity']: self.append('INFINITY')
2681             elif str(node.value) in ['-inf', '-1.#INF', 'Infinity']: self.append('-INFINITY')
2682             else: self.append(str(node.value)) 
2683         elif t[0].ident == 'str_': 
2684             self.append('new str("%s"' % self.expandspecialchars(node.value))
2685             if '\0' in node.value: # '\0' delimiter in C
2686                 self.append(', %d' % len(node.value))
2687             self.append(')')
2688         else: 
2689             self.append('new %s(%s)' % (t[0].ident, node.value))
2690
2691 # --- helper functions
2692
2693 def singletype(node, type):
2694     types = [t[0] for t in inode(node).types()]
2695     if len(types) == 1 and isinstance(types[0], type):
2696         return types[0]
2697     return None
2698
2699 def namespace(module):
2700     return '__'+'__::__'.join(module.mod_path)+'__'
2701
2702 # --- determine representation of node type set (within parameterized context)
2703 def typesetreprnew(node, parent, cplusplus=True):
2704     orig_parent = parent
2705     while is_listcomp(parent): # XXX redundant with typesplit?
2706         parent = parent.parent
2707
2708     # --- separate types in multiple duplicates, so we can do parallel template matching of subtypes..
2709     split = typesplit(node, parent)
2710
2711     # --- use this 'split' to determine type representation
2712     ts = typestrnew(split, parent, cplusplus, orig_parent, node) 
2713     if cplusplus: 
2714         if not ts.endswith('*'): ts += ' '
2715         return ts
2716     return '['+ts+']'
2717
2718 def typestrnew(split, root_class, cplusplus, orig_parent, node=None):
2719     #print 'typestrnew', split, root_class
2720
2721     # --- annotation or c++ code
2722     conv1 = {'int_': 'int', 'float_': 'double', 'str_': 'str', 'none': 'int'}
2723     conv2 = {'int_': 'int', 'float_': 'float', 'str_': 'str', 'class_': 'class', 'none': 'None'}
2724     if cplusplus: sep, ptr, conv = '<>', ' *', conv1
2725     else: sep, ptr, conv = '()', '', conv2
2726
2727     def map(ident):
2728         if cplusplus: return ident+' *'
2729         return conv.get(ident, ident)
2730
2731     # --- examine split
2732     alltypes = set() # XXX
2733     for (dcpa, cpa), types in split.items():
2734         alltypes.update(types)
2735
2736     anon_funcs = set([t[0] for t in alltypes if isinstance(t[0], function)])
2737     if anon_funcs:
2738         f = anon_funcs.pop()
2739         if not f in getmv().lambda_signum: # XXX method reference
2740             return '__method_ref_0'
2741         return 'lambda'+str(getmv().lambda_signum[f])
2742
2743     classes = polymorphic_cl(split_classes(split))
2744     lcp = lowest_common_parents(classes)
2745
2746     # --- multiple parent classes: check template variables
2747     if len(lcp) > 1:              
2748         tvar = template_match(split, root_class, orig_parent)
2749         if tvar: return tvar.name
2750         if set(lcp) == set([defclass('int_'),defclass('float_')]):
2751             return conv['float_']
2752         if inode(node).mv.module.builtin:
2753             return '***ERROR*** '
2754         if isinstance(node, variable):
2755             if not node.name.startswith('__') :
2756                 #print 'beh', classes, lcp, split, template_match(split, root_class, orig_parent)
2757
2758                 if orig_parent: varname = "%s" % node
2759                 else: varname = "'%s'" % node
2760                 error("variable %s has dynamic (sub)type: {%s}" % (varname, ', '.join([conv2.get(cl.ident, cl.ident) for cl in lcp])), warning=True)
2761         elif not isinstance(node, (Or,And)):
2762             error("expression has dynamic (sub)type: {%s}" % ', '.join([conv2.get(cl.ident, cl.ident) for cl in lcp]), node, warning=True)
2763
2764     elif not classes:
2765         if cplusplus: return 'void *'
2766         return ''
2767
2768     cl = lcp.pop() 
2769
2770     # --- simple built-in types
2771     if cl.ident in ['int_', 'float_','none']:
2772         return conv[cl.ident]
2773     elif cl.ident == 'str_':
2774         return 'str'+ptr 
2775             
2776     # --- namespace prefix
2777     namespace = ''
2778     if cl.module not in [getmv().module, getgx().modules['builtin']] and not (cl.ident in getmv().ext_funcs or cl.ident in getmv().ext_classes):
2779         if cplusplus: namespace = '__'+'__::__'.join([n for n in cl.module.mod_path])+'__::'
2780         else: namespace = '::'.join([n for n in cl.module.mod_path])+'::'
2781
2782         if cl.module.filename.endswith('__init__.py'): # XXX only pass cl.module
2783             include = '/'.join(cl.module.mod_path)+'/__init__.hpp'
2784         else:
2785             include = '/'.join(cl.module.mod_path)+'.hpp'
2786         getmv().module.prop_includes.add(include)
2787
2788     # --- recurse for types with parametric subtypes
2789     template_vars = cl.template_vars # XXX why needed
2790     if cl.ident in ['pyiter', 'pyseq','pyset']: # XXX dynamic subtype check
2791         for c in classes:
2792             if 'A' in c.template_vars:
2793                 template_vars = {'A': c.template_vars['A']}
2794
2795     if not template_vars:
2796         if cl.ident in getgx().cpp_keywords:
2797             return namespace+getgx().ss_prefix+map(cl.ident)
2798         return namespace+map(cl.ident)
2799
2800     subtypes = [] 
2801     for tvar in template_vars:
2802         if cl.ident == 'tuple' and tvar != cl.unittvar:
2803             continue
2804
2805         subsplit = split_subsplit(split, tvar)
2806         subtypes.append(typestrnew(subsplit, root_class, cplusplus, orig_parent, node))
2807
2808     ident = cl.ident
2809
2810  &nb