Ejemplo n.º 1
0
def supported_funcs(gv, funcs):
    supported = []
    for func in funcs:
        if func.isGenerator or not cpp.hmcpa(func):
            continue
        if func.ident in ['__setattr__', '__getattr__', '__iadd__', '__isub__', '__imul__']: # XXX
            continue
        if isinstance(func.parent, class_):
            if func.invisible or func.inherited or not gv.inhcpa(func):
                continue
        if isinstance(func.parent, class_) and func.ident in func.parent.staticmethods:
            print '*WARNING* method not exported:', func.parent.ident+'.'+func.ident
            continue
        builtins = True
        for formal in func.formals:
            try:
                cpp.nodetypestr(func.vars[formal], func, check_extmod=True)
                cpp.nodetypestr(func.retnode.thing, func, check_extmod=True, check_ret=True)
            except cpp.ExtmodError:
                builtins = False
        if builtins:
            supported.append(func)
        else:
            if isinstance(func.parent, class_):
                print '*WARNING* method not exported:', func.parent.ident+'.'+func.ident
            else:
                print '*WARNING* function not exported:', func.ident
    return supported
Ejemplo n.º 2
0
def do_extmod_method(gv, func):
    is_method = isinstance(func.parent, class_)
    if is_method: formals = func.formals[1:]
    else: formals = func.formals

    if isinstance(func.parent, class_): id = clname(func.parent)+'_'+func.ident
    else: id = 'Global_'+'_'.join(gv.module.mod_path)+'_'+func.ident
    print >>gv.out, 'PyObject *%s(PyObject *self, PyObject *args, PyObject *kwargs) {' % id
    print >>gv.out, '    try {'

    for i, formal in enumerate(formals):
        gv.start('')
        typ = cpp.nodetypestr(func.vars[formal], func)
        if func.ident in OVERLOAD:
            print >>gv.out, '        %(type)sarg_%(num)d = __to_ss<%(type)s>(args);' % {'type' : typ, 'num' : i}
            continue
        gv.append('        %(type)sarg_%(num)d = __ss_arg<%(type)s>("%(name)s", %(num)d, ' % {'type' : typ, 'num' : i, 'name': formal})
        if i >= len(formals)-len(func.defaults):
            gv.append('1, ')
            defau = func.defaults[i-(len(formals)-len(func.defaults))]
            cast = cpp.assign_needs_cast(defau, None, func.vars[formal], func)
            if cast:
                gv.append('(('+cpp.nodetypestr(func.vars[formal], func)+')')

            if defau in func.mv.defaults:
                if gv.mergeinh[defau] == set([(defclass('none'),0)]):
                    gv.append('0')
                else:
                    gv.append('%s::default_%d' % ('__'+func.mv.module.ident+'__', func.mv.defaults[defau]))
            else:
                gv.visit(defau, func)
            if cast:
                gv.append(')')
        elif typ.strip() == '__ss_bool':
            gv.append('0, False')
        else:
            gv.append('0, 0')
        gv.append(', args, kwargs)')
        gv.eol()
    print >>gv.out

    # call
    if is_method: where = '((%sObject *)self)->__ss_object->' % clname(func.parent)
    else: where = '__'+gv.module.ident+'__::'
    print >>gv.out, '        return __to_py('+where+gv.cpp_name(func.ident)+'('+', '.join(['arg_%d' % i for i in range(len(formals))])+'));\n'

    # convert exceptions
    print >>gv.out, '    } catch (Exception *e) {'
    print >>gv.out, '        PyErr_SetString(__to_py(e), ((e->msg)?(e->msg->unit.c_str()):""));'
    print >>gv.out, '        return 0;'
    print >>gv.out, '    }'
    print >>gv.out, '}\n'
Ejemplo n.º 3
0
def supported_vars(vars): # XXX virtuals?
    supported = []
    for var in vars:
        if not var in getgx().merged_inh or not getgx().merged_inh[var]:
            continue
        if var.name.startswith('__'): # XXX
            continue
        if var.invisible or cpp.singletype2(getgx().merged_inh[var], module):
            continue
        try:
            typehu = cpp.nodetypestr(var, var.parent, check_extmod=True)
        except cpp.ExtmodError:
            if isinstance(var.parent, class_):
                print '*WARNING* variable not exported:', var.parent.ident+'.'+var.name
            else:
                print '*WARNING* variable not exported:', var.name
            continue
        supported.append(var)
    return supported
Ejemplo n.º 4
0
def do_reduce_setstate(gv, cl, vars):
    if defclass('Exception') in cl.ancestors(): # XXX
        return
    print >>gv.out, 'PyObject *%s__reduce__(PyObject *self, PyObject *args, PyObject *kwargs) {' % clname(cl)
    print >>gv.out, '    PyObject *t = PyTuple_New(3);'
    print >>gv.out, '    PyTuple_SetItem(t, 0, PyObject_GetAttrString(__ss_mod_%s, "__newobj__"));' % '_'.join(gv.module.mod_path)
    print >>gv.out, '    PyObject *a = PyTuple_New(1);'
    print >>gv.out, '    PyTuple_SetItem(a, 0, (PyObject *)&%sObjectType);' % clname(cl)
    print >>gv.out, '    PyTuple_SetItem(t, 1, a);'
    print >>gv.out, '    PyObject *b = PyTuple_New(2);'
    for i, var in enumerate(vars):
        print >>gv.out, '    PyTuple_SetItem(b, %d, __to_py(((%sObject *)self)->__ss_object->%s));' % (i, clname(cl), var.cpp_name())
    print >>gv.out, '    PyTuple_SetItem(t, 2, b);'
    print >>gv.out, '    return t;'
    print >>gv.out, '}\n'
    print >>gv.out, 'PyObject *%s__setstate__(PyObject *self, PyObject *args, PyObject *kwargs) {' % clname(cl)
    print >>gv.out, '    int l = PyTuple_Size(args);'
    print >>gv.out, '    PyObject *state = PyTuple_GetItem(args, 0);'
    for i, var in enumerate(vars):
        vartype = cpp.nodetypestr(var, var.parent)
        print >>gv.out, '    ((%sObject *)self)->__ss_object->%s = __to_ss<%s>(PyTuple_GetItem(state, %d));' % (clname(cl), var.cpp_name(), vartype, i)
    print >>gv.out, '    return Py_None;'
    print >>gv.out, '}\n'
Ejemplo n.º 5
0
def annotate():
    if not getgx().annotation:
        return
    re_comment = re.compile(r'#[^\"\']*$')
    def paste(expr, text):
        if not expr.lineno: return
        if (expr,0,0) in getgx().cnode and inode(expr).mv != mv: return # XXX
        line = source[expr.lineno-1][:-1]
        match = re_comment.search(line)
        if match:
            line = line[:match.start()]
        if text:
            text = '# '+text
        line = string.rstrip(line)
        if text and len(line) < 40: line += (40-len(line))*' '
        source[expr.lineno-1] = line
        if text: source[expr.lineno-1] += ' ' + text
        source[expr.lineno-1] += '\n'

    for module in getgx().modules.values():
        if module.builtin:
            continue

        mv = module.mv
        setmv(mv)

        # merge type information for nodes in module XXX inheritance across modules?
        merge = merged([n for n in getgx().types if n.mv == mv], inheritance=True)

        source = open(module.filename).readlines()

        # --- constants/names/attributes
        for expr in merge:
            if isinstance(expr, (Const, Name)):
                paste(expr, nodetypestr(expr, inode(expr).parent, False))
        for expr in merge:
            if isinstance(expr, Getattr):
                paste(expr, nodetypestr(expr, inode(expr).parent, False))
        for expr in merge:
            if isinstance(expr, (Tuple,List,Dict)):
                paste(expr, nodetypestr(expr, inode(expr).parent, False))

        # --- instance variables
        funcs = getmv().funcs.values()
        for cl in getmv().classes.values():
            labels = [var.name+': '+nodetypestr(var, cl, False) for var in cl.vars.values() if var in merge and merge[var] and not var.name.startswith('__')]
            if labels: paste(cl.node, ', '.join(labels))
            funcs += cl.funcs.values()

        # --- function variables
        for func in funcs:
            if not func.node or func.node in getgx().inherited: continue
            vars = [func.vars[f] for f in func.formals]
            labels = [var.name+': '+nodetypestr(var, func, False) for var in vars if not var.name.startswith('__')]
            paste(func.node, ', '.join(labels))

        # --- callfuncs
        for callfunc, _ in getmv().callfuncs:
            if isinstance(callfunc.node, Getattr):
                if not isinstance(callfunc.node, (fakeGetattr, fakeGetattr2, fakeGetattr3)):
                    paste(callfunc.node.expr, nodetypestr(callfunc, inode(callfunc).parent, False))
            else:
                paste(callfunc.node, nodetypestr(callfunc, inode(callfunc).parent, False))

        # --- higher-level crap (listcomps, returns, assignments, prints)
        for expr in merge:
            if isinstance(expr, ListComp):
                paste(expr, nodetypestr(expr, inode(expr).parent, False))
            elif isinstance(expr, Return):
                paste(expr, nodetypestr(expr.value, inode(expr).parent, False))
            elif isinstance(expr, (AssTuple, AssList)):
                paste(expr, nodetypestr(expr, inode(expr).parent, False))
            elif isinstance(expr, (Print,Printnl)):
                paste(expr, ', '.join([nodetypestr(child, inode(child).parent, False) for child in expr.nodes]))

        # --- assignments
        for expr in merge:
            if isinstance(expr, Assign):
                pairs = assign_rec(expr.nodes[0], expr.expr)
                paste(expr, ', '.join([nodetypestr(r, inode(r).parent, False) for (l,r) in pairs]))
            elif isinstance(expr, AugAssign):
                paste(expr, nodetypestr(expr.expr, inode(expr).parent, False))

        # --- output annotated file (skip if no write permission)
        try:
            out = open(os.path.join(getgx().output_dir, module.filename[:-3]+'.ss.py'),'w')
            out.write(''.join(source))
            out.close()
        except IOError:
            pass
Ejemplo n.º 6
0
def annotate():
    if not getgx().annotation:
        return
    re_comment = re.compile(r'#[^\"\']*$')

    def paste(expr, text):
        if not expr.lineno: return
        if (expr, 0, 0) in getgx().cnode and inode(expr).mv != mv:
            return  # XXX
        line = source[expr.lineno - 1]
        match = re_comment.search(line)
        if match:
            line = line[:match.start()]
        if text:
            text = '# ' + text
        line = line.rstrip()
        if text and len(line) < 40: line += (40 - len(line)) * ' '
        source[expr.lineno - 1] = line
        if text: source[expr.lineno - 1] += ' ' + text
        source[expr.lineno - 1] += '\n'

    for module in getgx().modules.values():
        if module.builtin:
            continue

        mv = module.mv
        setmv(mv)

        # merge type information for nodes in module XXX inheritance across modules?
        merge = merged([n for n in getgx().types if n.mv == mv],
                       inheritance=True)

        source = open(module.filename).readlines()

        # --- constants/names/attributes
        for expr in merge:
            if isinstance(expr, (Const, Name)):
                paste(expr, nodetypestr(expr, inode(expr).parent, False))
        for expr in merge:
            if isinstance(expr, Getattr):
                paste(expr, nodetypestr(expr, inode(expr).parent, False))
        for expr in merge:
            if isinstance(expr, (Tuple, List, Dict)):
                paste(expr, nodetypestr(expr, inode(expr).parent, False))

        # --- instance variables
        funcs = getmv().funcs.values()
        for cl in getmv().classes.values():
            labels = [
                var.name + ': ' + nodetypestr(var, cl, False)
                for var in cl.vars.values() if var in merge and merge[var]
                and not var.name.startswith('__')
            ]
            if labels: paste(cl.node, ', '.join(labels))
            funcs += cl.funcs.values()

        # --- function variables
        for func in funcs:
            if not func.node or func.node in getgx().inherited: continue
            vars = [func.vars[f] for f in func.formals]
            labels = [
                var.name + ': ' + nodetypestr(var, func, False) for var in vars
                if not var.name.startswith('__')
            ]
            paste(func.node, ', '.join(labels))

        # --- callfuncs
        for callfunc, _ in getmv().callfuncs:
            if isinstance(callfunc.node, Getattr):
                if not isinstance(callfunc.node,
                                  (fakeGetattr, fakeGetattr2, fakeGetattr3)):
                    paste(callfunc.node.expr,
                          nodetypestr(callfunc,
                                      inode(callfunc).parent, False))
            else:
                paste(callfunc.node,
                      nodetypestr(callfunc,
                                  inode(callfunc).parent, False))

        # --- higher-level crap (listcomps, returns, assignments, prints)
        for expr in merge:
            if isinstance(expr, ListComp):
                paste(expr, nodetypestr(expr, inode(expr).parent, False))
            elif isinstance(expr, Return):
                paste(expr, nodetypestr(expr.value, inode(expr).parent, False))
            elif isinstance(expr, (AssTuple, AssList)):
                paste(expr, nodetypestr(expr, inode(expr).parent, False))
            elif isinstance(expr, (Print, Printnl)):
                paste(
                    expr, ', '.join([
                        nodetypestr(child,
                                    inode(child).parent, False)
                        for child in expr.nodes
                    ]))

        # --- assignments
        for expr in merge:
            if isinstance(expr, Assign):
                pairs = assign_rec(expr.nodes[0], expr.expr)
                paste(
                    expr, ', '.join([
                        nodetypestr(r,
                                    inode(r).parent, False) for (l, r) in pairs
                    ]))
            elif isinstance(expr, AugAssign):
                paste(expr, nodetypestr(expr.expr, inode(expr).parent, False))

        # --- output annotated file (skip if no write permission)
        try:
            out = open(module.filename[:-3] + '.ss.py', 'w')
            out.write(''.join(source))
            out.close()
        except IOError:
            pass
Ejemplo n.º 7
0
def analyze(source, testing=False):
    try:
        gc.set_threshold(23456, 10, 10)
    except AttributeError: # not all Python implementations support this
        pass

    if testing:
        setgx(newgx())
        ast = parse(source+'\n')
    else:
        ast = graph.parsefile(source)

    mv = None
    setmv(mv)

    # --- build dataflow graph from source code
    getgx().main_module = graph.parse_module(getgx().main_mod, ast)
    getgx().main_module.filename = getgx().main_mod+'.py'
    getgx().modules[getgx().main_mod] = getgx().main_module
    mv = getgx().main_module.mv
    setmv(mv)

    # --- seed class_.__name__ attributes..
    for cl in getgx().allclasses:
        if cl.ident == 'class_':
            var = defaultvar('__name__', cl)
            getgx().types[inode(var)] = set([(defclass('str_'), 0)])

    # --- number classes (-> constant-time subclass check)
    cpp.number_classes()

    # --- non-ifa: copy classes for each allocation site
    for cl in getgx().allclasses:
        if cl.ident in ['int_','float_','none', 'class_','str_', 'bool_']:
            continue
        if cl.ident == 'list':
            cl.dcpa = len(getgx().list_types)+2
        elif cl.ident != '__iter': # XXX huh
            cl.dcpa = 2

        for dcpa in range(1, cl.dcpa):
            class_copy(cl, dcpa)

    var = defaultvar('unit', defclass('str_'))
    getgx().types[inode(var)] = set([(defclass('str_'), 0)])

    # --- cartesian product algorithm & iterative flow analysis
    iterative_dataflow_analysis()

    print '[generating c++ code..]' # XXX 

    for cl in getgx().allclasses:
        for name in cl.vars:
            if name in cl.parent.vars and not name.startswith('__'):
                error("instance variable '%s' of class '%s' shadows class variable" % (name, cl.ident), fatal = False)

    getgx().merged_all = merged(getgx().types) #, inheritance=True)
    getgx().merge_dcpa = merged(getgx().types, dcpa=True)

    mv = getgx().main_module.mv
    setmv(mv)
    propagate() # XXX remove

    getgx().merged_all = merged(getgx().types) #, inheritance=True)
    getgx().merged_inh = merged(getgx().types, inheritance=True)

    # --- detect inheritance stuff
    cpp.upgrade_variables()
    getgx().merged_all = merged(getgx().types)
    getgx().merged_inh = merged(getgx().types, inheritance=True)
    cpp.analyze_virtuals()
    getgx().merge_dcpa = merged(getgx().types, dcpa=True)
    getgx().merged_all = merged(getgx().types) #, inheritance=True) # XXX

    # --- determine which classes need an __init__ method
    for node, types in getgx().merged_all.items():
        if isinstance(node, CallFunc):
            objexpr, ident, _ , method_call, _, _, _ = analyze_callfunc(node)
            if method_call and ident == '__init__':
                for t in getgx().merged_all[objexpr]:
                    t[0].has_init = True

    # --- determine which classes need copy, deepcopy methods
    if 'copy' in getgx().modules:
        func = getgx().modules['copy'].mv.funcs['copy']
        var = func.vars[func.formals[0]]
        for cl in set([t[0] for t in getgx().merged_inh[var]]):
            cl.has_copy = True # XXX transitive, modeling

        func = getgx().modules['copy'].mv.funcs['deepcopy']
        var = func.vars[func.formals[0]]
        for cl in set([t[0] for t in getgx().merged_inh[var]]):
            cl.has_deepcopy = True # XXX transitive, modeling

    # --- add inheritance relationships for non-original Nodes (and tempvars?); XXX register more, right solution?
    for func in getgx().allfuncs:
        #if not func.mv.module.builtin and func.ident == '__init__':
        if func in getgx().inheritance_relations:
            for inhfunc in getgx().inheritance_relations[func]:
                for a, b in zip(func.registered, inhfunc.registered):
                    graph.inherit_rec(a, b, func.mv)

                for a, b in zip(func.registered_tempvars, inhfunc.registered_tempvars): # XXX more general
                    getgx().inheritance_tempvars.setdefault(a, []).append(b)

    getgx().merged_inh = merged(getgx().types, inheritance=True) # XXX why X times

    # error for dynamic expression
    for node in getgx().merged_all:
        if isinstance(node, Node) and not isinstance(node, AssAttr) and not inode(node).mv.module.builtin:
            cpp.nodetypestr(node, inode(node).parent)

    return getgx()
