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