Beispiel #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* '%s' method not exported (staticmethod)" % (func.parent.ident+'.'+func.ident)
            continue
        builtins = True
        for formal in func.formals:
            try:
                typestr.nodetypestr(func.vars[formal], func, check_extmod=True)
            except typestr.ExtmodError:
                builtins = False
                reason = "cannot convert argument '%s'" % formal
        try:
            typestr.nodetypestr(func.retnode.thing, func, check_extmod=True, check_ret=True)
        except typestr.ExtmodError:
            builtins = False
            reason = 'cannot convert return value'
        if builtins:
            supported.append(func)
        else:
            if isinstance(func.parent, class_):
                print "*WARNING* '%s' method not exported (%s)" % (func.parent.ident+'.'+func.ident, reason)
            else:
                print "*WARNING* '%s' function not exported (%s)" % (func.ident, reason)
    return supported
Beispiel #2
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 = typestr.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'
Beispiel #3
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 = typestr.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'
Beispiel #4
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* '%s' method not exported (staticmethod)" % (
                func.parent.ident + '.' + func.ident)
            continue
        builtins = True
        for formal in func.formals:
            try:
                typestr.nodetypestr(func.vars[formal], func, check_extmod=True)
            except typestr.ExtmodError:
                builtins = False
                reason = "cannot convert argument '%s'" % formal
        try:
            typestr.nodetypestr(func.retnode.thing,
                                func,
                                check_extmod=True,
                                check_ret=True)
        except typestr.ExtmodError:
            builtins = False
            reason = 'cannot convert return value'
        if builtins:
            supported.append(func)
        else:
            if isinstance(func.parent, class_):
                print "*WARNING* '%s' method not exported (%s)" % (
                    func.parent.ident + '.' + func.ident, reason)
            else:
                print "*WARNING* '%s' function not exported (%s)" % (
                    func.ident, reason)
    return supported
Beispiel #5
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 = typestr.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))]
            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][0]))
            else:
                gv.visit(defau, func)
        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->message)?(e->message->unit.c_str()):""));'
    print >>gv.out, '        return 0;'
    print >>gv.out, '    }'
    print >>gv.out, '}\n'
Beispiel #6
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 singletype2(getgx().merged_inh[var], module):
            continue
        try:
            typehu = typestr.nodetypestr(var, var.parent, check_extmod=True)
        except typestr.ExtmodError:
            if isinstance(var.parent, class_):
                print "*WARNING* '%s' variable not exported (cannot convert)" % (var.parent.ident+'.'+var.name)
            else:
                print "*WARNING* '%s' variable not exported (cannot convert)" % var.name
            continue
        supported.append(var)
    return supported
Beispiel #7
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 singletype2(getgx().merged_inh[var], module):
            continue
        try:
            typehu = typestr.nodetypestr(var, var.parent, check_extmod=True)
        except typestr.ExtmodError:
            if isinstance(var.parent, class_):
                print "*WARNING* '%s' variable not exported (cannot convert)" % (
                    var.parent.ident + '.' + var.name)
            else:
                print "*WARNING* '%s' variable not exported (cannot convert)" % var.name
            continue
        supported.append(var)
    return supported
Beispiel #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(),
                                                   cl.cpp_name())
    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(), cl.cpp_name())
    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 = typestr.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->message)?(e->message->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
Beispiel #9
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 = typestr.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))]
            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][0]))
            else:
                gv.visit(defau, func)
        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->message)?(e->message->unit.c_str()):""));'
    print >> gv.out, '        return 0;'
    print >> gv.out, '    }'
    print >> gv.out, '}\n'
Beispiel #10
0
def analyze(source, testing=False):
    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)])

    # --- 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()

    if not getgx().silent:
        print '[generating c++ code..]'

    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))

    mv = getgx().main_module.mv
    setmv(mv)

    getgx().merged_inh = merged(getgx().types, inheritance=True)
    virtual.analyze_virtuals()
    copy_.determine_classes()

    # --- add inheritance relationships for non-original Nodes (and tempvars?); XXX register more, right solution?
    for func in getgx().allfuncs:
        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)

    # error for dynamic expression without explicit type declaration
    for node in getgx().merged_inh:
        if isinstance(node, Node) and not isinstance(
                node, AssAttr) and not inode(node).mv.module.builtin:
            typestr.nodetypestr(node, inode(node).parent)

    return getgx()
Beispiel #11
0
def analyze(source, testing=False):
    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)])

    # --- 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()

    if not getgx().silent:
        print '[generating c++ code..]'

    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))

    mv = getgx().main_module.mv
    setmv(mv)

    getgx().merged_inh = merged(getgx().types, inheritance=True)
    virtual.analyze_virtuals()
    copy_.determine_classes()

    # --- add inheritance relationships for non-original Nodes (and tempvars?); XXX register more, right solution?
    for func in getgx().allfuncs:
        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)

    # error for dynamic expression without explicit type declaration
    for node in getgx().merged_inh:
        if isinstance(node, Node) and not isinstance(node, AssAttr) and not inode(node).mv.module.builtin:
            typestr.nodetypestr(node, inode(node).parent)

    return getgx()
Beispiel #12
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(),
                                                   cl.cpp_name())
    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(), cl.cpp_name())
    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 = typestr.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->message)?(e->message->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