Ejemplo n.º 8
0
def do_extmod_class(gv, cl):
    for n in cl.module.mod_path:
        print >>gv.out, 'namespace __%s__ { /* XXX */' % n
    print >>gv.out

    # determine methods, vars to expose
    funcs = supported_funcs(gv, cl.funcs.values())
    vars = supported_vars(cl.vars.values())

    # python object
    print >>gv.out, '/* class %s */\n' % cl.ident
    print >>gv.out, 'typedef struct {'
    print >>gv.out, '    PyObject_HEAD'
    print >>gv.out, '    %s::%s *__ss_object;' % (cl.module.full_path(), cpp.nokeywords(cl.ident))
    print >>gv.out, '} %sObject;\n' % clname(cl)
    print >>gv.out, 'static PyMemberDef %sMembers[] = {' % clname(cl)
    print >>gv.out, '    {NULL}\n};\n'

    # methods
    for func in funcs:
        do_extmod_method(gv, func)
    do_extmod_methoddef(gv, cl.ident, funcs, cl)

    # tp_init
    if hasmethod(cl, '__init__') and cl.funcs['__init__'] in funcs:
        print >>gv.out, 'int %s___tpinit__(PyObject *self, PyObject *args, PyObject *kwargs) {' % clname(cl)
        print >>gv.out, '    if(!%s___init__(self, args, kwargs))' % clname(cl)
        print >>gv.out, '        return -1;'
        print >>gv.out, '    return 0;'
        print >>gv.out, '}\n'

    # tp_new
    print >>gv.out, 'PyObject *%sNew(PyTypeObject *type, PyObject *args, PyObject *kwargs) {' % clname(cl)
    print >>gv.out, '    %sObject *self = (%sObject *)type->tp_alloc(type, 0);' % (clname(cl), clname(cl))
    print >>gv.out, '    self->__ss_object = new %s::%s();' % (cl.module.full_path(), cpp.nokeywords(cl.ident))
    print >>gv.out, '    self->__ss_object->__class__ = %s::cl_%s;' % (cl.module.full_path(), cl.ident)
    print >>gv.out, '    __ss_proxy->__setitem__(self->__ss_object, self);'
    print >>gv.out, '    return (PyObject *)self;'
    print >>gv.out, '}\n'

    # tp_dealloc
    print >>gv.out, 'void %sDealloc(%sObject *self) {' % (clname(cl), clname(cl))
    print >>gv.out, '    self->ob_type->tp_free((PyObject *)self);'
    print >>gv.out, '    __ss_proxy->__delitem__(self->__ss_object);'
    print >>gv.out, '}\n'

    # getset
    for var in vars:
        print >>gv.out, 'PyObject *__ss_get_%s_%s(%sObject *self, void *closure) {' % (clname(cl), var.name, clname(cl))
        print >>gv.out, '    return __to_py(self->__ss_object->%s);' % var.cpp_name()
        print >>gv.out, '}\n'

        print >>gv.out, 'int __ss_set_%s_%s(%sObject *self, PyObject *value, void *closure) {' % (clname(cl), var.name, clname(cl))
        print >>gv.out, '    try {'
        typ = cpp.nodetypestr(var, var.parent)
        if typ == 'void *': # XXX investigate
            print >>gv.out, '        self->__ss_object->%s = NULL;' % var.cpp_name()
        else:
            print >>gv.out, '        self->__ss_object->%s = __to_ss<%s>(value);' % (var.cpp_name(), typ)
        print >>gv.out, '    } catch (Exception *e) {'
        print >>gv.out, '        PyErr_SetString(__to_py(e), ((e->msg)?(e->msg->unit.c_str()):""));'
        print >>gv.out, '        return -1;'
        print >>gv.out, '    }'

        print >>gv.out, '    return 0;'
        print >>gv.out, '}\n'

    print >>gv.out, 'PyGetSetDef %sGetSet[] = {' % clname(cl)
    for var in vars:
        print >>gv.out, '    {(char *)"%s", (getter)__ss_get_%s_%s, (setter)__ss_set_%s_%s, (char *)"", NULL},' % (var.name, clname(cl), var.name, clname(cl), var.name)
    print >>gv.out, '    {NULL}\n};\n'

    # python type
    print >>gv.out, 'PyTypeObject %sObjectType = {' % clname(cl)
    print >>gv.out, '    PyObject_HEAD_INIT(NULL)'
    print >>gv.out, '    0,              /* ob_size           */'
    print >>gv.out, '    "%s.%s",        /* tp_name           */' % (cl.module.ident, cl.ident)
    print >>gv.out, '    sizeof(%sObject), /* tp_basicsize      */' % clname(cl)
    print >>gv.out, '    0,              /* tp_itemsize       */'
    print >>gv.out, '    (destructor)%sDealloc, /* tp_dealloc        */' % clname(cl)
    print >>gv.out, '    0,              /* tp_print          */'
    print >>gv.out, '    0,              /* tp_getattr        */'
    print >>gv.out, '    0,              /* tp_setattr        */'
    print >>gv.out, '    0,              /* tp_compare        */'
    if hasmethod(cl, '__repr__'):
        print >>gv.out, '    (PyObject *(*)(PyObject *))%s___repr__, /* tp_repr           */' % clname(cl)
    else:
        print >>gv.out, '    0,              /* tp_repr           */'
    print >>gv.out, '    &%s_as_number,  /* tp_as_number      */' % clname(cl)
    print >>gv.out, '    0,              /* tp_as_sequence    */'
    print >>gv.out, '    0,              /* tp_as_mapping     */'
    print >>gv.out, '    0,              /* tp_hash           */'
    print >>gv.out, '    0,              /* tp_call           */'
    if hasmethod(cl, '__str__'):
        print >>gv.out, '    (PyObject *(*)(PyObject *))%s___str__, /* tp_str           */' % clname(cl)
    else:
        print >>gv.out, '    0,              /* tp_str            */'
    print >>gv.out, '    0,              /* tp_getattro       */'
    print >>gv.out, '    0,              /* tp_setattro       */'
    print >>gv.out, '    0,              /* tp_as_buffer      */'
    print >>gv.out, '    Py_TPFLAGS_DEFAULT, /* tp_flags          */'
    print >>gv.out, '    0,              /* tp_doc            */'
    print >>gv.out, '    0,              /* tp_traverse       */'
    print >>gv.out, '    0,              /* tp_clear          */'
    print >>gv.out, '    0,              /* tp_richcompare    */'
    print >>gv.out, '    0,              /* tp_weaklistoffset */'
    print >>gv.out, '    0,              /* tp_iter           */'
    print >>gv.out, '    0,              /* tp_iternext       */'
    print >>gv.out, '    %sMethods,      /* tp_methods        */' % clname(cl)
    print >>gv.out, '    %sMembers,      /* tp_members        */' % clname(cl)
    print >>gv.out, '    %sGetSet,       /* tp_getset         */' % clname(cl)
    if cl.bases and not cl.bases[0].mv.module.builtin:
            print >>gv.out, '    &%sObjectType,              /* tp_base           */' % clname(cl.bases[0])
    else:
        print >>gv.out, '    0,              /* tp_base           */'
    print >>gv.out, '    0,              /* tp_dict           */'
    print >>gv.out, '    0,              /* tp_descr_get      */'
    print >>gv.out, '    0,              /* tp_descr_set      */'
    print >>gv.out, '    0,              /* tp_dictoffset     */'
    if hasmethod(cl, '__init__') and cl.funcs['__init__'] in funcs:
        print >>gv.out, '    %s___tpinit__, /* tp_init           */' % clname(cl)
    else:
        print >>gv.out, '    0,              /* tp_init           */'
    print >>gv.out, '    0,              /* tp_alloc          */'
    print >>gv.out, '    %sNew,          /* tp_new            */' % clname(cl)
    print >>gv.out, '};\n'
    do_reduce_setstate(gv, cl, vars)
    for n in cl.module.mod_path:
        print >>gv.out, '} // namespace __%s__' % n
    print >>gv.out