134 lines
4.6 KiB
Python
134 lines
4.6 KiB
Python
"""
|
|
Code to generate code for a C/C++ Python extension module.
|
|
"""
|
|
|
|
from function import Function
|
|
from typehandlers.base import CodeBlock, DeclarationsScope
|
|
from cppclass import CppClass
|
|
|
|
|
|
class Module(object):
|
|
"""
|
|
A Module object takes care of generating the code for a Python module.
|
|
"""
|
|
|
|
def __init__(self, name):
|
|
"""Constructor
|
|
name -- module name
|
|
"""
|
|
self.declarations = DeclarationsScope()
|
|
self.name = name
|
|
self.functions = [] # (name, wrapper) pairs
|
|
self.classes = []
|
|
self.before_init = CodeBlock('PyErr_Print();\nreturn;')
|
|
self.after_init = CodeBlock('PyErr_Print();\nreturn;',
|
|
predecessor=self.before_init)
|
|
self.c_function_name_transformer = None
|
|
self.set_strip_prefix(name + '_')
|
|
|
|
def set_strip_prefix(self, prefix):
|
|
"""Sets the prefix string to be used when transforming a C
|
|
function name into the python function name; the given prefix
|
|
string is removed from the C function name."""
|
|
|
|
def strip_prefix(c_name):
|
|
"""A C funtion name transformer that simply strips a
|
|
common prefix from the name"""
|
|
if c_name.startswith(prefix):
|
|
return c_name[len(prefix):]
|
|
else:
|
|
return c_name
|
|
self.c_function_name_transformer = strip_prefix
|
|
|
|
def set_c_function_name_transformer(self, transformer):
|
|
"""Sets the function to be used when transforming a C function
|
|
name into the python function name; the given given function
|
|
is called like this:
|
|
|
|
python_name = transformer(c_name)
|
|
"""
|
|
self.c_function_name_transformer = transformer
|
|
|
|
def add_function(self, wrapper, name=None):
|
|
"""
|
|
Add a function to the module.
|
|
|
|
wrapper -- a Function instance that can generate the wrapper
|
|
name -- name of the module function as it will appear from
|
|
Python side; if not given, the
|
|
c_function_name_transformer callback, or strip_prefix,
|
|
will be used to guess the Python name.
|
|
"""
|
|
assert name is None or isinstance(name, str)
|
|
assert isinstance(wrapper, Function)
|
|
if name is None:
|
|
name = self.c_function_name_transformer(wrapper.function_name)
|
|
self.functions.append((name, wrapper))
|
|
|
|
|
|
def add_class(self, class_):
|
|
"""
|
|
Add a class to the module.
|
|
|
|
class_ -- a CppClass object
|
|
"""
|
|
assert isinstance(class_, CppClass)
|
|
self.classes.append(class_)
|
|
|
|
|
|
def generate(self, code_sink, docstring=None):
|
|
"""Generates the module to a code sink"""
|
|
m = self.declarations.declare_variable('PyObject*', 'm')
|
|
assert m == 'm'
|
|
self.before_init.write_code(
|
|
"m = Py_InitModule3(\"%s\", %s_functions, %s);"
|
|
% (self.name, self.name,
|
|
docstring and '"'+docstring+'"' or 'NULL'))
|
|
self.before_init.write_error_check("m == NULL")
|
|
|
|
## generate the function wrappers
|
|
for func_name, func_wrapper in self.functions:
|
|
code_sink.writeln()
|
|
func_wrapper.generate(code_sink)
|
|
code_sink.writeln()
|
|
|
|
## generate the function table
|
|
code_sink.writeln("static PyMethodDef %s_functions[] = {"
|
|
% (self.name,))
|
|
code_sink.indent()
|
|
for func_name, func_wrapper in self.functions:
|
|
code_sink.writeln(func_wrapper.get_py_method_def(func_name))
|
|
code_sink.writeln("{NULL, NULL, 0, NULL}")
|
|
code_sink.unindent()
|
|
code_sink.writeln("};")
|
|
|
|
## generate the classes
|
|
for class_ in self.classes:
|
|
code_sink.writeln()
|
|
class_.generate(code_sink)
|
|
code_sink.writeln()
|
|
|
|
## register the class type
|
|
self.after_init.write_error_check('PyType_Ready(&%s)'
|
|
% (class_.pytypestruct,))
|
|
## add to the module dict
|
|
self.after_init.write_code(
|
|
'PyModule_AddObject(m, \"%s\", (PyObject *) &%s);' % (
|
|
class_.name, class_.pytypestruct))
|
|
|
|
|
|
## now generate the module init function itself
|
|
code_sink.writeln()
|
|
code_sink.writeln("PyMODINIT_FUNC")
|
|
code_sink.writeln("init%s(void)" % (self.name,))
|
|
code_sink.writeln('{')
|
|
code_sink.indent()
|
|
self.declarations.get_code_sink().flush_to(code_sink)
|
|
self.before_init.sink.flush_to(code_sink)
|
|
self.after_init.write_cleanup()
|
|
self.after_init.sink.flush_to(code_sink)
|
|
code_sink.unindent()
|
|
code_sink.writeln('}')
|
|
|
|
|