llvmpy/newbinding/binding/gen.py
Siu Kwan Lam a12c4da93d Init commit for work on new binding
This contains the foundation for the new binding as well as early work on Module and Type.
2013-02-05 13:47:32 -06:00

206 lines
6.2 KiB
Python

import sys
from binding import *
from utils import *
from cStringIO import StringIO
extension_entry = '''
extern "C" {
#if (PY_MAJOR_VERSION >= 3)
PyObject *
PyInit_%(module)s(void)
{
PyObject *module = create_python_module("%(module)s", %(methtable)s);
if (module) {
if (populate_submodules(module, submodules))
return module;
}
return NULL;
}
#else
PyMODINIT_FUNC
init%(module)s(void)
{
PyObject *module = create_python_module("%(module)s", %(methtable)s);
if (module) {
populate_submodules(module, submodules);
}
}
#endif
} // end extern C
'''
def build_methoddef(name, defns, println):
println('static PyMethodDef %s[] = {' % name)
for name, func in defns:
println('{ "%(name)s", (PyCFunction)%(func)s, METH_VARARGS, NULL },' %
locals())
else:
println('{ NULL }')
println('};')
println('')
class Context(object):
def __init__(self):
self.includes = set()
self.functions = {}
self.classes = {}
self.definitions = []
def generate_cpp(self, println):
for i in self.includes:
println('#include "%s"' % i)
println('\n'.join(self.definitions))
# global function
defns = []
for name, func in self.functions.items():
defns.append((name, func.name))
build_methoddef('global_functions', defns, println)
# classes
for name, cls in self.classes.items():
defns = []
for meth in cls.methods:
defns.append((meth.name, meth.mangled_name))
println("// %s" % cls.fullname)
build_methoddef(cls.mangled_name, defns, println)
println('static SubModuleEntry submodules[] = {')
for name, cls in self.classes.items():
table = cls.mangled_name
println('{ "%(name)s", %(table)s },' % locals())
println('{ NULL },')
println('};')
println('')
# generate entry
println(extension_entry % {'module': '_api',
'methtable': 'global_functions',})
def generate_py(self, println):
println('import _api, capsule')
println('')
# global function
for name in self.functions:
println('def %(name)s(*args):' % locals())
println2 = indent_println(println)
println2('args = map(capsule.unwrap, args)')
println2('ptr = _api.%(name)s(*args)' % locals())
println2('return capsule.wrap(ptr)')
println('')
# classes
classes = sorted(self.classes.items(), key=lambda x: x[1].rank)
for name, cls in classes:
if isinstance(cls, Subclass):
parent = cls.parent.name
else:
parent = 'capsule.Wrapper'
println('@capsule.register_class')
println('class %(name)s(%(parent)s):' % locals())
self.generate_py_class(indent_println(println), cls)
println('')
def generate_py_class(self, println, cls):
if len(cls.methods) == 0:
println('pass')
else:
mod = cls.name
for method in cls.methods:
name = method.name
if isinstance(method, StaticMethod):
println('@staticmethod')
println('def %(name)s(*args):' % locals())
println2 = indent_println(println)
println2('args = map(capsule.unwrap, args)')
println2('ret = _api.%(mod)s.%(name)s(*args)' % locals())
println2('return capsule.wrap(ret)')
elif isinstance(method, Destructor):
println('_delete_ = _api.%(mod)s.%(name)s' % locals())
else:
println('def %(name)s(self, *args):' % locals())
println2 = indent_println(println)
println2('args = map(capsule.unwrap, args)')
println2('ret = _api.%(mod)s.%(name)s(self._ptr, *args)' %
locals())
println2('return capsule.wrap(ret)')
println('')
def add_module(self, modname):
module = __import__(modname)
allsyms = [(k, v) for k, v in vars(module).items()
if isinstance(v, Binding)]
symtab = sorted(allsyms, key=lambda x: x[1].rank)
# generate includes
for k, v in symtab:
self.includes |= v.include
# compile everything
for k, v in symtab:
buf = StringIO()
def println_to_def(s):
buf.write(s)
buf.write('\n')
v.compile(k, println_to_def)
self.definitions.append(buf.getvalue())
buf.close()
# generate py defintion table for global functions
for k, v in symtab:
if isinstance(v, Function):
if v.name in self.functions:
raise NameError("Duplicated function name: %s" % v.name)
self.functions[v.name] = v
# generate sub module tables for classes
submodules = []
for k, v in symtab:
if isinstance(v, Class):
if v.name in self.classes:
if v is not self.classes[v.name]:
raise NameError("Duplicated class: %s" % v.name)
self.classes[v.name] = v
def populate_headers(println):
includes = [
'llvm_binding/conversion.h',
'llvm_binding/binding.h',
'llvm_binding/extra.h',
'llvm_binding/capsule_context.h',
]
for inc in includes:
println('#include "%s"' % inc)
def wrap_println(f):
def println(s):
f.write(s)
f.write('\n')
return println
if __name__ == '__main__':
context = Context()
for mod in sys.argv[2:]:
context.add_module(mod)
filename = sys.argv[1]
with open('%s.cpp' % filename, 'w') as outfile:
println = wrap_println(outfile)
populate_headers(println)
context.generate_cpp(println)
with open('%s.py' % filename, 'w') as outfile:
println = wrap_println(outfile)
context.generate_py(println)