Init commit for work on new binding
This contains the foundation for the new binding as well as early work on Module and Type.
This commit is contained in:
parent
b793e72189
commit
a12c4da93d
23 changed files with 1477 additions and 0 deletions
18
newbinding/Makefile
Normal file
18
newbinding/Makefile
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
PYMODS = _Debug raw_ostream Type DerivedTypes LLVMContext StringRef AssemblyAnnotationWriter Module
|
||||
|
||||
all: _api.so _capsule.so
|
||||
|
||||
_api.so _capsule.so: api.cpp capsule.cpp
|
||||
python setup.py build_ext --inplace
|
||||
|
||||
|
||||
api.cpp api.py: binding/*.py include/llvm_binding/*.h
|
||||
cd binding; python gen.py api $(PYMODS)
|
||||
mv binding/api.cpp api.cpp
|
||||
mv binding/api.py api.py
|
||||
|
||||
clean:
|
||||
rm -f _api.so _capsule.so
|
||||
rm -f api.cpp api.py
|
||||
|
||||
|
||||
6
newbinding/binding/AssemblyAnnotationWriter.py
Normal file
6
newbinding/binding/AssemblyAnnotationWriter.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from binding import *
|
||||
from namespace import llvm
|
||||
|
||||
AssemblyAnnotationWriter = llvm.Class()
|
||||
AssemblyAnnotationWriter.include.add("llvm/Assembly/AssemblyAnnotationWriter.h")
|
||||
|
||||
13
newbinding/binding/DerivedTypes.py
Normal file
13
newbinding/binding/DerivedTypes.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
from binding import *
|
||||
from namespace import llvm
|
||||
from LLVMContext import LLVMContext
|
||||
from Type import Type
|
||||
|
||||
FunctionType = Type.Subclass()
|
||||
FunctionType.include.add('llvm/DerivedTypes.h')
|
||||
|
||||
get = FunctionType.staticmethod(FunctionType.Pointer, Type.Pointer, Bool.From(bool))
|
||||
isVarArg = FunctionType.method(Bool.To(bool))
|
||||
getReturnType = FunctionType.method(Type.Pointer)
|
||||
getParamType = FunctionType.method(Type.Pointer, Unsigned.From(int))
|
||||
getNumParams = FunctionType.method(Unsigned.To(int))
|
||||
8
newbinding/binding/LLVMContext.py
Normal file
8
newbinding/binding/LLVMContext.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
from binding import *
|
||||
from namespace import llvm
|
||||
|
||||
LLVMContext = llvm.Class()
|
||||
LLVMContext.include.add("llvm/LLVMContext.h")
|
||||
|
||||
getGlobalContext = llvm.Function(LLVMContext.Ref)
|
||||
|
||||
0
newbinding/binding/Makefile
Normal file
0
newbinding/binding/Makefile
Normal file
25
newbinding/binding/Module.py
Normal file
25
newbinding/binding/Module.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
from binding import *
|
||||
from namespace import llvm
|
||||
from LLVMContext import LLVMContext
|
||||
from StringRef import StringRef
|
||||
from raw_ostream import raw_svector_ostream_helper
|
||||
from AssemblyAnnotationWriter import AssemblyAnnotationWriter
|
||||
|
||||
Module = llvm.Class()
|
||||
Module.include.add("llvm/Module.h")
|
||||
|
||||
new = Module.new(StringRef.From(str), LLVMContext.Ref)
|
||||
delete = Module.delete()
|
||||
getModuleIdentifier = Module.method(ConstStdString.To(str))
|
||||
setModuleIdentifier = Module.method(Void, StringRef.From(str))
|
||||
setDataLayout = Module.method(Void, StringRef.From(str))
|
||||
setTargetTriple = Module.method(Void, StringRef.From(str))
|
||||
setModuleInlineAsm = Module.method(Void, StringRef.From(str))
|
||||
appendModuleInlineAsm = Module.method(Void, StringRef.From(str))
|
||||
getContext = Module.method(LLVMContext.Ref)
|
||||
dump = Module.method(Void)
|
||||
print_ = Module.method(Void, raw_svector_ostream_helper.Ref,
|
||||
AssemblyAnnotationWriter.Pointer)
|
||||
print_.realname = 'print'
|
||||
#getOrInsertFunction = Module.method(Constant, StringRef.From(str), FunctionType.Pointer)
|
||||
|
||||
6
newbinding/binding/StringRef.py
Normal file
6
newbinding/binding/StringRef.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from binding import *
|
||||
from namespace import llvm
|
||||
|
||||
StringRef = llvm.Class()
|
||||
StringRef.include.add("llvm/ADT/StringRef.h")
|
||||
|
||||
96
newbinding/binding/Type.py
Normal file
96
newbinding/binding/Type.py
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
from binding import *
|
||||
from namespace import llvm
|
||||
from LLVMContext import LLVMContext
|
||||
from raw_ostream import raw_svector_ostream_helper
|
||||
|
||||
Type = llvm.Class()
|
||||
Type.include.add('llvm/Type.h')
|
||||
|
||||
IntegerType = Type.Subclass()
|
||||
CompositeType = Type.Subclass()
|
||||
SequentialType = CompositeType.Subclass()
|
||||
PointerType = SequentialType.Subclass()
|
||||
|
||||
getContext = Type.method(LLVMContext.Ref)
|
||||
dump = Type.method(Void)
|
||||
print_ = Type.method(Void, raw_svector_ostream_helper.Ref)
|
||||
print_.realname = 'print'
|
||||
|
||||
def type_checker():
|
||||
return Type.method(Bool.To(bool))
|
||||
|
||||
isVoidTy = type_checker()
|
||||
isHalfTy = type_checker()
|
||||
isFloatTy = type_checker()
|
||||
isDoubleTy = type_checker()
|
||||
isX86_FP80Ty = type_checker()
|
||||
isFP128Ty = type_checker()
|
||||
isPPC_FP128Ty = type_checker()
|
||||
isFloatingPointTy = type_checker()
|
||||
isX86_MMXTy = type_checker()
|
||||
isFPOrFPVectorTy = type_checker()
|
||||
isLabelTy = type_checker()
|
||||
isMetadataTy = type_checker()
|
||||
isIntOrIntVectorTy = type_checker()
|
||||
isFunctionTy = type_checker()
|
||||
isStructTy = type_checker()
|
||||
isArrayTy = type_checker()
|
||||
isPointerTy = type_checker()
|
||||
isPtrOrPtrVectorTy = type_checker()
|
||||
isVectorTy = type_checker()
|
||||
isEmptyTy = type_checker()
|
||||
isPrimitiveType = type_checker()
|
||||
isDerivedType = type_checker()
|
||||
isFirstClassType = type_checker()
|
||||
isSingleValueType = type_checker()
|
||||
isAggregateType = type_checker()
|
||||
isSized = type_checker()
|
||||
|
||||
isIntegerTy = Type.multimethod([Bool.To(bool)],
|
||||
[Bool.To(bool), Unsigned.From(int)])
|
||||
|
||||
|
||||
def type_factory():
|
||||
return Type.staticmethod(Type.Pointer, LLVMContext.Ref)
|
||||
|
||||
getVoidTy = type_factory()
|
||||
getLabelTy = type_factory()
|
||||
getHalfTy = type_factory()
|
||||
getFloatTy = type_factory()
|
||||
getDoubleTy = type_factory()
|
||||
getMetadataTy = type_factory()
|
||||
getX86_FP80Ty = type_factory()
|
||||
getFP128Ty = type_factory()
|
||||
getPPC_FP128Ty = type_factory()
|
||||
getX86_MMXTy = type_factory()
|
||||
|
||||
getIntNTy = Type.staticmethod(IntegerType.Pointer, LLVMContext.Ref, Unsigned.From(int))
|
||||
|
||||
def integer_factory():
|
||||
return Type.staticmethod(IntegerType.Pointer, LLVMContext.Ref)
|
||||
|
||||
getInt1Ty = integer_factory()
|
||||
getInt8Ty = integer_factory()
|
||||
getInt16Ty = integer_factory()
|
||||
getInt32Ty = integer_factory()
|
||||
getInt64Ty = integer_factory()
|
||||
|
||||
def pointer_factory():
|
||||
return Type.staticmethod(PointerType.Pointer, LLVMContext.Ref)
|
||||
|
||||
getHalfPtrTy = pointer_factory()
|
||||
getFloatPtrTy = pointer_factory()
|
||||
getDoublePtrTy = pointer_factory()
|
||||
getX86_FP80PtrTy = pointer_factory()
|
||||
getFP128PtrTy = pointer_factory()
|
||||
getPPC_FP128PtrTy = pointer_factory()
|
||||
getX86_MMXPtrTy = pointer_factory()
|
||||
getInt1PtrTy = pointer_factory()
|
||||
getInt8PtrTy = pointer_factory()
|
||||
getInt16PtrTy = pointer_factory()
|
||||
getInt32PtrTy = pointer_factory()
|
||||
getInt64PtrTy = pointer_factory()
|
||||
getIntNPtrTy = Type.staticmethod(PointerType.Pointer,
|
||||
LLVMContext.Ref, Unsigned.From(int))
|
||||
|
||||
|
||||
3
newbinding/binding/_Debug.py
Normal file
3
newbinding/binding/_Debug.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from binding import *
|
||||
|
||||
enable_capsule_dtor_debug = Function('', Void, Bool.From(bool))
|
||||
498
newbinding/binding/binding.py
Normal file
498
newbinding/binding/binding.py
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
from utils import *
|
||||
|
||||
_py2capi_fmtmap = {
|
||||
str: 's#',
|
||||
}
|
||||
|
||||
NULL = 'NULL'
|
||||
|
||||
_symbols = set()
|
||||
|
||||
def new_symbol(name):
|
||||
if name in _symbols:
|
||||
ct = 1
|
||||
orig = name
|
||||
while name in _symbols:
|
||||
name = '%s%d' % (orig, ct)
|
||||
ct += 1
|
||||
_symbols.add(name)
|
||||
return name
|
||||
|
||||
def parse_arguments(println, var, *args):
|
||||
typecodes = []
|
||||
holders = []
|
||||
argvals = []
|
||||
for arg in args:
|
||||
typecodes.append(arg.format)
|
||||
val = declare(println, 'PyObject*')
|
||||
argvals.append(val)
|
||||
holders.append('&' + val)
|
||||
|
||||
items = [var, '"%s"' % (''.join(typecodes))] + holders
|
||||
println('if(!PyArg_ParseTuple(%s)) return NULL;' % ', '.join(items))
|
||||
|
||||
# unwrap
|
||||
unwrapped = []
|
||||
for arg, val in zip(args, argvals):
|
||||
unwrapped.append(arg.unwrap(println, val))
|
||||
|
||||
return unwrapped
|
||||
|
||||
def mangle(name):
|
||||
name = name.replace('_', '__').replace(' ', '_')
|
||||
return name.replace('::', '_').rstrip('*&')
|
||||
|
||||
def pycapsule_new(println, ptr, name, clsname, dtor='capsule_destructor'):
|
||||
# build capsule
|
||||
name_soften = mangle(name)
|
||||
var = new_symbol('pycap_%s' % name_soften)
|
||||
fmt = 'PyObject* %(var)s = PyCapsule_New(%(ptr)s, "%(name)s", %(dtor)s);'
|
||||
println(fmt % locals())
|
||||
|
||||
# build context
|
||||
fmt = 'new CapsuleContext("%(clsname)s")'
|
||||
context = declare(println, 'CapsuleContext*', fmt % locals())
|
||||
|
||||
fmt = 'PyCapsule_SetContext(%(var)s, (void*)%(context)s)'
|
||||
err = declare(println, 'int', fmt % locals())
|
||||
|
||||
println('if (%(err)s) return NULL;' % locals())
|
||||
return var
|
||||
|
||||
|
||||
def declare(println, typ, init=None):
|
||||
typ_soften = mangle(typ)
|
||||
var = new_symbol('var_%s' % typ_soften)
|
||||
if init is None:
|
||||
println('%(typ)s %(var)s;' % locals())
|
||||
else:
|
||||
println('%(typ)s %(var)s = %(init)s;' % locals())
|
||||
return var
|
||||
|
||||
|
||||
def return_value(println, var):
|
||||
println('return %(var)s;' % locals())
|
||||
|
||||
|
||||
def return_none(println):
|
||||
println('Py_RETURN_NONE;')
|
||||
|
||||
|
||||
def die_if_null(println, var):
|
||||
println('if (!%(var)s) return NULL;' % locals())
|
||||
|
||||
|
||||
class Binding(object):
|
||||
__rank_global = 0
|
||||
def __init__(self):
|
||||
self.rank = Binding.__rank_global
|
||||
Binding.__rank_global += 1
|
||||
self.include = set()
|
||||
|
||||
def compile(self, name, println):
|
||||
raise NotImplementedError(type(self))
|
||||
|
||||
class Ref(object):
|
||||
def __init__(self, elem):
|
||||
self.element = elem
|
||||
|
||||
@property
|
||||
def fullname(self):
|
||||
return '%s&' % self.element.fullname
|
||||
|
||||
@property
|
||||
def capsule_name(self):
|
||||
return self.element.capsule_name
|
||||
|
||||
@property
|
||||
def pointer(self):
|
||||
return self.element.pointer
|
||||
|
||||
def as_pointer(self, println, var):
|
||||
init = '&%s' % (var)
|
||||
casted = declare(println, self.pointer, init)
|
||||
return casted
|
||||
|
||||
@property
|
||||
def format(self):
|
||||
return 'O'
|
||||
|
||||
def unwrap(self, println, var):
|
||||
ptr = self.element.unwrap(println, var)
|
||||
return declare(println, self.fullname, '*%s' % ptr)
|
||||
|
||||
def wrap(self, println, var):
|
||||
return self.element.wrap(println, self.as_pointer(println, var))
|
||||
|
||||
|
||||
class Pointer(object):
|
||||
def __init__(self, elem):
|
||||
self.element = elem
|
||||
|
||||
@property
|
||||
def fullname(self):
|
||||
return '%s*' % self.element.fullname
|
||||
|
||||
@property
|
||||
def capsule_name(self):
|
||||
return self.element.capsule_name
|
||||
|
||||
@property
|
||||
def pointer(self):
|
||||
return self.element.pointer
|
||||
|
||||
@property
|
||||
def format(self):
|
||||
return 'O'
|
||||
|
||||
def unwrap(self, println, var):
|
||||
ret = declare(println, self.fullname)
|
||||
println2 = indent_println(println)
|
||||
println('if (%(var)s == Py_None) {' % locals())
|
||||
println2('%(ret)s = NULL;' % locals())
|
||||
println('} else {')
|
||||
ptr = self.element.unwrap(println2, var)
|
||||
println2('%(ret)s = %(ptr)s;' % locals())
|
||||
println('}')
|
||||
return ret
|
||||
|
||||
def wrap(self, println, var):
|
||||
return self.element.wrap(println, var)
|
||||
|
||||
|
||||
class BuiltinType(object):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.Ref = Ref(self)
|
||||
self.Pointer = Pointer(self)
|
||||
|
||||
@property
|
||||
def fullname(self):
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def capsule_name(self):
|
||||
return self.fullname
|
||||
|
||||
def To(self, pytype):
|
||||
return Wrapper(self, pytype)
|
||||
|
||||
def From(self, pytype):
|
||||
return Unwrapper(self, pytype)
|
||||
|
||||
Void = BuiltinType('void')
|
||||
Bool = BuiltinType('bool')
|
||||
Unsigned = BuiltinType('unsigned')
|
||||
ConstStdString = BuiltinType('const std::string')
|
||||
|
||||
class Unwrapper(object):
|
||||
def __init__(self, cls, pytype):
|
||||
self.cls = cls
|
||||
self.pytype = pytype
|
||||
|
||||
@property
|
||||
def fullname(self):
|
||||
return str(self.pytype)
|
||||
|
||||
@property
|
||||
def format(self):
|
||||
return 'O'
|
||||
|
||||
def unwrap(self, println, var):
|
||||
out = declare(println, self.cls.fullname)
|
||||
conv = 'py_%s_to' % (self.pytype.__name__)
|
||||
status = '%(conv)s(%(var)s, %(out)s)' % locals()
|
||||
println('if (!%(status)s) return NULL;' % locals())
|
||||
return out
|
||||
|
||||
|
||||
class Wrapper(object):
|
||||
def __init__(self, cls, pytype):
|
||||
self.cls = cls
|
||||
self.pytype = pytype
|
||||
|
||||
@property
|
||||
def fullname(self):
|
||||
return self.cls.fullname
|
||||
|
||||
def wrap(self, println, var):
|
||||
conv = 'py_%s_from' % (self.pytype.__name__)
|
||||
func = '%(conv)s(%(var)s)' % locals()
|
||||
out = declare(println, 'PyObject*', func)
|
||||
println('if (!%(out)s) return NULL;' % locals())
|
||||
return out
|
||||
|
||||
class Class(Binding):
|
||||
def __init__(self, ns):
|
||||
super(Class, self).__init__()
|
||||
self.ctor = None
|
||||
self.Ref = Ref(self)
|
||||
self.Pointer = Pointer(self)
|
||||
self.Subclass = lambda: Subclass(self)
|
||||
self.ns = ns
|
||||
self.methods = []
|
||||
self.name = None
|
||||
|
||||
def To(self, pytype):
|
||||
return Wrapper(self, pytype)
|
||||
|
||||
def From(self, pytype):
|
||||
return Unwrapper(self, pytype)
|
||||
|
||||
def new(self, *args):
|
||||
method = Constructor(self, self.Pointer, *args)
|
||||
self.methods.append(method)
|
||||
return method
|
||||
|
||||
def delete(self):
|
||||
method = Destructor(self, Void, self.Pointer)
|
||||
self.methods.append(method)
|
||||
return method
|
||||
|
||||
def method(self, return_type, *args):
|
||||
method = Method(self, return_type, self.Pointer, *args)
|
||||
self.methods.append(method)
|
||||
return method
|
||||
|
||||
def staticmethod(self, return_type, *args):
|
||||
sm = StaticMethod(self, return_type, *args)
|
||||
self.methods.append(sm)
|
||||
return sm
|
||||
|
||||
def multimethod(self, *signatures):
|
||||
mm = MultiMethod(self, signatures)
|
||||
self.methods.append(mm)
|
||||
return mm
|
||||
|
||||
def compile(self, name, println):
|
||||
# set name
|
||||
self.name = self.name or name
|
||||
|
||||
@property
|
||||
def capsule_name(self):
|
||||
return self.fullname
|
||||
|
||||
@property
|
||||
def pointer(self):
|
||||
return '%s*' % self.fullname
|
||||
|
||||
@property
|
||||
def fullname(self):
|
||||
return '::'.join([self.ns, self.name])
|
||||
|
||||
@property
|
||||
def mangled_name(self):
|
||||
return mangle(self.fullname)
|
||||
|
||||
@property
|
||||
def format(self):
|
||||
return 'O'
|
||||
|
||||
def unwrap(self, println, var):
|
||||
typ = self.pointer
|
||||
elty = self.fullname
|
||||
cap = self.capsule_name
|
||||
capptr = 'PyCapsule_GetPointer(%(var)s, "%(cap)s")' % locals()
|
||||
ptr = declare(println, 'void*', capptr)
|
||||
unwrapped = 'typecast<%(elty)s>::from(%(ptr)s)' % locals()
|
||||
var = declare(println, typ, unwrapped)
|
||||
println('if (!%(var)s) {' % locals())
|
||||
println2 = indent_println(println)
|
||||
println2('PyErr_SetString(PyExc_TypeError, "Invalid cast");')
|
||||
println2('return NULL;')
|
||||
println('}')
|
||||
die_if_null(println, var)
|
||||
return var
|
||||
|
||||
def wrap(self, println, var):
|
||||
return pycapsule_new(println, var, self.capsule_name, self.fullname)
|
||||
|
||||
class Subclass(Class):
|
||||
def __init__(self, parent):
|
||||
super(Subclass, self).__init__(parent.ns)
|
||||
self.parent = parent
|
||||
self.ns = self.parent.ns
|
||||
|
||||
@property
|
||||
def capsule_name(self):
|
||||
return self.parent.capsule_name
|
||||
|
||||
class Function(Binding):
|
||||
def __init__(self, ns, return_type, *args):
|
||||
super(Function, self).__init__()
|
||||
self.return_type = return_type
|
||||
self.args = args
|
||||
self.ns = ns
|
||||
self.name = None
|
||||
|
||||
def compile(self, name, println):
|
||||
# set name
|
||||
self.name = self.name or name
|
||||
# generate wrapper
|
||||
println('static')
|
||||
println('PyObject*')
|
||||
println('%(name)s(PyObject* self, PyObject* args)' % locals())
|
||||
println('{')
|
||||
self.compile_body(indent_println(println))
|
||||
println('}')
|
||||
|
||||
def compile_body(self, println):
|
||||
args = parse_arguments(println, 'args', *self.args)
|
||||
call = '%s(%s)' % (self.fullname, ', '.join(args))
|
||||
if self.return_type is not Void:
|
||||
callres = declare(println, self.return_type.fullname, call)
|
||||
pycap = self.return_type.wrap(println, callres)
|
||||
return_value(println, pycap)
|
||||
else:
|
||||
println('%s;' % call)
|
||||
return_none(println)
|
||||
|
||||
|
||||
@property
|
||||
def fullname(self):
|
||||
return '::'.join([self.ns, self.name])
|
||||
|
||||
class Method(Binding):
|
||||
def __init__(self, cls, return_type, *args):
|
||||
super(Method, self).__init__()
|
||||
self.cls = cls
|
||||
self.return_type = return_type
|
||||
self.args = args
|
||||
self.name = None
|
||||
self._realname = None
|
||||
|
||||
def compile(self, name, println):
|
||||
# set name
|
||||
self.name = self.name or name
|
||||
# generate wrapper
|
||||
println('static')
|
||||
println('PyObject*')
|
||||
mangled = self.mangled_name
|
||||
println('%(mangled)s(PyObject* self, PyObject* args)' % locals())
|
||||
println('{')
|
||||
self.compile_body(indent_println(println))
|
||||
println('}')
|
||||
|
||||
def compile_body(self, println):
|
||||
args = parse_arguments(println, 'args', *self.args)
|
||||
this = args[0]
|
||||
args = ', '.join(args[1:])
|
||||
name = self.realname
|
||||
call = '%(this)s->%(name)s(%(args)s)' % locals()
|
||||
if self.return_type is not Void:
|
||||
obj = declare(println, self.return_type.fullname, call)
|
||||
ret = self.return_type.wrap(println, obj)
|
||||
return_value(println, ret)
|
||||
else:
|
||||
println('%s;' % call)
|
||||
return_none(println)
|
||||
|
||||
@property
|
||||
def fullname(self):
|
||||
return '::'.join([self.cls.fullname, self.name])
|
||||
|
||||
@property
|
||||
def realname(self):
|
||||
if not self._realname:
|
||||
return self.name
|
||||
else:
|
||||
return self._realname
|
||||
|
||||
@realname.setter
|
||||
def realname(self, v):
|
||||
self._realname = v
|
||||
|
||||
|
||||
@property
|
||||
def mangled_name(self):
|
||||
return mangle(self.fullname)
|
||||
|
||||
class MultiMethod(Binding):
|
||||
'''Can only differs by the number of arguments.
|
||||
'''
|
||||
def __init__(self, cls, signatures):
|
||||
super(MultiMethod, self).__init__()
|
||||
nargs = set()
|
||||
for sig in signatures:
|
||||
n = len(sig)
|
||||
if n in nargs:
|
||||
raise TypeError("MultiMethod only supports overloaded version"
|
||||
"with different number of arguments")
|
||||
nargs.add(n)
|
||||
self.cls = cls
|
||||
self.signatures = signatures
|
||||
self.name = None
|
||||
|
||||
def compile(self, name, println):
|
||||
# set name
|
||||
self.name = self.name or name
|
||||
# generate wrapper
|
||||
println('static')
|
||||
println('PyObject*')
|
||||
mangled = self.mangled_name
|
||||
println('%(mangled)s(PyObject* self, PyObject* args)' % locals())
|
||||
println('{')
|
||||
println2 = indent_println(println)
|
||||
nargs = declare(println2, 'Py_ssize_t', 'PyTuple_Size(args)')
|
||||
for sig in self.signatures:
|
||||
expect = len(sig)
|
||||
println2('if (%(nargs)s == %(expect)d) {' % locals())
|
||||
method = Method(self.cls, sig[0], self.cls.Pointer, *sig[1:])
|
||||
method.name = self.name
|
||||
method.compile_body(indent_println(println2))
|
||||
println2('}')
|
||||
println2('PyErr_SetString(PyExc_TypeError, "Wrong # of args");')
|
||||
println2('return NULL;')
|
||||
println('}')
|
||||
|
||||
@property
|
||||
def fullname(self):
|
||||
return '::'.join([self.cls.fullname, self.name])
|
||||
|
||||
@property
|
||||
def mangled_name(self):
|
||||
return mangle(self.fullname)
|
||||
|
||||
class StaticMethod(Method):
|
||||
def compile_body(self, println):
|
||||
args = parse_arguments(println, 'args', *self.args)
|
||||
args = ', '.join(args)
|
||||
fullname = self.fullname
|
||||
call = '%(fullname)s(%(args)s)' % locals()
|
||||
if self.return_type is not Void:
|
||||
obj = declare(println, self.return_type.fullname, call)
|
||||
ret = self.return_type.wrap(println, obj)
|
||||
return_value(println, ret)
|
||||
else:
|
||||
println('%s;' % call)
|
||||
return_none(println)
|
||||
|
||||
class Constructor(StaticMethod):
|
||||
def compile_body(self, println):
|
||||
args = parse_arguments(println, 'args', *self.args)
|
||||
args = ', '.join(args)
|
||||
name = self.cls.fullname
|
||||
ctor = 'new %(name)s(%(args)s)' % locals()
|
||||
obj = declare(println, self.cls.pointer, ctor)
|
||||
ret = self.return_type.wrap(println, obj)
|
||||
return_value(println, ret)
|
||||
|
||||
class Destructor(Method):
|
||||
def compile_body(self, println):
|
||||
args = parse_arguments(println, 'args', *self.args)
|
||||
assert len(args) == 1
|
||||
dtor = 'delete %s;' % args[0]
|
||||
println(dtor)
|
||||
return_none(println)
|
||||
|
||||
|
||||
class Namespace(object):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def Class(self, *args, **kwargs):
|
||||
return Class(self.name, *args, **kwargs)
|
||||
|
||||
def Function(self, *args, **kwargs):
|
||||
return Function(self.name, *args, **kwargs)
|
||||
|
||||
206
newbinding/binding/gen.py
Normal file
206
newbinding/binding/gen.py
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
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)
|
||||
|
||||
4
newbinding/binding/namespace.py
Normal file
4
newbinding/binding/namespace.py
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
from binding import *
|
||||
|
||||
extra = Namespace('llvm_extra')
|
||||
llvm = Namespace('llvm')
|
||||
17
newbinding/binding/raw_ostream.py
Normal file
17
newbinding/binding/raw_ostream.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
from binding import *
|
||||
from namespace import llvm
|
||||
from LLVMContext import LLVMContext
|
||||
from StringRef import StringRef
|
||||
|
||||
raw_ostream = llvm.Class()
|
||||
raw_ostream.include.add("llvm/Support/raw_ostream.h")
|
||||
|
||||
raw_svector_ostream = raw_ostream.Subclass()
|
||||
raw_svector_ostream.include.add("llvm/Support/raw_os_ostream.h")
|
||||
|
||||
# extra class to help binding
|
||||
raw_svector_ostream_helper = raw_svector_ostream.Subclass()
|
||||
create = raw_svector_ostream_helper.staticmethod(
|
||||
raw_svector_ostream_helper.Pointer)
|
||||
delete = raw_svector_ostream_helper.delete()
|
||||
str = raw_svector_ostream_helper.method(StringRef.To(str))
|
||||
6
newbinding/binding/utils.py
Normal file
6
newbinding/binding/utils.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
def indent_println(println):
|
||||
def _println(s):
|
||||
println("%s%s" % (' '* 4, s))
|
||||
return _println
|
||||
|
||||
143
newbinding/capsule.cpp
Normal file
143
newbinding/capsule.cpp
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
#include <Python.h>
|
||||
#include <llvm_binding/capsule_context.h>
|
||||
|
||||
static
|
||||
PyObject* getName(PyObject* self, PyObject* args) {
|
||||
PyObject* obj;
|
||||
if (!PyArg_ParseTuple(args, "O", &obj)){
|
||||
return NULL;
|
||||
}
|
||||
const char* name = PyCapsule_GetName(obj);
|
||||
if (!name) return NULL;
|
||||
|
||||
return PyString_FromString(name);
|
||||
}
|
||||
|
||||
static
|
||||
PyObject* getPointer(PyObject* self, PyObject* args) {
|
||||
PyObject* obj;
|
||||
if (!PyArg_ParseTuple(args, "O", &obj)){
|
||||
return NULL;
|
||||
}
|
||||
void* pointer = PyCapsule_GetPointer(obj, PyCapsule_GetName(obj));
|
||||
if (!pointer) return NULL;
|
||||
|
||||
return PyLong_FromVoidPtr(pointer);
|
||||
}
|
||||
|
||||
static
|
||||
PyObject* check(PyObject* self, PyObject* args) {
|
||||
PyObject* obj;
|
||||
if (!PyArg_ParseTuple(args, "O", &obj)){
|
||||
return NULL;
|
||||
}
|
||||
if (PyCapsule_CheckExact(obj)) {
|
||||
Py_RETURN_TRUE;
|
||||
} else {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------
|
||||
// PyCapsule Context
|
||||
// ------------------
|
||||
|
||||
static
|
||||
CapsuleContext* getContext(PyObject* self, PyObject* args) {
|
||||
PyObject* obj;
|
||||
if (!PyArg_ParseTuple(args, "O", &obj)) {
|
||||
return NULL;
|
||||
}
|
||||
void* context = PyCapsule_GetContext(obj);
|
||||
if (!context) {
|
||||
PyErr_SetString(PyExc_TypeError, "PyCapsule has no context.");
|
||||
return NULL;
|
||||
}
|
||||
return (CapsuleContext*)context;
|
||||
}
|
||||
|
||||
static
|
||||
PyObject* getClassName(PyObject* self, PyObject* args) {
|
||||
CapsuleContext* context = getContext(self, args);
|
||||
if (!context) {
|
||||
return NULL;
|
||||
} else {
|
||||
return PyString_FromString(context->className);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
PyObject* setDestructor(PyObject* self, PyObject* args) {
|
||||
PyObject* cap;
|
||||
PyObject* callable;
|
||||
if (!PyArg_ParseTuple(args, "OO", &cap, &callable)) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject* arglist = Py_BuildValue("(O)", cap);
|
||||
CapsuleContext* context = getContext(self, arglist);
|
||||
Py_DECREF(arglist);
|
||||
if (!context) {
|
||||
return NULL;
|
||||
} else {
|
||||
void* ptr;
|
||||
if (callable != Py_None) {
|
||||
if (PyCallable_Check(callable)) {
|
||||
ptr = callable;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError, "Argument is not callable.");
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
ptr = NULL;
|
||||
}
|
||||
context->destructor = (Destructor_Fn)ptr;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef core_methods[] = {
|
||||
#define declmethod(func) { #func , ( PyCFunction )func , METH_VARARGS , NULL }
|
||||
declmethod(getName),
|
||||
declmethod(getPointer),
|
||||
declmethod(check),
|
||||
declmethod(getClassName),
|
||||
declmethod(setDestructor),
|
||||
{ NULL },
|
||||
#undef declmethod
|
||||
};
|
||||
|
||||
// Module main function, hairy because of py3k port
|
||||
extern "C" {
|
||||
|
||||
#if (PY_MAJOR_VERSION >= 3)
|
||||
struct PyModuleDef module_def = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_capsule",
|
||||
NULL,
|
||||
-1,
|
||||
core_methods,
|
||||
NULL, NULL, NULL, NULL
|
||||
};
|
||||
#define INITERROR return NULL
|
||||
PyObject *
|
||||
PyInit__capsule(void)
|
||||
#else
|
||||
#define INITERROR return
|
||||
PyMODINIT_FUNC
|
||||
init_capsule(void)
|
||||
#endif
|
||||
{
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *module = PyModule_Create( &module_def );
|
||||
#else
|
||||
PyObject *module = Py_InitModule("_capsule", core_methods);
|
||||
#endif
|
||||
if (module == NULL)
|
||||
INITERROR;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
|
||||
return module;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // end extern C
|
||||
74
newbinding/capsule.py
Normal file
74
newbinding/capsule.py
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import _capsule
|
||||
from weakref import WeakValueDictionary
|
||||
|
||||
_pyclasses = {}
|
||||
_addr2obj = WeakValueDictionary()
|
||||
|
||||
|
||||
def _sentry(ptr):
|
||||
assert _capsule.check(ptr)
|
||||
|
||||
|
||||
def classof(cap):
|
||||
cls = _capsule.getClassName(cap)
|
||||
return _pyclasses[cls]
|
||||
|
||||
|
||||
def wrap(cap):
|
||||
'''Wrap a PyCapsule with the corresponding Wrapper class.
|
||||
If `cap` is not a PyCapsule, returns `cap`
|
||||
'''
|
||||
if not _capsule.check(cap): # bypass if cap is not a PyCapsule
|
||||
return cap
|
||||
addr = _capsule.getPointer(cap)
|
||||
try:
|
||||
# find cached object by pointer address
|
||||
obj = _addr2obj[addr]
|
||||
except KeyError:
|
||||
# create new object and cache it
|
||||
cls = classof(cap)
|
||||
obj = cls(cap)
|
||||
_addr2obj[addr] = obj # cache object by address
|
||||
# set destructor if cls.delete is defined
|
||||
if hasattr(cls, '_delete_'):
|
||||
_capsule.setDestructor(cap, cls._delete_)
|
||||
else:
|
||||
assert classof(obj._ptr) is classof(cap)
|
||||
# Unset destructor for capsules that are repeated
|
||||
_capsule.setDestructor(cap, None)
|
||||
return obj
|
||||
|
||||
|
||||
def unwrap(obj):
|
||||
'''Unwrap a Wrapper instance into the underlying PyCapsule.
|
||||
If `obj` is not a Wrapper instance, returns `obj`.
|
||||
'''
|
||||
if isinstance(obj, Wrapper):
|
||||
return obj._ptr
|
||||
else:
|
||||
return obj
|
||||
|
||||
|
||||
def register_class(cls):
|
||||
clsname = cls.__name__
|
||||
_pyclasses['llvm::%s' % clsname] = cls
|
||||
return cls
|
||||
|
||||
|
||||
class Wrapper(object):
|
||||
|
||||
__slots__ = '__ptr'
|
||||
|
||||
def __init__(self, ptr):
|
||||
_sentry(ptr)
|
||||
self.__ptr = ptr
|
||||
|
||||
@property
|
||||
def _ptr(self):
|
||||
return self.__ptr
|
||||
|
||||
def _release_ownership(self):
|
||||
_capsule.setDestructor(self._ptr, None)
|
||||
|
||||
|
||||
|
||||
73
newbinding/include/llvm_binding/binding.h
Normal file
73
newbinding/include/llvm_binding/binding.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#include <Python.h>
|
||||
#include <cstring>
|
||||
|
||||
#if (PY_MAJOR_VERSION >= 3)
|
||||
|
||||
static
|
||||
PyObject*
|
||||
create_python_module(const char *name, PyMethodDef* methtable){
|
||||
PyModuleDef module_def_tmp = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
name,
|
||||
NULL,
|
||||
-1,
|
||||
methtable,
|
||||
NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
PyModuleDef* module_def = new PyModuleDef(module_def_tmp); // will leak??
|
||||
PyObject* module = PyModule_Create(module_def);
|
||||
if (module == NULL){
|
||||
delete module_def;
|
||||
return NULL;
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static
|
||||
PyObject*
|
||||
create_python_module(const char *name, PyMethodDef* methtable){
|
||||
PyObject* module = Py_InitModule(name, methtable);
|
||||
if (module == NULL) return NULL;
|
||||
return module;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static
|
||||
PyObject*
|
||||
create_python_submodule(PyObject* parent, const char* name,
|
||||
PyMethodDef* methtable)
|
||||
{
|
||||
const char* parentname = PyModule_GetName(parent);
|
||||
const unsigned len_parent = strlen(parentname);
|
||||
const unsigned len_sub = strlen(name);
|
||||
const unsigned len = len_parent + 1 + len_sub;
|
||||
char* fullname = new char[len + 1];
|
||||
strcpy(fullname, parentname);
|
||||
fullname[len_parent] = '.';
|
||||
strcpy(fullname + len_parent + 1, name);
|
||||
PyObject* submod = create_python_module(fullname, methtable);
|
||||
delete [] fullname;
|
||||
if (!submod)
|
||||
return NULL;
|
||||
if( -1 == PyModule_AddObject(parent, name, submod) )
|
||||
return NULL;
|
||||
return submod;
|
||||
}
|
||||
|
||||
struct SubModuleEntry{
|
||||
const char* name;
|
||||
PyMethodDef* methtable;
|
||||
};
|
||||
|
||||
static
|
||||
int populate_submodules(PyObject* parent, SubModuleEntry* entries){
|
||||
for(SubModuleEntry* iter = entries; iter->name; ++iter){
|
||||
if (!create_python_submodule(parent, iter->name, iter->methtable))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
48
newbinding/include/llvm_binding/capsule_context.h
Normal file
48
newbinding/include/llvm_binding/capsule_context.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef LLVMPY_CAPSULE_CONTEXT_H_
|
||||
#define LLVMPY_CAPSULE_CONTEXT_H_
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
|
||||
typedef PyObject* Destructor_Fn;
|
||||
|
||||
static bool CapsuleContextDebug = false;
|
||||
|
||||
struct CapsuleContext {
|
||||
const char* className;
|
||||
Destructor_Fn destructor;
|
||||
|
||||
CapsuleContext(const char* cn, Destructor_Fn dtor=NULL)
|
||||
: className(cn), destructor(dtor) { }
|
||||
};
|
||||
|
||||
void capsule_destructor(PyObject* capsule){
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
CapsuleContext* context = (CapsuleContext*)PyCapsule_GetContext(capsule);
|
||||
if (context->destructor) {
|
||||
if (CapsuleContextDebug) {
|
||||
cerr << clock()
|
||||
<< " == DEBUG =="
|
||||
<< " destroy pointer: "
|
||||
<< context->className
|
||||
<< endl;
|
||||
}
|
||||
PyObject_CallMethodObjArgs(context->destructor, capsule, NULL);
|
||||
} else {
|
||||
if (CapsuleContextDebug) {
|
||||
cerr << clock()
|
||||
<< " == DEBUG =="
|
||||
<< " keep pointer alive: "
|
||||
<< context->className
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
delete context;
|
||||
}
|
||||
|
||||
void enable_capsule_dtor_debug(bool enabled){
|
||||
CapsuleContextDebug = enabled;
|
||||
}
|
||||
|
||||
#endif //LLVMPY_CAPSULE_CONTEXT_H_
|
||||
|
||||
93
newbinding/include/llvm_binding/conversion.h
Normal file
93
newbinding/include/llvm_binding/conversion.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
#include <Python.h>
|
||||
#include <llvm/Support/Casting.h>
|
||||
#include <llvm/ADT/StringRef.h>
|
||||
|
||||
// python object unwrapper
|
||||
|
||||
static
|
||||
int py_str_to(PyObject *strobj, llvm::StringRef &strref){
|
||||
// type check
|
||||
if (!PyString_Check(strobj)) {
|
||||
// raises TypeError
|
||||
PyErr_SetString(PyExc_TypeError, "Expecting a str");
|
||||
return 0;
|
||||
}
|
||||
// get len and buffer
|
||||
const Py_ssize_t len = PyString_Size(strobj);
|
||||
const char * buf = PyString_AsString(strobj);
|
||||
if (!buf) {
|
||||
// raises TypeError
|
||||
return 0;
|
||||
}
|
||||
// set output
|
||||
strref = llvm::StringRef(buf, len);
|
||||
// success
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
int py_int_to(PyObject *intobj, unsigned & val){
|
||||
if (!PyInt_Check(intobj)) {
|
||||
// raise TypeError
|
||||
PyErr_SetString(PyExc_TypeError, "Expecting an int");
|
||||
return 0;
|
||||
}
|
||||
val = PyInt_AsUnsignedLongMask(intobj);
|
||||
// success
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
int py_bool_to(PyObject *boolobj, bool & val){
|
||||
if (!PyBool_Check(boolobj)) {
|
||||
// raise TypeError
|
||||
PyErr_SetString(PyExc_TypeError, "Expecting a bool");
|
||||
return 0;
|
||||
}
|
||||
if (boolobj == Py_True) {
|
||||
val = true;
|
||||
} else if (boolobj == Py_False) {
|
||||
val = false;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError, "Invalid boolean object");
|
||||
return 0;
|
||||
}
|
||||
// success
|
||||
return 1;
|
||||
}
|
||||
|
||||
// python object wrapper
|
||||
|
||||
static
|
||||
PyObject* py_str_from(const std::string &str){
|
||||
return PyString_FromStringAndSize(str.c_str(), str.size());
|
||||
}
|
||||
|
||||
static
|
||||
PyObject* py_bool_from(bool val){
|
||||
if (val) {
|
||||
Py_RETURN_TRUE;
|
||||
} else {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
PyObject* py_int_from(int val){
|
||||
return PyInt_FromLong(val);
|
||||
}
|
||||
|
||||
// casting
|
||||
template<class Td>
|
||||
struct typecast {
|
||||
template<class Ts> static
|
||||
Td* from(Ts* src) {
|
||||
return llvm::dyn_cast<Td>(src);
|
||||
}
|
||||
|
||||
static
|
||||
Td* from(void* src) {
|
||||
return static_cast<Td*>(src);
|
||||
}
|
||||
};
|
||||
|
||||
34
newbinding/include/llvm_binding/extra.h
Normal file
34
newbinding/include/llvm_binding/extra.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#include <Python.h>
|
||||
#include <llvm/ADT/SmallVector.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
|
||||
namespace llvm{
|
||||
|
||||
class raw_svector_ostream_helper: public raw_svector_ostream {
|
||||
SmallVectorImpl<char> *SV;
|
||||
public:
|
||||
static
|
||||
raw_svector_ostream_helper* create(){
|
||||
SmallVectorImpl<char>* sv = new SmallVector<char, 16>();
|
||||
return new raw_svector_ostream_helper(sv);
|
||||
}
|
||||
|
||||
~raw_svector_ostream_helper(){
|
||||
delete SV;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
explicit
|
||||
raw_svector_ostream_helper(SmallVectorImpl<char>* sv)
|
||||
: raw_svector_ostream(*sv), SV(sv) {}
|
||||
|
||||
private:
|
||||
// no copy
|
||||
raw_svector_ostream_helper(const raw_svector_ostream_helper&);
|
||||
// no assign
|
||||
void operator = (const raw_svector_ostream_helper&);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
54
newbinding/setup.py
Normal file
54
newbinding/setup.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import sys, os
|
||||
from distutils.core import setup, Extension
|
||||
|
||||
llvm_config = os.environ.get('LLVM_CONFIG_PATH')
|
||||
|
||||
def run_llvm_config(args):
|
||||
cmd = llvm_config + ' ' + ' '.join(args)
|
||||
return os.popen(cmd).read().rstrip()
|
||||
|
||||
def get_libs_and_objs(components):
|
||||
parts = run_llvm_config(['--libs'] + components).split()
|
||||
libs = []
|
||||
objs = []
|
||||
for part in parts:
|
||||
if part.startswith('-l'):
|
||||
libs.append(part[2:])
|
||||
elif part.endswith('.o'):
|
||||
objs.append(part)
|
||||
return libs, objs
|
||||
|
||||
incdir = run_llvm_config(['--includedir'])
|
||||
libdir = run_llvm_config(['--libdir'])
|
||||
ldflags = run_llvm_config(['--ldflags'])
|
||||
macros = [('__STDC_CONSTANT_MACROS', None),
|
||||
('__STDC_LIMIT_MACROS', None)]
|
||||
|
||||
extra_link_args = ldflags.split()
|
||||
|
||||
libs_core, objs_core = get_libs_and_objs(['core', 'analysis', 'scalaropts',
|
||||
'executionengine', 'jit', 'native',
|
||||
'interpreter', 'bitreader',
|
||||
'bitwriter', 'instrumentation', 'ipa',
|
||||
'ipo', 'transformutils', 'asmparser',
|
||||
'linker', 'support', 'vectorize'])
|
||||
|
||||
ext_modules = [Extension(name='_api',
|
||||
sources=['api.cpp'],
|
||||
include_dirs = ['include', incdir],
|
||||
library_dirs = [libdir],
|
||||
libraries = libs_core,
|
||||
define_macros = macros,
|
||||
extra_objects = objs_core,
|
||||
extra_link_args = extra_link_args),
|
||||
Extension(name='_capsule',
|
||||
sources=['capsule.cpp'],
|
||||
include_dirs = ['include'],),
|
||||
]
|
||||
|
||||
|
||||
setup(name = 'llvmpy2',
|
||||
description = 'Python bindings for LLVM',
|
||||
author = 'Siu Kwan Lam',
|
||||
ext_modules = ext_modules,
|
||||
license = "BSD")
|
||||
32
newbinding/test.py
Normal file
32
newbinding/test.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import _api
|
||||
|
||||
context = _api.getGlobalContext()
|
||||
modname = "modname"
|
||||
module = _api.Module.new(modname, context)
|
||||
assert modname == _api.Module.getModuleIdentifier(module)
|
||||
modname2 = "newmodname"
|
||||
_api.Module.setModuleIdentifier(module, modname2)
|
||||
assert modname2 == _api.Module.getModuleIdentifier(module)
|
||||
|
||||
_api.Module.dump(module)
|
||||
|
||||
_api.Module.delete(module)
|
||||
|
||||
voidty = _api.Type.getVoidTy(context)
|
||||
assert _api.Type.isVoidTy(voidty)
|
||||
assert not _api.Type.isLabelTy(voidty)
|
||||
|
||||
int21ty = _api.Type.getIntNTy(context, 21)
|
||||
assert _api.Type.isIntegerTy(int21ty)
|
||||
assert _api.Type.isIntegerTy(int21ty, 21)
|
||||
_api.Type.dump(int21ty)
|
||||
|
||||
halfty = _api.Type.getHalfTy(context)
|
||||
assert _api.Type.isHalfTy(halfty)
|
||||
_api.Type.dump(halfty)
|
||||
|
||||
fnty = _api.FunctionType.get(halfty, False)
|
||||
_api.Type.dump(fnty)
|
||||
|
||||
|
||||
|
||||
20
newbinding/test2.py
Normal file
20
newbinding/test2.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import api
|
||||
#api.enable_capsule_dtor_debug(True)
|
||||
context = api.getGlobalContext()
|
||||
|
||||
m = api.Module.new("modname", context)
|
||||
print m.getModuleIdentifier()
|
||||
m.setModuleIdentifier('modname2')
|
||||
print m.getModuleIdentifier()
|
||||
m.dump()
|
||||
os = api.raw_svector_ostream_helper.create()
|
||||
m.print_(os, None)
|
||||
print os.str()
|
||||
|
||||
int1ty = api.Type.getInt1Ty(context)
|
||||
int1ty.dump()
|
||||
|
||||
print int1ty.isIntegerTy(1)
|
||||
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue