we only need one warning for 'isinstance'
[shedskin:mainline.git] / shedskin / graph.py
1 '''
2 *** SHED SKIN Python-to-C++ Compiler ***
3 Copyright 2005-2013 Mark Dufour; License GNU GPL version 3 (See LICENSE)
4
5 graph.py: build constraint graph used in dataflow analysis
6
7 constraint graph: graph along which possible types 'flow' during an 'abstract execution' of a program (a dataflow analysis). consider the assignment statement 'a = b'. it follows that the set of possible types of b is smaller than or equal to that of a (a constraint). we can determine possible types of a, by 'flowing' the types from b to a, in other words, along the constraint.
8
9 constraint graph nodes are stored in gx.cnode, and the set of types of for each node in gx.types. nodes are identified by an AST Node, and two integers. the integers are used in py to duplicate parts of the constraint graph along two dimensions. in the initial constraint graph, these integers are always 0.
10
11 class ModuleVisitor: inherits visitor pattern from compiler.visitor.ASTVisitor, to recursively generate constraints for each syntactical Python construct. for example, the visitFor method is called in case of a for-loop. temporary variables are introduced in many places, to enable translation to a lower-level language.
12
13 parse_module(): locate module by name (e.g. 'os.path'), and use ModuleVisitor if not cached
14
15 '''
16 import copy
17 import os
18 import re
19 import sys
20 from compiler.ast import Const, AssTuple, AssList, From, Add, ListCompFor, \
21     UnaryAdd, Import, Bitand, Stmt, Assign, FloorDiv, Not, Mod, AssAttr, \
22     Keyword, GenExpr, LeftShift, AssName, Div, Or, Lambda, And, CallFunc, \
23     Global, Slice, RightShift, Sub, Getattr, Dict, Ellipsis, Mul, \
24     Subscript, Function as FunctionNode, Return, Power, Bitxor, Class as ClassNode, Name, List, \
25     Discard, Sliceobj, Tuple, Pass, UnarySub, Bitor, ListComp
26 from compiler.visitor import ASTVisitor
27
28 from error import error
29 from infer import inode, in_out, CNode, default_var, register_temp_var
30 from python import StaticClass, lookup_func, Function, is_zip2, \
31     lookup_class, is_method, is_literal, is_enum, lookup_var, assign_rec, \
32     Class, is_property_setter, is_fastfor, aug_msg, \
33     Module, def_class, parse_file, find_module
34
35
36 # --- global variable mv
37 _mv = None
38
39
40 def setmv(mv):
41     global _mv
42     _mv = mv
43     return _mv
44
45
46 def getmv():
47     return _mv
48
49
50 class FakeGetattr3(Getattr):
51     pass
52
53
54 class FakeGetattr2(Getattr):
55     pass
56
57
58 class FakeGetattr(Getattr):
59     pass  # XXX ugly
60
61
62 def check_redef(gx, node, s=None, onlybuiltins=False):  # XXX to modvisitor, rewrite
63     if not getmv().module.builtin:
64         existing = [getmv().ext_classes, getmv().ext_funcs]
65         if not onlybuiltins:
66             existing += [getmv().classes, getmv().funcs]
67         for whatsit in existing:
68             if s is not None:
69                 name = s
70             else:
71                 name = node.name
72             if name in whatsit:
73                 error("function/class redefinition is not supported", gx, node, mv=getmv())
74
75
76 # --- maintain inheritance relations between copied AST nodes
77 def inherit_rec(gx, original, copy, mv):
78     gx.inheritance_relations.setdefault(original, []).append(copy)
79     gx.inherited.add(copy)
80     gx.parent_nodes[copy] = original
81
82     for (a, b) in zip(original.getChildNodes(), copy.getChildNodes()):
83         inherit_rec(gx, a, b, mv)
84
85
86 def register_node(node, func):
87     if func:
88         func.registered.append(node)
89
90
91 def slice_nums(nodes):
92     nodes2 = []
93     x = 0
94     for i, n in enumerate(nodes):
95         if not n or (isinstance(n, Const) and n.value is None):
96             nodes2.append(Const(0))
97         else:
98             nodes2.append(n)
99             x |= (1 << i)
100     return [Const(x)] + nodes2
101
102
103 # --- module visitor; analyze program, build constraint graph
104 class ModuleVisitor(ASTVisitor):
105     def __init__(self, module, gx):
106         ASTVisitor.__init__(self)
107         self.module = module
108         self.gx = gx
109         self.classes = {}
110         self.funcs = {}
111         self.globals = {}
112         self.lambdas = {}
113         self.imports = {}
114         self.fake_imports = {}
115         self.ext_classes = {}
116         self.ext_funcs = {}
117         self.lambdaname = {}
118         self.lwrapper = {}
119         self.tempcount = self.gx.tempcount
120         self.callfuncs = []
121         self.for_in_iters = []
122         self.listcomps = []
123         self.defaults = {}
124         self.importnodes = []
125
126     def dispatch(self, node, *args):
127         if (node, 0, 0) not in self.gx.cnode:
128             ASTVisitor.dispatch(self, node, *args)
129
130     def fake_func(self, node, objexpr, attrname, args, func):
131         if (node, 0, 0) in self.gx.cnode:  # XXX
132             newnode = self.gx.cnode[node, 0, 0]
133         else:
134             newnode = CNode(self.gx, node, parent=func, mv=getmv())
135             self.gx.types[newnode] = set()
136
137         fakefunc = CallFunc(Getattr(objexpr, attrname), args)
138         fakefunc.lineno = objexpr.lineno
139         self.visit(fakefunc, func)
140         self.add_constraint((inode(self.gx, fakefunc), newnode), func)
141
142         inode(self.gx, objexpr).fakefunc = fakefunc
143         return fakefunc
144
145     # simple heuristic for initial list split: count nesting depth, first constant child type
146     def list_type(self, node):
147         count = 0
148         child = node
149         while isinstance(child, (List, ListComp)):
150             if not child.getChildNodes():
151                 return None
152             child = child.getChildNodes()[0]
153             count += 1
154
155         if isinstance(child, (UnarySub, UnaryAdd)):
156             child = child.expr
157
158         if isinstance(child, CallFunc) and isinstance(child.node, Name):
159             map = {'int': int, 'str': str, 'float': float}
160             if child.node.name in ('range'):  # ,'xrange'):
161                 count, child = count + 1, int
162             elif child.node.name in map:
163                 child = map[child.node.name]
164             elif child.node.name in (cl.ident for cl in self.gx.allclasses) or child.node.name in getmv().classes:  # XXX getmv().classes
165                 child = child.node.name
166             else:
167                 if count == 1:
168                     return None
169                 child = None
170         elif isinstance(child, Const):
171             child = type(child.value)
172         elif isinstance(child, Name) and child.name in ('True', 'False'):
173             child = bool
174         elif isinstance(child, Tuple):
175             child = tuple
176         elif isinstance(child, Dict):
177             child = dict
178         else:
179             if count == 1:
180                 return None
181             child = None
182
183         self.gx.list_types.setdefault((count, child), len(self.gx.list_types) + 2)
184         # print 'listtype', node, self.gx.list_types[count, child]
185         return self.gx.list_types[count, child]
186
187     def instance(self, node, cl, func=None):
188         if (node, 0, 0) in self.gx.cnode:  # XXX to create_node() func
189             newnode = self.gx.cnode[node, 0, 0]
190         else:
191             newnode = CNode(self.gx, node, parent=func, mv=getmv())
192
193         newnode.constructor = True
194
195         if cl.ident in ['int_', 'float_', 'str_', 'none', 'class_', 'bool_']:
196             self.gx.types[newnode] = set([(cl, cl.dcpa - 1)])
197         else:
198             if cl.ident == 'list' and self.list_type(node):
199                 self.gx.types[newnode] = set([(cl, self.list_type(node))])
200             else:
201                 self.gx.types[newnode] = set([(cl, cl.dcpa)])
202
203     def constructor(self, node, classname, func):
204         cl = def_class(self.gx, classname)
205
206         self.instance(node, cl, func)
207         default_var(self.gx, 'unit', cl)
208
209         if classname in ['list', 'tuple'] and not node.nodes:
210             self.gx.empty_constructors.add(node)  # ifa disables those that flow to instance variable assignments
211
212         # --- internally flow binary tuples
213         if cl.ident == 'tuple2':
214             default_var(self.gx, 'first', cl)
215             default_var(self.gx, 'second', cl)
216             elem0, elem1 = node.nodes
217
218             self.visit(elem0, func)
219             self.visit(elem1, func)
220
221             self.add_dynamic_constraint(node, elem0, 'unit', func)
222             self.add_dynamic_constraint(node, elem1, 'unit', func)
223
224             self.add_dynamic_constraint(node, elem0, 'first', func)
225             self.add_dynamic_constraint(node, elem1, 'second', func)
226
227             return
228
229         # --- add dynamic children constraints for other types
230         if classname == 'dict':  # XXX filter children
231             default_var(self.gx, 'unit', cl)
232             default_var(self.gx, 'value', cl)
233
234             for child in node.getChildNodes():
235                 self.visit(child, func)
236
237             for (key, value) in node.items:  # XXX filter
238                 self.add_dynamic_constraint(node, key, 'unit', func)
239                 self.add_dynamic_constraint(node, value, 'value', func)
240         else:
241             for child in node.nodes:
242                 self.visit(child, func)
243
244             for child in self.filter_redundant_children(node):
245                 self.add_dynamic_constraint(node, child, 'unit', func)
246
247     # --- for compound list/tuple/dict constructors, we only consider a single child node for each subtype
248     def filter_redundant_children(self, node):
249         done = set()
250         nonred = []
251         for child in node.nodes:
252             type = self.child_type_rec(child)
253             if not type or not type in done:
254                 done.add(type)
255                 nonred.append(child)
256
257         return nonred
258
259     # --- determine single constructor child node type, used by the above
260     def child_type_rec(self, node):
261         if isinstance(node, (UnarySub, UnaryAdd)):
262             node = node.expr
263
264         if isinstance(node, (List, Tuple)):
265             if isinstance(node, List):
266                 cl = def_class(self.gx, 'list')
267             elif len(node.nodes) == 2:
268                 cl = def_class(self.gx, 'tuple2')
269             else:
270                 cl = def_class(self.gx, 'tuple')
271
272             merged = set()
273             for child in node.nodes:
274                 merged.add(self.child_type_rec(child))
275
276             if len(merged) == 1:
277                 return (cl, merged.pop())
278
279         elif isinstance(node, Const):
280             return (list(inode(self.gx, node).types())[0][0],)
281
282     # --- add dynamic constraint for constructor argument, e.g. '[expr]' becomes [].__setattr__('unit', expr)
283     def add_dynamic_constraint(self, parent, child, varname, func):
284         # print 'dynamic constr', child, parent
285
286         self.gx.assign_target[child] = parent
287         cu = Const(varname)
288         self.visit(cu, func)
289         fakefunc = CallFunc(FakeGetattr2(parent, '__setattr__'), [cu, child])
290         self.visit(fakefunc, func)
291
292         fakechildnode = CNode(self.gx, (child, varname), parent=func, mv=getmv())  # create separate 'fake' CNode per child, so we can have multiple 'callfuncs'
293         self.gx.types[fakechildnode] = set()
294
295         self.add_constraint((inode(self.gx, parent), fakechildnode), func)  # add constraint from parent to fake child node. if parent changes, all fake child nodes change, and the callfunc for each child node is triggered
296         fakechildnode.callfuncs.append(fakefunc)
297
298     # --- add regular constraint to function
299     def add_constraint(self, constraint, func):
300         in_out(constraint[0], constraint[1])
301         self.gx.constraints.add(constraint)
302         while isinstance(func, Function) and func.listcomp:
303             func = func.parent  # XXX
304         if isinstance(func, Function):
305             func.constraints.add(constraint)
306
307     def struct_unpack(self, rvalue, func):
308         if isinstance(rvalue, CallFunc):
309             if isinstance(rvalue.node, Getattr) and isinstance(rvalue.node.expr, Name) and rvalue.node.expr.name == 'struct' and rvalue.node.attrname == 'unpack' and lookup_var('struct', func, mv=self).imported:  # XXX imported from where?
310                 return True
311             elif isinstance(rvalue.node, Name) and rvalue.node.name == 'unpack' and 'unpack' in self.ext_funcs and not lookup_var('unpack', func, mv=self):  # XXX imported from where?
312                 return True
313
314     def struct_info(self, node, func):
315         if isinstance(node, Name):
316             var = lookup_var(node.name, func, mv=self)  # XXX fwd ref?
317             if not var or len(var.const_assign) != 1:
318                 error('non-constant format string', self.gx, node, mv=self)
319             error('assuming constant format string', self.gx, node, mv=self, warning=True)
320             fmt = var.const_assign[0].value
321         elif isinstance(node, Const):
322             fmt = node.value
323         else:
324             error('non-constant format string', self.gx, node, mv=self)
325         char_type = dict(['xx', 'cs', 'bi', 'Bi', '?b', 'hi', 'Hi', 'ii', 'Ii', 'li', 'Li', 'qi', 'Qi', 'ff', 'df', 'ss', 'ps'])
326         ordering = '@'
327         if fmt and fmt[0] in '@<>!=':
328             ordering, fmt = fmt[0], fmt[1:]
329         result = []
330         digits = ''
331         for i, c in enumerate(fmt):
332             if c.isdigit():
333                 digits += c
334             elif c in char_type:
335                 rtype = {'i': 'int', 's': 'str', 'b': 'bool', 'f': 'float', 'x': 'pad'}[char_type[c]]
336                 if rtype == 'str' and c != 'c':
337                     result.append((ordering, c, 'str', int(digits or '1')))
338                 elif digits == '0':
339                     result.append((ordering, c, rtype, 0))
340                 else:
341                     result.extend(int(digits or '1') * [(ordering, c, rtype, 1)])
342                 digits = ''
343             else:
344                 error('bad or unsupported char in struct format: ' + repr(c), self.gx, node, mv=self)
345                 digits = ''
346         return result
347
348     def struct_faketuple(self, info):
349         result = []
350         for o, c, t, d in info:
351             if d != 0 or c == 's':
352                 if t == 'int':
353                     result.append(Const(1))
354                 elif t == 'str':
355                     result.append(Const(''))
356                 elif t == 'float':
357                     result.append(Const(1.0))
358                 elif t == 'bool':
359                     result.append(Name('True'))
360         return Tuple(result)
361
362     def visitExec(self, node, func=None):
363         error("'exec' is not supported", self.gx, node, mv=getmv())
364
365     def visitGenExpr(self, node, func=None):
366         newnode = CNode(self.gx, node, parent=func, mv=getmv())
367         self.gx.types[newnode] = set()
368         lc = ListComp(node.code.expr, [ListCompFor(qual.assign, qual.iter, qual.ifs, qual.lineno) for qual in node.code.quals], lineno=node.lineno)
369         register_node(lc, func)
370         self.gx.genexp_to_lc[node] = lc
371         self.visit(lc, func)
372         self.add_constraint((inode(self.gx, lc), newnode), func)
373
374     def visitStmt(self, node, func=None):
375         comments = []
376         for b in node.nodes:
377             if isinstance(b, Discard):
378                 self.bool_test_add(b.expr)
379             if isinstance(b, Discard) and isinstance(b.expr, Const) and type(b.expr.value) == str:
380                 comments.append(b.expr.value)
381             elif comments:
382                 self.gx.comments[b] = comments
383                 comments = []
384             self.visit(b, func)
385
386     def visitModule(self, node):
387         # --- bootstrap built-in classes
388         if self.module.ident == 'builtin':
389             for dummy in self.gx.builtins:
390                 self.visit(ClassNode(dummy, [], None, Pass()))
391
392         if self.module.ident != 'builtin':
393             n = From('builtin', [('*', None)], None)  # Python2.5+
394             getmv().importnodes.append(n)
395             self.visit(n)
396
397         # --- __name__
398         if self.module.ident != 'builtin':
399             namevar = default_var(self.gx, '__name__', None, mv=getmv())
400             self.gx.types[inode(self.gx, namevar)] = set([(def_class(self.gx, 'str_'), 0)])
401
402         self.forward_references(node)
403
404         # --- visit children
405         for child in node.getChildNodes():
406             if isinstance(child, Stmt):
407                 getmv().importnodes.extend(n for n in child.nodes if isinstance(n, (Import, From)))
408             self.visit(child, None)
409
410         # --- register classes
411         for cl in getmv().classes.values():
412             self.gx.allclasses.add(cl)
413
414         # --- inheritance expansion
415
416         # determine base classes
417         for cl in self.classes.values():
418             for base in cl.node.bases:
419                 if not (isinstance(base, Name) and base.name == 'object'):
420                     ancestor = lookup_class(base, getmv())
421                     cl.bases.append(ancestor)
422                     ancestor.children.append(cl)
423
424         # for each base class, duplicate methods
425         for cl in self.classes.values():
426             for ancestor in cl.ancestors_upto(None)[1:]:
427
428                 cl.staticmethods.extend(ancestor.staticmethods)
429                 cl.properties.update(ancestor.properties)
430
431                 for func in ancestor.funcs.values():
432                     if not func.node or func.inherited:
433                         continue
434
435                     ident = func.ident
436                     if ident in cl.funcs:
437                         ident += ancestor.ident + '__'
438
439                     # deep-copy AST function nodes
440                     func_copy = copy.deepcopy(func.node)
441                     inherit_rec(self.gx, func.node, func_copy, func.mv)
442                     tempmv, mv = getmv(), func.mv
443                     setmv(mv)
444                     self.visitFunction(func_copy, cl, inherited_from=ancestor)
445                     mv = tempmv
446                     setmv(mv)
447
448                     # maintain relation with original
449                     self.gx.inheritance_relations.setdefault(func, []).append(cl.funcs[ident])
450                     cl.funcs[ident].inherited = func.node
451                     cl.funcs[ident].inherited_from = func
452                     func_copy.name = ident
453
454                     if ident == func.ident:
455                         cl.funcs[ident + ancestor.ident + '__'] = cl.funcs[ident]
456
457     def stmt_nodes(self, node, cl):
458         result = []
459         for child in node.getChildNodes():
460             if isinstance(child, Stmt):
461                 for n in child.nodes:
462                     if isinstance(n, cl):
463                         result.append(n)
464         return result
465
466     def forward_references(self, node):
467         getmv().classnodes = []
468
469         # classes
470         for n in self.stmt_nodes(node, ClassNode):
471             check_redef(self.gx, n)
472             getmv().classnodes.append(n)
473             newclass = Class(self.gx, n, getmv())
474             self.classes[n.name] = newclass
475             getmv().classes[n.name] = newclass
476             newclass.module = self.module
477             newclass.parent = StaticClass(newclass, getmv())
478
479             # methods
480             for m in self.stmt_nodes(n, FunctionNode):
481                 if hasattr(m, 'decorators') and m.decorators and [dec for dec in m.decorators if is_property_setter(dec)]:
482                     m.name = m.name + '__setter__'
483                 if m.name in newclass.funcs:  # and func.ident not in ['__getattr__', '__setattr__']: # XXX
484                     error("function/class redefinition is not allowed", self.gx, m, mv=getmv())
485                 func = Function(self.gx, m, newclass, mv=getmv())
486                 newclass.funcs[func.ident] = func
487                 self.set_default_vars(m, func)
488
489         # functions
490         getmv().funcnodes = []
491         for n in self.stmt_nodes(node, FunctionNode):
492             check_redef(self.gx, n)
493             getmv().funcnodes.append(n)
494             func = getmv().funcs[n.name] = Function(self.gx, n, mv=getmv())
495             self.set_default_vars(n, func)
496
497         # global variables XXX visitGlobal
498         for assname in self.local_assignments(node, global_=True):
499             default_var(self.gx, assname.name, None, mv=getmv())
500
501     def set_default_vars(self, node, func):
502         globals = set(self.get_globals(node))
503         for assname in self.local_assignments(node):
504             if assname.name not in globals:
505                 default_var(self.gx, assname.name, func)
506
507     def get_globals(self, node):
508         if isinstance(node, Global):
509             result = node.names
510         else:
511             result = []
512             for child in node.getChildNodes():
513                 result.extend(self.get_globals(child))
514         return result
515
516     def local_assignments(self, node, global_=False):
517         if global_ and isinstance(node, (ClassNode, FunctionNode)):
518             return []
519         elif isinstance(node, (ListComp, GenExpr)):
520             return []
521         elif isinstance(node, AssName):
522             result = [node]
523         else:
524             result = []
525             for child in node.getChildNodes():
526                 result.extend(self.local_assignments(child, global_))
527         return result
528
529     def visitImport(self, node, func=None):
530         if not node in getmv().importnodes:
531             error("please place all imports (no 'try:' etc) at the top of the file", self.gx, node, mv=getmv())
532
533         for (name, pseudonym) in node.names:
534             if pseudonym:
535                 # --- import a.b as c: don't import a
536                 self.import_module(name, pseudonym, node, False)
537             else:
538                 self.import_modules(name, node, False)
539
540     def import_modules(self, name, node, fake):
541         # --- import a.b.c: import a, then a.b, then a.b.c
542         split = name.split('.')
543         module = getmv().module
544         for i in range(len(split)):
545             subname = '.'.join(split[:i + 1])
546             parent = module
547             module = self.import_module(subname, subname, node, fake)
548             if module.ident not in parent.mv.imports:  # XXX
549                 if not fake:
550                     parent.mv.imports[module.ident] = module
551         return module
552
553     def import_module(self, name, pseudonym, node, fake):
554         module = self.analyze_module(name, pseudonym, node, fake)
555         if not fake:
556             var = default_var(self.gx, pseudonym or name, None, mv=getmv())
557             var.imported = True
558             self.gx.types[inode(self.gx, var)] = set([(module, 0)])
559         return module
560
561     def visitFrom(self, node, parent=None):
562         if not node in getmv().importnodes:  # XXX use (func, node) as parent..
563             error("please place all imports (no 'try:' etc) at the top of the file", self.gx, node, mv=getmv())
564         if hasattr(node, 'level') and node.level:
565             error("relative imports are not supported", self.gx, node, mv=getmv())
566
567         if node.modname == '__future__':
568             for name, _ in node.names:
569                 if name not in ['with_statement', 'print_function']:
570                     error("future '%s' is not yet supported" % name, self.gx, node, mv=getmv())
571             return
572
573         module = self.import_modules(node.modname, node, True)
574         self.gx.from_module[node] = module
575
576         for name, pseudonym in node.names:
577             if name == '*':
578                 self.ext_funcs.update(module.mv.funcs)
579                 self.ext_classes.update(module.mv.classes)
580                 for import_name, import_module in module.mv.imports.items():
581                     var = default_var(self.gx, import_name, None, mv=getmv())  # XXX merge
582                     var.imported = True
583                     self.gx.types[inode(self.gx, var)] = set([(import_module, 0)])
584                     self.imports[import_name] = import_module
585                 for name, extvar in module.mv.globals.items():
586                     if not extvar.imported and not name in ['__name__']:
587                         var = default_var(self.gx, name, None, mv=getmv())  # XXX merge
588                         var.imported = True
589                         self.add_constraint((inode(self.gx, extvar), inode(self.gx, var)), None)
590                 continue
591
592             path = module.path
593             pseudonym = pseudonym or name
594             if name in module.mv.funcs:
595                 self.ext_funcs[pseudonym] = module.mv.funcs[name]
596             elif name in module.mv.classes:
597                 self.ext_classes[pseudonym] = module.mv.classes[name]
598             elif name in module.mv.globals and not module.mv.globals[name].imported:  # XXX
599                 extvar = module.mv.globals[name]
600                 var = default_var(self.gx, pseudonym, None, mv=getmv())
601                 var.imported = True
602                 self.add_constraint((inode(self.gx, extvar), inode(self.gx, var)), None)
603             elif os.path.isfile(os.path.join(path, name + '.py')) or \
604                     os.path.isfile(os.path.join(path, name, '__init__.py')):
605                 modname = '.'.join(module.name_list + [name])
606                 self.import_module(modname, name, node, False)
607             else:
608                 error("no identifier '%s' in module '%s'" % (name, node.modname), self.gx, node, mv=getmv())
609
610     def analyze_module(self, name, pseud, node, fake):
611         module = parse_module(name, self.gx, getmv().module, node)
612         if not fake:
613             self.imports[pseud] = module
614         else:
615             self.fake_imports[pseud] = module
616         return module
617
618     def visitFunction(self, node, parent=None, is_lambda=False, inherited_from=None):
619         if not getmv().module.builtin and (node.varargs or node.kwargs):
620             error('argument (un)packing is not supported', self.gx, node, mv=getmv())
621
622         if not parent and not is_lambda and node.name in getmv().funcs:
623             func = getmv().funcs[node.name]
624         elif isinstance(parent, Class) and not inherited_from and node.name in parent.funcs:
625             func = parent.funcs[node.name]
626         else:
627             func = Function(self.gx, node, parent, inherited_from, mv=getmv())
628             if inherited_from:
629                 self.set_default_vars(node, func)
630
631         if not is_method(func):
632             if not getmv().module.builtin and not node in getmv().funcnodes and not is_lambda:
633                 error("non-global function '%s'" % node.name, self.gx, node, mv=getmv())
634
635         if hasattr(node, 'decorators') and node.decorators:
636             for dec in node.decorators.nodes:
637                 if isinstance(dec, Name) and dec.name == 'staticmethod':
638                     parent.staticmethods.append(node.name)
639                 elif isinstance(dec, Name) and dec.name == 'property':
640                     parent.properties[node.name] = [node.name, None]
641                 elif is_property_setter(dec):
642                     parent.properties[dec.expr.name][1] = node.name
643                 else:
644                     error("unsupported type of decorator", self.gx, dec, mv=getmv())
645
646         if parent:
647             if not inherited_from and not func.ident in parent.staticmethods and (not func.formals or func.formals[0] != 'self'):
648                 error("formal arguments of method must start with 'self'", self.gx, node, mv=getmv())
649             if not func.mv.module.builtin and func.ident in ['__new__', '__getattr__', '__setattr__', '__radd__', '__rsub__', '__rmul__', '__rdiv__', '__rtruediv__', '__rfloordiv__', '__rmod__', '__rdivmod__', '__rpow__', '__rlshift__', '__rrshift__', '__rand__', '__rxor__', '__ror__', '__iter__', '__call__', '__enter__', '__exit__', '__del__', '__copy__', '__deepcopy__']:
650                 error("'%s' is not supported" % func.ident, self.gx, node, warning=True, mv=getmv())
651
652         if is_lambda:
653             self.lambdas[node.name] = func
654
655         # --- add unpacking statement for tuple formals
656         func.expand_args = {}
657         for i, formal in enumerate(func.formals):
658             if isinstance(formal, tuple):
659                 tmp = self.temp_var((node, i), func)
660                 func.formals[i] = tmp.name
661                 fake_unpack = Assign([self.unpack_rec(formal)], Name(tmp.name))
662                 func.expand_args[tmp.name] = fake_unpack
663                 self.visit(fake_unpack, func)
664
665         func.defaults = node.defaults
666
667         for formal in func.formals:
668             var = default_var(self.gx, formal, func)
669             var.formal_arg = True
670
671         # --- flow return expressions together into single node
672         func.retnode = retnode = CNode(self.gx, node, parent=func, mv=getmv())
673         self.gx.types[retnode] = set()
674         func.yieldnode = yieldnode = CNode(self.gx, (node, 'yield'), parent=func, mv=getmv())
675         self.gx.types[yieldnode] = set()
676
677         self.visit(node.code, func)
678
679         for i, default in enumerate(func.defaults):
680             if not is_literal(default):
681                 self.defaults[default] = (len(self.defaults), func, i)
682             self.visit(default, None)  # defaults are global
683
684         # --- add implicit 'return None' if no return expressions
685         if not func.returnexpr:
686             func.fakeret = Return(Name('None'))
687             self.visit(func.fakeret, func)
688
689         # --- register function
690         if isinstance(parent, Class):
691             if func.ident not in parent.staticmethods:  # XXX use flag
692                 default_var(self.gx, 'self', func)
693                 if func.ident == '__init__' and '__del__' in parent.funcs:  # XXX what if no __init__
694                     self.visit(CallFunc(Getattr(Name('self'), '__del__'), []), func)
695                     self.gx.gc_cleanup = True
696             parent.funcs[func.ident] = func
697
698     def unpack_rec(self, formal):
699         if isinstance(formal, str):
700             return AssName(formal, 'OP_ASSIGN')
701         else:
702             return AssTuple([self.unpack_rec(elem) for elem in formal])
703
704     def visitLambda(self, node, func=None):
705         lambdanr = len(self.lambdas)
706         name = '__lambda%d__' % lambdanr
707         fakenode = FunctionNode(None, name, node.argnames, node.defaults, node.flags, None, Return(node.code))
708         self.visit(fakenode, None, True)
709         f = self.lambdas[name]
710         f.lambdanr = lambdanr
711         self.lambdaname[node] = name
712         newnode = CNode(self.gx, node, parent=func, mv=getmv())
713         self.gx.types[newnode] = set([(f, 0)])
714         newnode.copymetoo = True
715
716     def visitAnd(self, node, func=None):
717         self.visit_and_or(node, func)
718
719     def visitOr(self, node, func=None):
720         self.visit_and_or(node, func)
721
722     def visit_and_or(self, node, func):
723         newnode = CNode(self.gx, node, parent=func, mv=getmv())
724         self.gx.types[newnode] = set()
725         for child in node.getChildNodes():
726             if node in self.gx.bool_test_only:
727                 self.bool_test_add(child)
728             self.visit(child, func)
729             self.add_constraint((inode(self.gx, child), newnode), func)
730             self.temp_var2(child, newnode, func)
731
732     def visitIf(self, node, func=None):
733         for test, code in node.tests:
734             self.bool_test_add(test)
735             faker = CallFunc(Name('bool'), [test])
736             self.visit(faker, func)
737             self.visit(code, func)
738         if node.else_:
739             self.visit(node.else_, func)
740
741     def visitIfExp(self, node, func=None):
742         newnode = CNode(self.gx, node, parent=func, mv=getmv())
743         self.gx.types[newnode] = set()
744
745         for child in node.getChildNodes():
746             self.visit(child, func)
747
748         self.add_constraint((inode(self.gx, node.then), newnode), func)
749         self.add_constraint((inode(self.gx, node.else_), newnode), func)
750
751     def visitGlobal(self, node, func=None):
752         func.globals += node.names
753
754     def visitList(self, node, func=None):
755         self.constructor(node, 'list', func)
756
757     def visitDict(self, node, func=None):
758         self.constructor(node, 'dict', func)
759         if node.items:  # XXX library bug
760             node.lineno = node.items[0][0].lineno
761
762     def visitNot(self, node, func=None):
763         self.bool_test_add(node.expr)
764         newnode = CNode(self.gx, node, parent=func, mv=getmv())
765         newnode.copymetoo = True
766         self.gx.types[newnode] = set([(def_class(self.gx, 'bool_'), 0)])  # XXX new type?
767         self.visit(node.expr, func)
768
769     def visitBackquote(self, node, func=None):
770         self.fake_func(node, node.expr, '__repr__', [], func)
771
772     def visitTuple(self, node, func=None):
773         if len(node.nodes) == 2:
774             self.constructor(node, 'tuple2', func)
775         else:
776             self.constructor(node, 'tuple', func)
777
778     def visitSubscript(self, node, func=None):  # XXX merge __setitem__, __getitem__
779         if len(node.subs) > 1:
780             subscript = Tuple(node.subs)
781         else:
782             subscript = node.subs[0]
783
784         if isinstance(subscript, Ellipsis):  # XXX also check at setitem
785             error('ellipsis is not supported', self.gx, node, mv=getmv())
786
787         if isinstance(subscript, Sliceobj):
788             self.slice(node, node.expr, subscript.nodes, func)
789         else:
790             if node.flags == 'OP_DELETE':
791                 self.fake_func(node, node.expr, '__delitem__', [subscript], func)
792             elif len(node.subs) > 1:
793                 self.fake_func(node, node.expr, '__getitem__', [subscript], func)
794             else:
795                 ident = '__getitem__'
796                 self.fake_func(node, node.expr, ident, [subscript], func)
797
798     def visitSlice(self, node, func=None):
799         self.slice(node, node.expr, [node.lower, node.upper, None], func)
800
801     def slice(self, node, expr, nodes, func, replace=None):
802         nodes2 = slice_nums(nodes)
803         if replace:
804             self.fake_func(node, expr, '__setslice__', nodes2 + [replace], func)
805         elif node.flags == 'OP_DELETE':
806             self.fake_func(node, expr, '__delete__', nodes2, func)
807         else:
808             self.fake_func(node, expr, '__slice__', nodes2, func)
809
810     def visitUnarySub(self, node, func=None):
811         self.fake_func(node, node.expr, '__neg__', [], func)
812
813     def visitUnaryAdd(self, node, func=None):
814         self.fake_func(node, node.expr, '__pos__', [], func)
815
816     def visitCompare(self, node, func=None):
817         newnode = CNode(self.gx, node, parent=func, mv=getmv())
818         newnode.copymetoo = True
819         self.gx.types[newnode] = set([(def_class(self.gx, 'bool_'), 0)])  # XXX new type?
820         self.visit(node.expr, func)
821         msgs = {'<': 'lt', '>': 'gt', 'in': 'contains', 'not in': 'contains', '!=': 'ne', '==': 'eq', '<=': 'le', '>=': 'ge'}
822         left = node.expr
823         for op, right in node.ops:
824             self.visit(right, func)
825             msg = msgs.get(op)
826             if msg == 'contains':
827                 self.fake_func(node, right, '__' + msg + '__', [left], func)
828             elif msg in ('lt', 'gt', 'le', 'ge'):
829                 fakefunc = CallFunc(Name('__%s' % msg), [left, right])
830                 fakefunc.lineno = left.lineno
831                 self.visit(fakefunc, func)
832             elif msg:
833                 self.fake_func(node, left, '__' + msg + '__', [right], func)
834             left = right
835
836         # tempvars, e.g. (t1=fun())
837         for term in node.ops[:-1]:
838             if not isinstance(term[1], (Name, Const)):
839                 self.temp_var2(term[1], inode(self.gx, term[1]), func)
840
841     def visitBitand(self, node, func=None):
842         self.visitBitpair(node, aug_msg(node, 'and'), func)
843
844     def visitBitor(self, node, func=None):
845         self.visitBitpair(node, aug_msg(node, 'or'), func)
846
847     def visitBitxor(self, node, func=None):
848         self.visitBitpair(node, aug_msg(node, 'xor'), func)
849
850     def visitBitpair(self, node, msg, func=None):
851         CNode(self.gx, node, parent=func, mv=getmv())
852         self.gx.types[inode(self.gx, node)] = set()
853         left = node.nodes[0]
854         for i, right in enumerate(node.nodes[1:]):
855             faker = self.fake_func((left, i), left, msg, [right], func)
856             left = faker
857         self.add_constraint((inode(self.gx, faker), inode(self.gx, node)), func)
858
859     def visitAdd(self, node, func=None):
860         self.fake_func(node, node.left, aug_msg(node, 'add'), [node.right], func)
861
862     def visitInvert(self, node, func=None):
863         self.fake_func(node, node.expr, '__invert__', [], func)
864
865     def visitRightShift(self, node, func=None):
866         self.fake_func(node, node.left, aug_msg(node, 'rshift'), [node.right], func)
867
868     def visitLeftShift(self, node, func=None):
869         self.fake_func(node, node.left, aug_msg(node, 'lshift'), [node.right], func)
870
871     def visitAugAssign(self, node, func=None):  # a[b] += c -> a[b] = a[b]+c, using tempvars to handle sidefx
872         newnode = CNode(self.gx, node, parent=func, mv=getmv())
873         self.gx.types[newnode] = set()
874
875         clone = copy.deepcopy(node)
876         lnode = node.node
877
878         if isinstance(node.node, Name):
879             blah = AssName(clone.node.name, 'OP_ASSIGN')
880         elif isinstance(node.node, Getattr):
881             blah = AssAttr(clone.node.expr, clone.node.attrname, 'OP_ASSIGN')
882         elif isinstance(node.node, Subscript):
883             t1 = self.temp_var(node.node.expr, func)
884             a1 = Assign([AssName(t1.name, 'OP_ASSIGN')], node.node.expr)
885             self.visit(a1, func)
886             self.add_constraint((inode(self.gx, node.node.expr), inode(self.gx, t1)), func)
887
888             if len(node.node.subs) > 1:
889                 subs = Tuple(node.node.subs)
890             else:
891                 subs = node.node.subs[0]
892             t2 = self.temp_var(subs, func)
893             a2 = Assign([AssName(t2.name, 'OP_ASSIGN')], subs)
894
895             self.visit(a1, func)
896             self.visit(a2, func)
897             self.add_constraint((inode(self.gx, subs), inode(self.gx, t2)), func)
898
899             inode(self.gx, node).temp1 = t1.name
900             inode(self.gx, node).temp2 = t2.name
901             inode(self.gx, node).subs = subs
902
903             blah = Subscript(Name(t1.name), 'OP_APPLY', [Name(t2.name)])
904             lnode = Subscript(Name(t1.name), 'OP_APPLY', [Name(t2.name)])
905         else:
906             error('unsupported type of assignment', self.gx, node, mv=getmv())
907
908         if node.op == '-=':
909             blah2 = Sub((lnode, node.expr))
910         if node.op == '+=':
911             blah2 = Add((lnode, node.expr))
912         if node.op == '|=':
913             blah2 = Bitor((lnode, node.expr))
914         if node.op == '&=':
915             blah2 = Bitand((lnode, node.expr))
916         if node.op == '^=':
917             blah2 = Bitxor((lnode, node.expr))
918         if node.op == '**=':
919             blah2 = Power((lnode, node.expr))
920         if node.op == '<<=':
921             blah2 = LeftShift((lnode, node.expr))
922         if node.op == '>>=':
923             blah2 = RightShift((lnode, node.expr))
924         if node.op == '%=':
925             blah2 = Mod((lnode, node.expr))
926         if node.op == '*=':
927             blah2 = Mul((lnode, node.expr))
928         if node.op == '/=':
929             blah2 = Div((lnode, node.expr))
930         if node.op == '//=':
931             blah2 = FloorDiv((lnode, node.expr))
932
933         blah2.augment = True
934
935         assign = Assign([blah], blah2)
936         register_node(assign, func)
937         inode(self.gx, node).assignhop = assign
938         self.visit(assign, func)
939
940     def visitSub(self, node, func=None):
941         self.fake_func(node, node.left, aug_msg(node, 'sub'), [node.right], func)
942
943     def visitMul(self, node, func=None):
944         self.fake_func(node, node.left, aug_msg(node, 'mul'), [node.right], func)
945
946     def visitDiv(self, node, func=None):
947         self.fake_func(node, node.left, aug_msg(node, 'div'), [node.right], func)
948
949     def visitFloorDiv(self, node, func=None):
950         self.fake_func(node, node.left, aug_msg(node, 'floordiv'), [node.right], func)
951
952     def visitPower(self, node, func=None):
953         self.fake_func(node, node.left, '__pow__', [node.right], func)
954
955     def visitMod(self, node, func=None):
956         if isinstance(node.right, (Tuple, Dict)):
957             self.fake_func(node, node.left, '__mod__', [], func)
958             for child in node.right.getChildNodes():
959                 self.visit(child, func)
960                 if isinstance(node.right, Tuple):
961                     self.fake_func(inode(self.gx, child), child, '__str__', [], func)
962         else:
963             self.fake_func(node, node.left, '__mod__', [node.right], func)
964
965     def visitPrintnl(self, node, func=None):
966         self.visitPrint(node, func)
967
968     def visitPrint(self, node, func=None):
969         pnode = CNode(self.gx, node, parent=func, mv=getmv())
970         self.gx.types[pnode] = set()
971
972         for child in node.getChildNodes():
973             self.visit(child, func)
974             self.fake_func(inode(self.gx, child), child, '__str__', [], func)
975
976     def temp_var(self, node, func=None, looper=None, wopper=None):
977         if node in self.gx.parent_nodes:
978             varname = self.tempcount[self.gx.parent_nodes[node]]
979         elif node in self.tempcount:  # XXX investigate why this happens
980             varname = self.tempcount[node]
981         else:
982             varname = '__' + str(len(self.tempcount))
983
984         var = default_var(self.gx, varname, func, mv=getmv())
985         var.looper = looper
986         var.wopper = wopper
987         self.tempcount[node] = varname
988
989         register_temp_var(var, func)
990         return var
991
992     def temp_var2(self, node, source, func):
993         tvar = self.temp_var(node, func)
994         self.add_constraint((source, inode(self.gx, tvar)), func)
995         return tvar
996
997     def temp_var_int(self, node, func):
998         var = self.temp_var(node, func)
999         self.gx.types[inode(self.gx, var)] = set([(def_class(self.gx, 'int_'), 0)])
1000         inode(self.gx, var).copymetoo = True
1001         return var
1002
1003     def visitRaise(self, node, func=None):
1004         if node.expr1 is None or node.expr2 is not None or node.expr3 is not None:
1005             error('unsupported raise syntax', self.gx, node, mv=getmv())
1006         for child in node.getChildNodes():
1007             self.visit(child, func)
1008
1009     def visitTryExcept(self, node, func=None):
1010         self.visit(node.body, func)
1011
1012         for handler in node.handlers:
1013             self.visit(handler[2], func)
1014             if not handler[0]:
1015                 continue
1016
1017             if isinstance(handler[0], Tuple):
1018                 pairs = [(n, handler[1]) for n in handler[0].nodes]
1019             else:
1020                 pairs = [(handler[0], handler[1])]
1021
1022             for (h0, h1) in pairs:
1023                 if isinstance(h0, Name) and h0.name in ['int', 'float', 'str', 'class']:
1024                     continue  # handle in lookup_class
1025                 cl = lookup_class(h0, getmv())
1026                 if not cl:
1027                     error("unknown or unsupported exception type", self.gx, h0, mv=getmv())
1028
1029                 if isinstance(h1, AssName):
1030                     var = self.default_var(h1.name, func)
1031                 else:
1032                     var = self.temp_var(h0, func)
1033
1034                 var.invisible = True
1035                 inode(self.gx, var).copymetoo = True
1036                 self.gx.types[inode(self.gx, var)] = set([(cl, 1)])
1037
1038         # else
1039         if node.else_:
1040             self.visit(node.else_, func)
1041             self.temp_var_int(node.else_, func)
1042
1043     def visitTryFinally(self, node, func=None):
1044         error("'try..finally' is not supported", self.gx, node, mv=getmv())
1045
1046     def visitYield(self, node, func):
1047         func.isGenerator = True
1048         func.yieldNodes.append(node)
1049         self.visit(Return(CallFunc(Name('__iter'), [node.value])), func)
1050         self.add_constraint((inode(self.gx, node.value), func.yieldnode), func)
1051
1052     def visitFor(self, node, func=None):
1053         # --- iterable contents -> assign node
1054         assnode = CNode(self.gx, node.assign, parent=func, mv=getmv())
1055         self.gx.types[assnode] = set()
1056
1057         get_iter = CallFunc(Getattr(node.list, '__iter__'), [])
1058         fakefunc = CallFunc(Getattr(get_iter, 'next'), [])
1059
1060         self.visit(fakefunc, func)
1061         self.add_constraint((inode(self.gx, fakefunc), assnode), func)
1062
1063         # --- assign node -> variables  XXX merge into assign_pair
1064         if isinstance(node.assign, AssName):
1065             # for x in..
1066             lvar = self.default_var(node.assign.name, func)
1067             self.add_constraint((assnode, inode(self.gx, lvar)), func)
1068
1069         elif isinstance(node.assign, AssAttr):  # XXX experimental :)
1070             # for expr.x in..
1071             CNode(self.gx, node.assign, parent=func, mv=getmv())
1072
1073             self.gx.assign_target[node.assign.expr] = node.assign.expr  # XXX multiple targets possible please
1074             fakefunc2 = CallFunc(Getattr(node.assign.expr, '__setattr__'), [Const(node.assign.attrname), fakefunc])
1075             self.visit(fakefunc2, func)
1076
1077         elif isinstance(node.assign, (AssTuple, AssList)):
1078             # for (a,b, ..) in..
1079             self.tuple_flow(node.assign, node.assign, func)
1080         else:
1081             error('unsupported type of assignment', self.gx, node, mv=getmv())
1082
1083         self.do_for(node, assnode, get_iter, func)
1084
1085         # --- for-else
1086         if node.else_:
1087             self.temp_var_int(node.else_, func)
1088             self.visit(node.else_, func)
1089
1090         # --- loop body
1091         self.gx.loopstack.append(node)
1092         self.visit(node.body, func)
1093         self.gx.loopstack.pop()
1094         self.for_in_iters.append(node.list)
1095
1096     def do_for(self, node, assnode, get_iter, func):
1097         # --- for i in range(..) XXX i should not be modified.. use tempcounter; two bounds
1098         if is_fastfor(node):
1099             self.temp_var2(node.assign, assnode, func)
1100             self.temp_var2(node.list, inode(self.gx, node.list.args[0]), func)
1101
1102             if len(node.list.args) == 3 and not isinstance(node.list.args[2], Name) and not is_literal(node.list.args[2]):  # XXX merge with ListComp
1103                 for arg in node.list.args:
1104                     if not isinstance(arg, Name) and not is_literal(arg):  # XXX create func for better check
1105                         self.temp_var2(arg, inode(self.gx, arg), func)
1106
1107         # --- temp vars for list, iter etc.
1108         else:
1109             self.temp_var2(node, inode(self.gx, node.list), func)
1110             self.temp_var2((node, 1), inode(self.gx, get_iter), func)
1111             self.temp_var_int(node.list, func)
1112
1113             if is_enum(node) or is_zip2(node):
1114                 self.temp_var2((node, 2), inode(self.gx, node.list.args[0]), func)
1115                 if is_zip2(node):
1116                     self.temp_var2((node, 3), inode(self.gx, node.list.args[1]), func)
1117                     self.temp_var_int((node, 4), func)
1118
1119             self.temp_var((node, 5), func, looper=node.list)
1120             if isinstance(node.list, CallFunc) and isinstance(node.list.node, Getattr):
1121                 self.temp_var((node, 6), func, wopper=node.list.node.expr)
1122                 self.temp_var2((node, 7), inode(self.gx, node.list.node.expr), func)
1123
1124     def bool_test_add(self, node):
1125         if isinstance(node, (And, Or, Not)):
1126             self.gx.bool_test_only.add(node)
1127
1128     def visitWhile(self, node, func=None):
1129         self.gx.loopstack.append(node)
1130         self.bool_test_add(node.test)
1131         for child in node.getChildNodes():
1132             self.visit(child, func)
1133         self.gx.loopstack.pop()
1134
1135         if node.else_:
1136             self.temp_var_int(node.else_, func)
1137             self.visit(node.else_, func)
1138
1139     def visitWith(self, node, func=None):
1140         if node.vars:
1141             varnode = CNode(self.gx, node.vars, parent=func, mv=getmv())
1142             self.gx.types[varnode] = set()
1143             self.visit(node.expr, func)
1144             self.add_constraint((inode(self.gx, node.expr), varnode), func)
1145             lvar = self.default_var(node.vars.name, func)
1146             self.add_constraint((varnode, inode(self.gx, lvar)), func)
1147         else:
1148             self.visit(node.expr, func)
1149         for child in node.getChildNodes():
1150             self.visit(child, func)
1151
1152     def visitListCompIf(self, node, func=None):
1153         self.bool_test_add(node.test)
1154         for child in node.getChildNodes():
1155             self.visit(child, func)
1156
1157     def visitListComp(self, node, func=None):
1158         # --- [expr for iter in list for .. if cond ..]
1159         lcfunc = Function(self.gx, mv=getmv())
1160         lcfunc.listcomp = True
1161         lcfunc.ident = 'l.c.'  # XXX
1162         lcfunc.parent = func
1163
1164         for qual in node.quals:
1165             # iter
1166             assnode = CNode(self.gx, qual.assign, parent=func, mv=getmv())
1167             self.gx.types[assnode] = set()
1168
1169             # list.unit->iter
1170             get_iter = CallFunc(Getattr(qual.list, '__iter__'), [])
1171             fakefunc = CallFunc(Getattr(get_iter, 'next'), [])
1172             self.visit(fakefunc, lcfunc)
1173             self.add_constraint((inode(self.gx, fakefunc), inode(self.gx, qual.assign)), lcfunc)
1174
1175             if isinstance(qual.assign, AssName):  # XXX merge with visitFor
1176                 lvar = default_var(self.gx, qual.assign.name, lcfunc)  # XXX str or Name?
1177                 self.add_constraint((inode(self.gx, qual.assign), inode(self.gx, lvar)), lcfunc)
1178             else:  # AssTuple, AssList
1179                 self.tuple_flow(qual.assign, qual.assign, lcfunc)
1180
1181             self.do_for(qual, assnode, get_iter, lcfunc)
1182
1183             # cond
1184             for child in qual.ifs:
1185                 self.visit(child, lcfunc)
1186
1187             self.for_in_iters.append(qual.list)
1188
1189         # node type
1190         if node in self.gx.genexp_to_lc.values():  # converted generator expression
1191             self.instance(node, def_class(self.gx, '__iter'), func)
1192         else:
1193             self.instance(node, def_class(self.gx, 'list'), func)
1194
1195         # expr->instance.unit
1196         self.visit(node.expr, lcfunc)
1197         self.add_dynamic_constraint(node, node.expr, 'unit', lcfunc)
1198
1199         lcfunc.ident = 'list_comp_' + str(len(self.listcomps))
1200         self.listcomps.append((node, lcfunc, func))
1201
1202     def visitReturn(self, node, func):
1203         self.visit(node.value, func)
1204         func.returnexpr.append(node.value)
1205         if not (isinstance(node.value, Const) and node.value.value is None):
1206             newnode = CNode(self.gx, node, parent=func, mv=getmv())
1207             self.gx.types[newnode] = set()
1208             if isinstance(node.value, Name):
1209                 func.retvars.append(node.value.name)
1210         if func.retnode:
1211             self.add_constraint((inode(self.gx, node.value), func.retnode), func)
1212
1213     def visitAssign(self, node, func=None):
1214         # --- rewrite for struct.unpack XXX rewrite callfunc as tuple
1215         if len(node.nodes) == 1:
1216             lvalue, rvalue = node.nodes[0], node.expr
1217             if self.struct_unpack(rvalue, func) and isinstance(lvalue, (AssList, AssTuple)) and not [n for n in lvalue.nodes if isinstance(n, (AssList, AssTuple))]:
1218                 if not isinstance(rvalue.args[0], (Const, Name)):
1219                     error('non-constant format string', self.gx, node, mv=getmv())
1220                 self.visit(node.expr, func)
1221                 sinfo = self.struct_info(rvalue.args[0], func)
1222                 faketuple = self.struct_faketuple(sinfo)
1223                 self.visit(Assign(node.nodes, faketuple), func)
1224                 tvar = self.temp_var2(rvalue.args[1], inode(self.gx, rvalue.args[1]), func)
1225                 tvar_pos = self.temp_var_int(rvalue.args[0], func)
1226                 self.gx.struct_unpack[node] = (sinfo, tvar.name, tvar_pos.name)
1227                 return
1228
1229         newnode = CNode(self.gx, node, parent=func, mv=getmv())
1230         self.gx.types[newnode] = set()
1231
1232         # --- a,b,.. = c,(d,e),.. = .. = expr
1233         for target_expr in node.nodes:
1234             pairs = assign_rec(target_expr, node.expr)
1235             for (lvalue, rvalue) in pairs:
1236                 # expr[expr] = expr
1237                 if isinstance(lvalue, Subscript) and not isinstance(lvalue.subs[0], Sliceobj):
1238                     self.assign_pair(lvalue, rvalue, func)  # XXX use here generally, and in tuple_flow
1239
1240                 # expr.attr = expr
1241                 elif isinstance(lvalue, AssAttr):
1242                     self.assign_pair(lvalue, rvalue, func)
1243
1244                 # name = expr
1245                 elif isinstance(lvalue, AssName):
1246                     if (rvalue, 0, 0) not in self.gx.cnode:  # XXX generalize
1247                         self.visit(rvalue, func)
1248                     self.visit(lvalue, func)
1249                     lvar = self.default_var(lvalue.name, func)
1250                     if isinstance(rvalue, Const):
1251                         lvar.const_assign.append(rvalue)
1252                     self.add_constraint((inode(self.gx, rvalue), inode(self.gx, lvar)), func)
1253
1254                 # (a,(b,c), ..) = expr
1255                 elif isinstance(lvalue, (AssTuple, AssList)):
1256                     self.visit(rvalue, func)
1257                     self.tuple_flow(lvalue, rvalue, func)
1258
1259                 # expr[a:b] = expr # XXX bla()[1:3] = [1]
1260                 elif isinstance(lvalue, Slice):
1261                     self.slice(lvalue, lvalue.expr, [lvalue.lower, lvalue.upper, None], func, rvalue)
1262
1263                 # expr[a:b:c] = expr
1264                 elif isinstance(lvalue, Subscript) and isinstance(lvalue.subs[0], Sliceobj):
1265                     self.slice(lvalue, lvalue.expr, lvalue.subs[0].nodes, func, rvalue)
1266
1267         # temp vars
1268         if len(node.nodes) > 1 or isinstance(node.expr, Tuple):
1269             if isinstance(node.expr, Tuple):
1270                 if [n for n in node.nodes if isinstance(n, AssTuple)]:
1271                     for child in node.expr.nodes:
1272                         if (child, 0, 0) not in self.gx.cnode:  # (a,b) = (1,2): (1,2) never visited
1273                             continue
1274                         if not isinstance(child, Const) and not (isinstance(child, Name) and child.name == 'None'):
1275                             self.temp_var2(child, inode(self.gx, child), func)
1276             elif not isinstance(node.expr, Const) and not (isinstance(node.expr, Name) and node.expr.name == 'None'):
1277                 self.temp_var2(node.expr, inode(self.gx, node.expr), func)
1278
1279     def assign_pair(self, lvalue, rvalue, func):
1280         # expr[expr] = expr
1281         if isinstance(lvalue, Subscript) and not isinstance(lvalue.subs[0], Sliceobj):
1282             if len(lvalue.subs) > 1:
1283                 subscript = Tuple(lvalue.subs)
1284             else:
1285                 subscript = lvalue.subs[0]
1286
1287             fakefunc = CallFunc(Getattr(lvalue.expr, '__setitem__'), [subscript, rvalue])
1288             self.visit(fakefunc, func)
1289             inode(self.gx, lvalue.expr).fakefunc = fakefunc
1290             if len(lvalue.subs) > 1:
1291                 inode(self.gx, lvalue.expr).faketuple = subscript
1292
1293             if not isinstance(lvalue.expr, Name):
1294                 self.temp_var2(lvalue.expr, inode(self.gx, lvalue.expr), func)
1295
1296         # expr.attr = expr
1297         elif isinstance(lvalue, AssAttr):
1298             CNode(self.gx, lvalue, parent=func, mv=getmv())
1299             self.gx.assign_target[rvalue] = lvalue.expr
1300             fakefunc = CallFunc(Getattr(lvalue.expr, '__setattr__'), [Const(lvalue.attrname), rvalue])
1301             self.visit(fakefunc, func)
1302
1303     def default_var(self, name, func):
1304         if isinstance(func, Function) and name in func.globals:
1305             return default_var(self.gx, name, None, mv=getmv())
1306         else:
1307             return default_var(self.gx, name, func, mv=getmv())
1308
1309     def tuple_flow(self, lvalue, rvalue, func=None):
1310         self.temp_var2(lvalue, inode(self.gx, rvalue), func)
1311
1312         if isinstance(lvalue, (AssTuple, AssList)):
1313             lvalue = lvalue.nodes
1314         for (i, item) in enumerate(lvalue):
1315             fakenode = CNode(self.gx, (item,), parent=func, mv=getmv())  # fake node per item, for multiple callfunc triggers
1316             self.gx.types[fakenode] = set()
1317             self.add_constraint((inode(self.gx, rvalue), fakenode), func)
1318
1319             fakefunc = CallFunc(FakeGetattr3(rvalue, '__getitem__'), [Const(i)])
1320
1321             fakenode.callfuncs.append(fakefunc)
1322             self.visit(fakefunc, func)
1323
1324             self.gx.item_rvalue[item] = rvalue
1325             if isinstance(item, AssName):
1326                 lvar = self.default_var(item.name, func)
1327                 self.add_constraint((inode(self.gx, fakefunc), inode(self.gx, lvar)), func)
1328             elif isinstance(item, (Subscript, AssAttr)):
1329                 self.assign_pair(item, fakefunc, func)
1330             elif isinstance(item, (AssTuple, AssList)):  # recursion
1331                 self.tuple_flow(item, fakefunc, func)
1332             else:
1333                 error('unsupported type of assignment', self.gx, item, mv=getmv())
1334
1335     def super_call(self, orig, parent):
1336         node = orig.node
1337         while isinstance(parent, Function):
1338             parent = parent.parent
1339         if (isinstance(node.expr, CallFunc) and
1340             node.attrname not in ('__getattr__', '__setattr__') and
1341             isinstance(node.expr.node, Name) and
1342                 node.expr.node.name == 'super'):
1343             if (len(node.expr.args) >= 2 and
1344                     isinstance(node.expr.args[1], Name) and node.expr.args[1].name == 'self'):
1345                 cl = lookup_class(node.expr.args[0], getmv())
1346                 if cl.node.bases:
1347                     return cl.node.bases[0]
1348             error("unsupported usage of 'super'", self.gx, orig, mv=getmv())
1349
1350     def visitCallFunc(self, node, func=None):  # XXX clean up!!
1351         newnode = CNode(self.gx, node, parent=func, mv=getmv())
1352
1353         if isinstance(node.node, Getattr):  # XXX import math; math.e
1354             # rewrite super(..) call
1355             base = self.super_call(node, func)
1356             if base:
1357                 node.node = Getattr(copy.deepcopy(base), node.node.attrname)
1358                 node.args = [Name('self')] + node.args
1359
1360             # method call
1361             if isinstance(node.node, FakeGetattr):  # XXX butt ugly
1362                 self.visit(node.node, func)
1363             elif isinstance(node.node, FakeGetattr2):
1364                 self.gx.types[newnode] = set()  # XXX move above
1365
1366                 self.callfuncs.append((node, func))
1367
1368                 for arg in node.args:
1369                     inode(self.gx, arg).callfuncs.append(node)  # this one too
1370
1371                 return
1372             elif isinstance(node.node, FakeGetattr3):
1373                 pass
1374             else:
1375                 self.visitGetattr(node.node, func, callfunc=True)
1376                 inode(self.gx, node.node).callfuncs.append(node)  # XXX iterative dataflow analysis: move there?
1377                 inode(self.gx, node.node).fakert = True
1378
1379             ident = node.node.attrname
1380             inode(self.gx, node.node.expr).callfuncs.append(node)  # XXX iterative dataflow analysis: move there?
1381
1382             if isinstance(node.node.expr, Name) and node.node.expr.name in getmv().imports and node.node.attrname == '__getattr__':  # XXX analyze_callfunc
1383                 if node.args[0].value in getmv().imports[node.node.expr.name].mv.globals:  # XXX bleh
1384                     self.add_constraint((inode(self.gx, getmv().imports[node.node.expr.name].mv.globals[node.args[0].value]), newnode), func)
1385
1386         elif isinstance(node.node, Name):
1387             # direct call
1388             ident = node.node.name
1389             if ident == 'print':
1390                 ident = node.node.name = '__print'  # XXX
1391
1392             if ident in ['getattr', 'setattr', 'slice', 'type']:
1393                 error("'%s' function is not supported" % ident, self.gx, node.node, mv=getmv())
1394             if ident == 'dict' and [x for x in node.args if isinstance(x, Keyword)]:
1395                 error('unsupported method of initializing dictionaries', self.gx, node, mv=getmv())
1396             if ident == 'isinstance':
1397                 error("'isinstance' is not supported; always returns True", self.gx, node, mv=getmv(), warning=True)
1398
1399             if lookup_var(ident, func, mv=getmv()):
1400                 self.visit(node.node, func)
1401                 inode(self.gx, node.node).callfuncs.append(node)  # XXX iterative dataflow analysis: move there
1402         else:
1403             self.visit(node.node, func)
1404             inode(self.gx, node.node).callfuncs.append(node)  # XXX iterative dataflow analysis: move there
1405
1406         # --- arguments
1407         if not getmv().module.builtin and (node.star_args or node.dstar_args):
1408             error('argument (un)packing is not supported', self.gx, node, mv=getmv())
1409         args = node.args[:]
1410         if node.star_args:
1411             args.append(node.star_args)  # partially allowed in builtins
1412         if node.dstar_args:
1413             args.append(node.dstar_args)
1414         for arg in args:
1415             if isinstance(arg, Keyword):
1416                 arg = arg.expr
1417             self.visit(arg, func)
1418             inode(self.gx, arg).callfuncs.append(node)  # this one too
1419
1420         # --- handle instantiation or call
1421         constructor = lookup_class(node.node, getmv())
1422         if constructor and (not isinstance(node.node, Name) or not lookup_var(node.node.name, func, mv=getmv())):
1423             self.instance(node, constructor, func)
1424             inode(self.gx, node).callfuncs.append(node)  # XXX see above, investigate
1425         else:
1426             self.gx.types[newnode] = set()
1427
1428         self.callfuncs.append((node, func))
1429
1430     def visitClass(self, node, parent=None):
1431         if not getmv().module.builtin and not node in getmv().classnodes:
1432             error("non-global class '%s'" % node.name, self.gx, node, mv=getmv())
1433         if len(node.bases) > 1:
1434             error('multiple inheritance is not supported', self.gx, node, mv=getmv())
1435
1436         if not getmv().module.builtin:
1437             for base in node.bases:
1438                 if not isinstance(base, (Name, Getattr)):
1439                     error("invalid expression for base class", self.gx, node, mv=getmv())
1440
1441                 if isinstance(base, Name):
1442                     name = base.name
1443                 else:
1444                     name = base.attrname
1445
1446                 cl = lookup_class(base, getmv())
1447                 if not cl:
1448                     error("no such class: '%s'" % name, self.gx, node, mv=getmv())
1449
1450                 elif cl.mv.module.builtin and name not in ['object', 'Exception', 'tzinfo']:
1451                     if def_class(self.gx, 'Exception') not in cl.ancestors():
1452                         error("inheritance from builtin class '%s' is not supported" % name, self.gx, node, mv=getmv())
1453
1454         if node.name in getmv().classes:
1455             newclass = getmv().classes[node.name]  # set in visitModule, for forward references
1456         else:
1457             check_redef(self.gx, node)  # XXX merge with visitModule
1458             newclass = Class(self.gx, node, getmv())
1459             self.classes[node.name] = newclass
1460             getmv().classes[node.name] = newclass
1461             newclass.module = self.module
1462             newclass.parent = StaticClass(newclass, getmv())
1463
1464         # --- built-in functions
1465         for cl in [newclass, newclass.parent]:
1466             for ident in ['__setattr__', '__getattr__']:
1467                 func = Function(self.gx, mv=getmv())
1468                 func.ident = ident
1469                 func.parent = cl
1470
1471                 if ident == '__setattr__':
1472                     func.formals = ['name', 'whatsit']
1473                     retexpr = Return(Name('None'))
1474                     self.visit(retexpr, func)
1475                 elif ident == '__getattr__':
1476                     func.formals = ['name']
1477
1478                 cl.funcs[ident] = func
1479
1480         # --- built-in attributes
1481         if 'class_' in getmv().classes or 'class_' in getmv().ext_classes:
1482             var = default_var(self.gx, '__class__', newclass)
1483             var.invisible = True
1484             self.gx.types[inode(self.gx, var)] = set([(def_class(self.gx, 'class_'), def_class(self.gx, 'class_').dcpa)])
1485             def_class(self.gx, 'class_').dcpa += 1
1486
1487         # --- staticmethod, property
1488         skip = []
1489         for child in node.code.getChildNodes():
1490             if isinstance(child, Assign) and len(child.nodes) == 1:
1491                 lvalue, rvalue = child.nodes[0], child.expr
1492                 if isinstance(lvalue, AssName) and isinstance(rvalue, CallFunc) and isinstance(rvalue.node, Name) and rvalue.node.name in ['staticmethod', 'property']:
1493                     if rvalue.node.name == 'property':
1494                         if len(rvalue.args) == 1 and isinstance(rvalue.args[0], Name):
1495                             newclass.properties[lvalue.name] = rvalue.args[0].name, None
1496                         elif len(rvalue.args) == 2 and isinstance(rvalue.args[0], Name) and isinstance(rvalue.args[1], Name):
1497                             newclass.properties[lvalue.name] = rvalue.args[0].name, rvalue.args[1].name
1498                         else:
1499                             error("complex properties are not supported", self.gx, rvalue, mv=getmv())
1500                     else:
1501                         newclass.staticmethods.append(lvalue.name)
1502                     skip.append(child)
1503
1504         # --- children
1505         for child in node.code.getChildNodes():
1506             if child not in skip:
1507                 cl = self.classes[node.name]
1508                 if isinstance(child, FunctionNode):
1509                     self.visit(child, cl)
1510                 else:
1511                     cl.parent.static_nodes.append(child)
1512                     self.visit(child, cl.parent)
1513
1514         # --- __iadd__ etc.
1515         if not newclass.mv.module.builtin or newclass.ident in ['int_', 'float_', 'str_', 'tuple', 'complex']:
1516             msgs = ['add', 'mul']  # XXX mod, pow
1517             if newclass.ident in ['int_', 'float_']:
1518                 msgs += ['sub', 'div', 'floordiv']
1519             if newclass.ident in ['int_']:
1520                 msgs += ['lshift', 'rshift', 'and', 'xor', 'or']
1521             for msg in msgs:
1522                 if not '__i' + msg + '__' in newclass.funcs:
1523                     self.visit(FunctionNode(None, '__i' + msg + '__', ['self', 'other'], [], 0, None, Stmt([Return(CallFunc(Getattr(Name('self'), '__' + msg + '__'), [Name('other')], None, None))])), newclass)
1524
1525         # --- __str__, __hash__ # XXX model in lib/builtin.py, other defaults?
1526         if not newclass.mv.module.builtin and not '__str__' in newclass.funcs:
1527             self.visit(FunctionNode(None, '__str__', ['self'], [], 0, None, Return(CallFunc(Getattr(Name('self'), '__repr__'), []))), newclass)
1528             newclass.funcs['__str__'].invisible = True
1529         if not newclass.mv.module.builtin and not '__hash__' in newclass.funcs:
1530             self.visit(FunctionNode(None, '__hash__', ['self'], [], 0, None, Return(Const(0)), []), newclass)
1531             newclass.funcs['__hash__'].invisible = True
1532
1533     def visitGetattr(self, node, func=None, callfunc=False):
1534         if node.attrname in ['__doc__']:
1535             error('%s attribute is not supported' % node.attrname, self.gx, node, mv=getmv())
1536
1537         newnode = CNode(self.gx, node, parent=func, mv=getmv())
1538         self.gx.types[newnode] = set()
1539
1540         fakefunc = CallFunc(FakeGetattr(node.expr, '__getattr__'), [Const(node.attrname)])
1541         self.visit(fakefunc, func)
1542         self.add_constraint((self.gx.cnode[fakefunc, 0, 0], newnode), func)
1543
1544         self.callfuncs.append((fakefunc, func))
1545
1546         if not callfunc:
1547             self.fncl_passing(node, newnode, func)
1548
1549     def visitConst(self, node, func=None):
1550         if type(node.value) == unicode:
1551             error('unicode is not supported', self.gx, node, mv=getmv())
1552         map = {int: 'int_', str: 'str_', float: 'float_', type(None): 'none', long: 'int_', complex: 'complex'}  # XXX 'return' -> Return(Const(None))?
1553         self.instance(node, def_class(self.gx, map[type(node.value)]), func)
1554
1555     def fncl_passing(self, node, newnode, func):
1556         lfunc, lclass = lookup_func(node, getmv()), lookup_class(node, getmv())
1557         if lfunc:
1558             if lfunc.mv.module.builtin:
1559                 lfunc = self.builtin_wrapper(node, func)
1560             elif lfunc.ident not in lfunc.mv.lambdas:
1561                 lfunc.lambdanr = len(lfunc.mv.lambdas)
1562                 lfunc.mv.lambdas[lfunc.ident] = lfunc
1563             self.gx.types[newnode] = set([(lfunc, 0)])
1564         elif lclass:
1565             if lclass.mv.module.builtin:
1566                 lclass = self.builtin_wrapper(node, func)
1567             else:
1568                 lclass = lclass.parent
1569             self.gx.types[newnode] = set([(lclass, 0)])
1570         else:
1571             return False
1572         newnode.copymetoo = True  # XXX merge into some kind of 'seeding' function
1573         return True
1574
1575     def visitName(self, node, func=None):
1576         newnode = CNode(self.gx, node, parent=func, mv=getmv())
1577         self.gx.types[newnode] = set()
1578
1579         if node.name == '__doc__':
1580             error("'%s' attribute is not supported" % node.name, self.gx, node, mv=getmv())
1581
1582         if node.name in ['None', 'True', 'False']:
1583             if node.name == 'None':  # XXX also bools, remove def seed_nodes()
1584                 self.instance(node, def_class(self.gx, 'none'), func)
1585             else:
1586                 self.instance(node, def_class(self.gx, 'bool_'), func)
1587             return
1588
1589         if isinstance(func, Function) and node.name in func.globals:
1590             var = default_var(self.gx, node.name, None, mv=getmv())
1591         else:
1592             var = lookup_var(node.name, func, mv=getmv())
1593             if not var:
1594                 if self.fncl_passing(node, newnode, func):
1595                     pass
1596                 elif node.name in ['int', 'float', 'str']:  # XXX
1597                     cl = self.ext_classes[node.name + '_']
1598                     self.gx.types[newnode] = set([(cl.parent, 0)])
1599                     newnode.copymetoo = True
1600                 else:
1601                     var = default_var(self.gx, node.name, None, mv=getmv())
1602         if var:
1603             self.add_constraint((inode(self.gx, var), newnode), func)
1604
1605     def builtin_wrapper(self, node, func):
1606         node2 = CallFunc(copy.deepcopy(node), [Name(x) for x in 'abcde'])
1607         l = Lambda(list('abcde'), [], 0, node2)
1608         self.visit(l, func)
1609         self.lwrapper[node] = self.lambdaname[l]
1610         self.gx.lambdawrapper[node2] = self.lambdaname[l]
1611         f = self.lambdas[self.lambdaname[l]]
1612         f.lambdawrapper = True
1613         inode(self.gx, node2).lambdawrapper = f
1614         return f
1615
1616
1617 def parse_module(name, gx, parent=None, node=None):
1618     # --- valid name?
1619     if not re.match("^[a-zA-Z0-9_.]+$", name):
1620         print ("*ERROR*:%s.py: module names should consist of letters, digits and underscores" % name)
1621         sys.exit(1)
1622
1623     # --- create module
1624     try:
1625         if parent and parent.path != os.getcwd():
1626             basepaths = [parent.path, os.getcwd()]
1627         else:
1628             basepaths = [os.getcwd()]
1629         module_paths = basepaths + gx.libdirs
1630         absolute_name, filename, relative_filename, builtin = find_module(gx, name, module_paths)
1631         module = Module(absolute_name, filename, relative_filename, builtin, node)
1632     except ImportError:
1633         error('cannot locate module: ' + name, gx, node, mv=getmv())
1634
1635     # --- check cache
1636     if module.name in gx.modules:  # cached?
1637         return gx.modules[module.name]
1638     gx.modules[module.name] = module
1639
1640     # --- not cached, so parse
1641     module.ast = parse_file(module.filename)
1642
1643     old_mv = getmv()
1644     module.mv = mv = ModuleVisitor(module, gx)
1645     setmv(mv)
1646
1647     mv.visit = mv.dispatch
1648     mv.visitor = mv
1649     mv.dispatch(module.ast)
1650     module.import_order = gx.import_order
1651     gx.import_order += 1
1652
1653     mv = old_mv
1654     setmv(mv)
1655
1656     return module