diff --git a/newbinding/Makefile b/newbinding/Makefile index 61227e5..735d4ff 100644 --- a/newbinding/Makefile +++ b/newbinding/Makefile @@ -1,17 +1,12 @@ PYTHON = python -PYMODS = raw_ostream SmallVector Type DerivedTypes StringRef - -PYMODS += LLVMContext AssemblyAnnotationWriter Module -PYMODS += Value User Constant - all: _api.so _capsule.so _api.so _capsule.so: api.cpp capsule.cpp $(PYTHON) setup.py build_ext --inplace -api.cpp api.py: src/*.py include/llvm_binding/*.h - $(PYTHON) gen.py api src $(PYMODS) +api.cpp api.py: src/*.py include/llvm_binding/*.h gen.py binding.py + $(PYTHON) gen.py api src clean: cleantemp rm -f _api.so _capsule.so diff --git a/newbinding/binding.py b/newbinding/binding.py index c9de593..fc26d92 100644 --- a/newbinding/binding.py +++ b/newbinding/binding.py @@ -1,108 +1,352 @@ -import logging -import re -from utils import * +import functools +import codegen as cg -logger = logging.getLogger(__name__) +_rank = 0 +namespaces = {} -_py2capi_fmtmap = { - str: 's#', -} +class Namespace(object): + def __init__(self, name): + self.name = name + self.classes = [] + self.functions = [] + namespaces[name] = self -NULL = 'NULL' + def Class(self, *bases): + cls = Class(self, *bases) + self.classes.append(cls) + return cls -_symbols = set() + def Function(self, *args): + fn = Function(self, *args) + self.functions.append(fn) + return fn -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 + @property + def fullname(self): + return self.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) + def __str__(self): + return self.name - items = [var, '"%s"' % (''.join(typecodes))] + holders - println('if(!PyArg_ParseTuple(%s)) return NULL;' % ', '.join(items)) +class Type(object): + pass - # unwrap - unwrapped = [] - for arg, val in zip(args, argvals): - unwrapped.append(arg.unwrap(println, val)) +class BuiltinTypes(Type): + def __init__(self, name): + self.name = name - return unwrapped + @property + def fullname(self): + return self.name -_re_mangle_pattern = re.compile(r'[ _<>\*&]') + def wrap(self, writer, var): + return var -def mangle(name): - def repl(m): - s = m.group(0) - if s in '<>*&': - return '' - elif s in ' ': - return '_' - elif s in '_': - return '__' +Void = BuiltinTypes('void') +Unsigned = BuiltinTypes('unsigned') +Bool = BuiltinTypes('bool') +ConstStdString = BuiltinTypes('const std::string') + +class Class(Type): + format = 'O' + + def __init__(self, ns, *bases): + self.ns = ns + self.bases = bases + self._is_defined = False + self.methods = [] + self.enums = [] + self.includes = set() + + def __call__(self, defn): + assert not self._is_defined + self.name = defn.__name__ + for k, v in defn.__dict__.items(): + if isinstance(v, Method): + self.methods.append(v) + if isinstance(v, Constructor): + for sig in v.signatures: + sig[0] = ptr(self) + v.name = k + v.parent = self + elif isinstance(v, Enum): + self.enums.append(v) + v.name = k + v.parent = self + elif k == '_include_': + if isinstance(v, str): + self.includes.add(v) + else: + for i in v: + self.includes.add(i) + return self + + def compile_cpp(self, writer): + # generate methods + for meth in self.methods: + meth.compile_cpp(writer) + + # generate method table + writer.println('static') + writer.println('PyMethodDef %s[] = {' % cg.mangle(self.fullname)) + with writer.indent(): + fmt = '{ "%(name)s", (PyCFunction)%(func)s, METH_VARARGS, NULL },' + for meth in self.methods: + name = meth.name + func = cg.mangle(meth.fullname) + writer.println(fmt % locals()) + writer.println('{ NULL },') + writer.println('};') + writer.println() + + def compile_py(self, writer): + clsname = self.name + bases = 'capsule.Wrapper' + if self.bases: + bases = ', '.join(x.name for x in self.bases) + writer.println('@capsule.register_class') + with writer.block('class %(clsname)s(%(bases)s):' % locals()): + for enum in self.enums: + enum.compile_py(writer) + for meth in self.methods: + meth.compile_py(writer) + if not self.enums and not self.methods: + writer.println('pass') + writer.println() + + @property + def capsule_name(self): + if self.bases: + return self.bases[-1].capsule_name else: - assert False - name = _re_mangle_pattern.sub(repl, name) - return name.replace('::', '_') + return self.fullname -def pycapsule_new(println, ptr, name, clsname): - # build capsule - name_soften = mangle(name) - var = new_symbol('pycap_%s' % name_soften) - fmt = 'PyObject* %(var)s = pycapsule_new(%(ptr)s, "%(name)s", "%(clsname)s");' - println(fmt % locals()) - println('if (!%(var)s) return NULL;' % locals()) - return var + @property + def fullname(self): + try: + name = self.realname + except AttributeError: + name = self.name + return '::'.join([self.ns.fullname, name]) + + def __str__(self): + return self.fullname + + def unwrap(self, writer, val): + fmt = 'PyCapsule_GetPointer(%(val)s, "%(name)s")' + name = self.capsule_name + raw = writer.declare('void*', fmt % locals()) + writer.die_if_false(raw) + ptrty = ptr(self).fullname + ty = self.fullname + fmt = 'typecast<%(ty)s>::from(%(raw)s)' + casted = writer.declare(ptrty, fmt % locals()) + writer.die_if_false(casted) + return casted -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 +class Enum(object): + def __init__(self, *value_names): + self.parent = None + self.value_names = value_names + + @property + def fullname(self): + try: + name = self.realname + except AttributeError: + name = self.name + return '::'.join([self.parent.fullname, name]) + + def __str__(self): + return self.fullname + + def wrap(self, writer, val): + ret = writer.declare('PyObject*', 'NULL') + with writer.block('switch(%s) ' % val): + for v in self.value_names: + writer.println('case %s::%s:' % (self.parent, v)) + with writer.indent(): + fmt = '%(ret)s = PyString_FromString("%(v)s");' + writer.println(fmt % locals()) + writer.println('break;') + else: + writer.println('default:') + with writer.indent(): + writer.raises(ValueError, 'Invalid enum %s' % v) + return ret + + def compile_py(self, writer): + with writer.block('class %s:' % self.name): + for v in self.value_names: + writer.println('%(v)s = "%(v)s"' % locals()) + writer.println() + +class Method(object): + _kind_ = 'meth' + + def __init__(self, return_type=Void, *args): + self.parent = None + self.signatures = [] + self.includes = set() + self._add_signature(return_type, *args) + + def _add_signature(self, return_type, *args): + prev_lens = set(map(len, self.signatures)) + cur_len = len(args) + 1 + if cur_len in prev_lens: + raise Exception('Only support overloading with different number' + ' of arguments') + self.signatures.append([return_type] + list(args)) + + def __ior__(self, method): + assert type(self) is type(method) + for sig in method.signatures: + self._add_signature(sig[0], *sig[1:]) + return self + + @property + def fullname(self): + return '::'.join([self.parent.fullname, self.realname]) + + @property + def realname(self): + try: + return self.__realname + except AttributeError: + return self.name + + @realname.setter + def realname(self, v): + self.__realname = v + + def __str__(self): + return self.fullname + + def compile_cpp(self, writer): + with writer.py_function(self.fullname): + if len(self.signatures) == 1: + sig = self.signatures[0] + retty = sig[0] + argtys = sig[1:] + self.compile_cpp_body(writer, retty, argtys) + else: + nargs = writer.declare('Py_ssize_t', 'PyTuple_Size(args)') + for sig in self.signatures: + retty = sig[0] + argtys = sig[1:] + expect = len(argtys) + if (not isinstance(self, StaticMethod) and + isinstance(self.parent, Class)): + # Is a instance method, add 1 for "this". + expect += 1 + with writer.block('if (%(expect)d == %(nargs)s)' % locals()): + self.compile_cpp_body(writer, retty, argtys) + writer.raises(TypeError, 'Invalid number of args') + + def compile_cpp_body(self, writer, retty, argtys): + if isinstance(self.parent, Class): + args = writer.parse_arguments('args', ptr(self.parent), *argtys) + ret = writer.method_call(self.realname, retty.fullname, *args) + else: + args = writer.parse_arguments('args', *argtys) + ret = writer.call(self.fullname, retty.fullname, *args) + writer.return_value(retty.wrap(writer, ret)) + + def compile_py(self, writer): + decl = writer.function(self.name, args=('self',), varargs='args') + with decl as (this, varargs): + unwrap_this = writer.unwrap(this) + unwrapped = writer.unwrap_many(varargs) + func = '.'.join([self.parent.name, self.name]) + ret = writer.call('_api.%s' % func, + args=(unwrap_this,), varargs=unwrapped) + wrapped = writer.wrap(ret) + writer.return_value(wrapped) + writer.println() -def return_value(println, var): - println('return %(var)s;' % locals()) +class StaticMethod(Method): + + def compile_cpp_body(self, writer, retty, argtys): + assert isinstance(self.parent, Class) + args = writer.parse_arguments('args', *argtys) + ret = self.compile_cpp_call(writer, retty, args) + writer.return_value(retty.wrap(writer, ret)) + + def compile_cpp_call(self, writer, retty, args): + ret = writer.call(self.fullname, retty.fullname, *args) + return ret + + def compile_py(self, writer): + writer.println('@staticmethod') + decl = writer.function(self.name, varargs='args') + with decl as varargs: + unwrapped = writer.unwrap_many(varargs) + func = '.'.join([self.parent.name, self.name]) + ret = writer.call('_api.%s' % func, varargs=unwrapped) + wrapped = writer.wrap(ret) + writer.return_value(wrapped) + writer.println() -def return_none(println): - println('Py_RETURN_NONE;') +class Function(Method): + _kind_ = 'func' + + def __init__(self, parent, name, return_type=Void, *args): + super(Function, self).__init__(return_type, *args) + self.parent = parent + self.name = name + + def compile_py(self, writer): + with writer.function(self.name, varargs='args') as varargs: + unwrapped = writer.unwrap_many(varargs) + func = self.fullname.split('::', 1)[1].replace('::', '.') + ret = writer.call('_api.%s' % func, + varargs=unwrapped) + wrapped = writer.wrap(ret) + writer.return_value(wrapped) + writer.println() -def die_if_null(println, var): - println('if (!%(var)s) return NULL;' % locals()) +class Destructor(Method): + _kind_ = 'dtor' - -class Binding(object): - __rank_global = 0 def __init__(self): - self.rank = Binding.__rank_global - Binding.__rank_global += 1 - self.include = set() + super(Destructor, self).__init__() - def compile(self, name, println): - raise NotImplementedError(type(self)) + def compile_cpp_body(self, writer, retty, argtys): + assert isinstance(self.parent, Class) + assert not argtys + args = writer.parse_arguments('args', ptr(self.parent), *argtys) + writer.println('delete %s;' % args[0]) + writer.return_value(None) -class Ref(object): - def __init__(self, elem): - self.element = elem + def compile_py(self, writer): + func = '.'.join([self.parent.name, self.name]) + writer.println('_delete_ = _api.%s' % func) + + +class Constructor(StaticMethod): + _kind_ = 'ctor' + + def __init__(self, *args): + super(Constructor, self).__init__(Void, *args) + + def compile_cpp_call(self, writer, retty, args): + alloctype = retty.fullname.rstrip(' *') + arglist = ', '.join(args) + stmt = 'new %(alloctype)s(%(arglist)s)' % locals() + ret = writer.declare(retty.fullname, stmt) + return ret + +class ref(Type): + def __init__(self, element): + assert isinstance(element, Class), type(element) + self.element = element + + def __str__(self): + return self.fullname @property def fullname(self): @@ -112,503 +356,79 @@ class Ref(object): 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' + return self.element.format - def unwrap(self, println, var): - ptr = self.element.unwrap(println, var) - return declare(println, self.fullname, '*%s' % ptr) + def wrap(self, writer, val): + p = writer.declare(ptr(self.element).fullname, '&%s' % val) + return writer.pycapsule_new(p, self.capsule_name, self.element.fullname) - def wrap(self, println, var): - return self.element.wrap(println, self.as_pointer(println, var)) + def unwrap(self, writer, val): + p = self.element.unwrap(writer, val) + return writer.declare(self.fullname, '*%s' % p) -class Pointer(object): - def __init__(self, elem): - self.element = elem +class ptr(Type): + def __init__(self, element): + assert isinstance(element, Class) + self.element = element @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 + return '%s*' % self.element @property def format(self): - return 'O' + return self.element.format - 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('}') + def unwrap(self, writer, val): + ret = writer.declare(self.fullname, 'NULL') + with writer.block('if (%(val)s != Py_None)' % locals()): + val = self.element.unwrap(writer, val) + writer.println('%(ret)s = %(val)s;' % locals()) return ret - def wrap(self, println, var): - return self.element.wrap(println, var) + def wrap(self, writer, val): + return writer.pycapsule_new(val, self.element.capsule_name, + self.element.fullname) - -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 PyObjectImpl(object): - name = 'PyObject*' - fullname = name +class cast(Type): format = 'O' - def unwrap(self, println, var): - return var - -PyObject = PyObjectImpl() - -class Unwrapper(object): - def __init__(self, cls, pytype): - self.cls = cls - self.pytype = pytype + def __init__(self, original, target): + self.original = original + self.target = target @property def fullname(self): - return str(self.pytype) + return self.binding_type.fullname @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 Enum(Binding): - def __init__(self, ns, *values): - super(Enum, self).__init__() - self.values = values - self.ns = ns - self.name = None - - def compile(self, name, println): - self.name = self.name or name - - @property - def fullname(self): - return '::'.join([self.ns, self.name]) - -class ClassEnum(Enum): - def __init__(self, cls, *values): - super(ClassEnum, self).__init__(None, *values) - self.cls = cls - self.cls.enums.append(self) - - def compile(self, name, println): - self.ns = self.cls.fullname - super(ClassEnum, self).compile(name, println) - - def wrap(self, println, var): - println2 = indent_println(println) - ret = declare(println, 'PyObject*', NULL) - println('switch(%s) { ' % var) - for v in self.values: - println('case %s::%s:' % (self.ns, v)) - println2('%(ret)s = PyString_FromString("%(v)s");' % locals()) - println2('break;') + def python_type(self): + if not isinstance(self.target, Type): + return self.target else: - println('default:') - println2('PyErr_SetString(PyExc_TypeError, "Invalid enum: %s");' % - v) - println2('return NULL;') - println('}') + return self.original + + @property + def binding_type(self): + if isinstance(self.target, Type): + return self.target + else: + return self.original + + def wrap(self, writer, val): + dst = self.python_type.__name__ + return writer.call('py_%(dst)s_from' % locals(), 'PyObject*', val) + + def unwrap(self, writer, val): + src = self.python_type.__name__ + dst = self.binding_type.fullname + ret = writer.declare(dst) + status = writer.call('py_%(src)s_to' % locals(), 'int', val, ret) + writer.die_if_false(status) return ret - def unwrap(self, println, var): - pass -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.Enum = lambda *v: ClassEnum(self, *v) - self.enums = [] - 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 staticmultimethod(self, *signatures): - smm = StaticMultiMethod(self, signatures) - self.methods.append(smm) - return smm - - 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 StaticMultiMethod(Binding): - '''Can only differs by the number of arguments. - ''' - def __init__(self, cls, signatures): - super(StaticMultiMethod, self).__init__() - nargs = set() - for sig in signatures: - n = len(sig) - if n in nargs: - raise TypeError("StaticMultiMethod 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) - 1 - println2('if (%(nargs)s == %(expect)d) {' % locals()) - method = StaticMethod(self.cls, sig[0], *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 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) - diff --git a/newbinding/codegen.py b/newbinding/codegen.py new file mode 100644 index 0000000..9398b14 --- /dev/null +++ b/newbinding/codegen.py @@ -0,0 +1,279 @@ +import re, contextlib + +NULL = 'NULL' + +_symbols = set() + +def indent(println): + def _println(s=''): + println("%s%s" % (' '* 4, s)) + return _println + +def quote(txt): + return '"%s"' % txt + +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 + +_re_mangle_pattern = re.compile(r'[ _<>\*&]') + +def mangle(name): + def repl(m): + s = m.group(0) + if s in '<>*&': + return '' + elif s in ' ': + return '_' + elif s in '_': + return '__' + else: + assert False + name = _re_mangle_pattern.sub(repl, name) + return name.replace('::', '_') + +def pycapsule_new(println, ptr, name, clsname): + # build capsule + name_soften = mangle(name) + var = new_symbol('pycap_%s' % name_soften) + fmt = 'PyObject* %(var)s = pycapsule_new(%(ptr)s, "%(name)s", "%(clsname)s");' + println(fmt % locals()) + println('if (!%(var)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 CodeWriterBase(object): + def __init__(self, println): + self.println = println + self.used_symbols = set() + + @contextlib.contextmanager + def indent(self): + old = self.println + self.println = indent(self.println) + yield + self.println = old + + @contextlib.contextmanager + def py_function(self, name): + mangled = mangle(name) + self.println('static') + self.println('PyObject*') + with self.block('%(mangled)s(PyObject* self, PyObject* args)' % locals()): + self.used_symbols.add('self') + self.used_symbols.add('args') + yield + self.println() + + def new_symbol(self, name): + if name in self.used_symbols: + ct = 1 + orig = name + while name in self.used_symbols: + name = '%s%d' % (orig, ct) + ct += 1 + self.used_symbols.add(name) + return name + +class CppCodeWriter(CodeWriterBase): + @contextlib.contextmanager + def block(self, lead): + self.println(lead) + self.println('{') + with self.indent(): + yield + self.println('}') + + def declare(self, typ, init=None): + typ_soften = mangle(typ) + var = self.new_symbol('var_%s' % typ_soften) + if init is None: + self.println('%(typ)s %(var)s;' % locals()) + else: + self.println('%(typ)s %(var)s = %(init)s;' % locals()) + return var + + def return_value(self, val): + if val is None: + self.println('Py_RETURN_NONE;') + else: + self.println('return %s;' % val) + + def return_null(self): + self.return_value(NULL) + + def parse_arguments(self, var, *args): + typecodes = [] + holders = [] + argvals = [] + for arg in args: + typecodes.append(arg.format) + val = self.declare('PyObject*') + argvals.append(val) + holders.append('&' + val) + + items = [var, '"%s"' % (''.join(typecodes))] + holders + with self.block('if(!PyArg_ParseTuple(%s))' % ', '.join(items)): + self.return_null() + + # unwrap + unwrapped = [] + for arg, val in zip(args, argvals): + unwrapped.append(arg.unwrap(self, val)) + + return unwrapped + + def call(self, func, retty, *args): + arglist = ', '.join(args) + stmt = '%(func)s(%(arglist)s)' % locals() + if retty == 'void': + self.println(stmt) + else: + return self.declare(retty, stmt) + + def method_call(self, func, retty, *args): + this = args[0] + arglist = ', '.join(args[1:]) + if func == 'delete': + assert not arglist + stmt = 'delete %(this)s;' % locals() + elif func == 'new': + alloctype = retty.rstrip(' *') + stmt = 'new %(alloctype)s(%(arglist)s);' % locals() + else: + stmt = '%(this)s->%(func)s(%(arglist)s);' % locals() + if retty == 'void': + self.println(stmt) + else: + return self.declare(retty, stmt) + + def pycapsule_new(self, ptr, name, clsname): + name_soften = mangle(name) + ret = self.call('pycapsule_new', 'PyObject*', ptr, quote(name), + quote(clsname)) + with self.block('if (!%(ret)s)' % locals()): + self.return_null() + return ret + + def die_if_false(self, val): + with self.block('if(!%(val)s)' % locals()): + self.return_null() + + def raises(self, exccls, msg): + exc = 'PyExc_%s' % exccls.__name__ + self.println('PyErr_SetString(%s, "%s");' % (exc, msg)) + self.return_null() + + +class PyCodeWriter(CodeWriterBase): + @contextlib.contextmanager + def block(self, lead): + self.println(lead) + with self.indent(): + yield + + @contextlib.contextmanager + def function(self, func, args=(), varargs=None): + with self.scope(): + arguments = [] + for arg in args: + arguments.append(self.new_symbol(arg)) + if varargs: + varargs = self.new_symbol(varargs) + arguments.append('*%s' % varargs) + arglist = ', '.join(arguments) + with self.block('def %(func)s(%(arglist)s):' % locals()): + if arguments: + arguments[-1] = arguments[-1].lstrip('*') + if len(arguments) > 1: + yield arguments + else: + yield arguments[0] + else: + yield + + @contextlib.contextmanager + def scope(self): + self.old = self.used_symbols + self.used_symbols = set() + yield + self.used_symbols = self.old + + def unwrap_many(self, args): + unwrapped = self.new_symbol('unwrapped') + self.println('%(unwrapped)s = map(capsule.unwrap, %(args)s)' % locals()) + return unwrapped + + def unwrap(self, val): + return self.call('capsule.unwrap', args=(val,), ret='unwrapped') + + def wrap(self, val): + wrapped = self.new_symbol('wrapped') + self.println('%(wrapped)s = capsule.wrap(%(val)s)' % locals()) + return wrapped + + def call(self, func, args=(), varargs=None, ret='ret'): + arguments = [] + for arg in args: + arguments.append(arg) + if varargs: + arguments.append('*%s' % varargs) + arglist = ', '.join(arguments) + ret = self.new_symbol(ret) + self.println('%(ret)s = %(func)s(%(arglist)s)' % locals()) + return ret + + def return_value(self, val=None): + if val is None: + val = '' + self.println('return %s' % val) + + diff --git a/newbinding/extra.py b/newbinding/extra.py new file mode 100644 index 0000000..1af4e5f --- /dev/null +++ b/newbinding/extra.py @@ -0,0 +1,20 @@ +''' +Wrapped the extra functions in _api.so +''' + +import capsule + +def _wrapper(func): + def _core(*args): + unwrapped = map(capsule.unwrap, args) + ret = func(*unwrapped) + return capsule.wrap(ret) + return _core + +def _init(glob): + from _api import extra + for k, v in extra.__dict__.items(): + glob[k] = _wrapper(v) + +_init(globals()) + diff --git a/newbinding/gen.py b/newbinding/gen.py index cee71f1..4d8709e 100644 --- a/newbinding/gen.py +++ b/newbinding/gen.py @@ -1,26 +1,23 @@ -import sys, logging +import sys from binding import * -from utils import * -from cStringIO import StringIO +import codegen -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) 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; +PyObject *module = create_python_module("%(module)s", %(methtable)s); +if (module) { +if (populate_submodules(module, submodules)) +return module; +} +return NULL; } #else @@ -28,10 +25,10 @@ PyInit_%(module)s(void) PyMODINIT_FUNC init%(module)s(void) { - PyObject *module = create_python_module("%(module)s", %(methtable)s); - if (module) { - populate_submodules(module, submodules); - } +PyObject *module = create_python_module("%(module)s", %(methtable)s); +if (module) { +populate_submodules(module, submodules); +} } #endif @@ -39,172 +36,6 @@ init%(module)s(void) ''' -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 = [] - self._pending_symbols = [] - - 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('{ "extra", extra_methodtable },') - println('{ NULL }') - println('};') - println('') - - # generate entry - println(extension_entry % {'module': '_api', - 'methtable': 'global_functions',}) - - def generate_py(self, println): - println('import _api, capsule') - println('') - # wraps all extras - extra_wrapper = ''' -def _init_extra_wrapper(): - def wrap(callee): - def _wrapped(*args): - args = map(capsule.unwrap, args) - ret = callee(*args) - return capsule.wrap(ret) - return _wrapped - for k in dir(_api.extra): - v = getattr(_api.extra, k) - if not k.startswith('__') and callable(v): - globals()[k] = wrap(v) -_init_extra_wrapper() - ''' - println(extra_wrapper) - 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 - # generate class enums - for enum in cls.enums: - println('class %s:' % enum.name) - println2 = indent_println(println) - for v in enum.values: - println2('%(v)s = "%(v)s"' % locals()) - println('') - # generate class methods - for method in cls.methods: - name = method.name - if(isinstance(method, StaticMethod) or - isinstance(method, StaticMultiMethod)): - 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, module): - allsyms = [(k, v) for k, v in vars(module).items() - if isinstance(v, Binding)] - # generate includes - for k, v in allsyms: - self.includes |= v.include - - self._pending_symbols.extend(allsyms) - - def materialize(self): - symtab = sorted(self._pending_symbols, key=lambda x: x[1].rank) - - # compile everything - for k, v in symtab: - buf = StringIO() - def println_to_def(s): - buf.write(s) - buf.write('\n') - logger.info('compiling %s', k) - 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 = [ @@ -216,38 +47,96 @@ def populate_headers(println): ] for inc in includes: println('#include "%s"' % inc) + println() -def wrap_println(f): - def println(s): - f.write(s) - f.write('\n') + +def wrap_println_from_file(file): + def println(s=''): + file.write(s) + file.write('\n') return println -if __name__ == '__main__': +def main(): outputfilename = sys.argv[1] - srcdir = sys.argv[2] - modnames = sys.argv[3:] + entry_modname = sys.argv[2] - modules = [] - for m in modnames: - path = '%s.%s' % (srcdir, m) - logger.info("import module %s", path) - module = __import__(path) - for token in path.split('.')[1:]: - module = getattr(module, token) - modules.append(module) + entry_module = __import__(entry_modname) - context = Context() + units = [] + for ns in namespaces.values(): + print 'namespace', ns + for fn in ns.functions: + print fn + units.append(fn) + for cls in ns.classes: + print cls + units.append(cls) - for mod in modules: - context.add_module(mod) - context.materialize() + with open('%s.cpp' % outputfilename, 'w') as cppfile: + println = wrap_println_from_file(cppfile) - with open('%s.cpp' % outputfilename, 'w') as outfile: - println = wrap_println(outfile) + # extra headers populate_headers(println) - context.generate_cpp(println) - with open('%s.py' % outputfilename, 'w') as outfile: - println = wrap_println(outfile) - context.generate_py(println) + # required headers + includes = set() + for u in units: + includes |= u.includes + + for inc in includes: + println('#include "%s"' % inc) + println() + + # write methods and method tables + for u in units: + writer = codegen.CppCodeWriter(println) + u.compile_cpp(writer) + else: + del writer + + # write function table + writer = codegen.CppCodeWriter(println) + writer.println('static') + writer.println('PyMethodDef methtable[] = {') + with writer.indent(): + fmt = '{ "%(name)s", (PyCFunction)%(func)s, METH_VARARGS, NULL },' + for u in units: + if isinstance(u, Function): + name = u.name + func = codegen.mangle(u.fullname) + writer.println(fmt % locals()) + writer.println('{ NULL },') + writer.println('};') + writer.println() + del writer + + + # write submodule table + writer = codegen.CppCodeWriter(println) + writer.println('static') + writer.println('SubModuleEntry submodules[] = {') + with writer.indent(): + for cls in units: + if isinstance(cls, Class): + name = cls.name + table = codegen.mangle(cls.fullname) + writer.println('{ "%(name)s", %(table)s },' % locals()) + writer.println('{ "extra", extra_methodtable },') + writer.println('{ NULL }') + writer.println('};') + writer.println('') + del writer + + println(extension_entry % {'module': '_api', 'methtable': 'methtable'}) + + with open('%s.py' % outputfilename, 'w') as pyfile: + println = wrap_println_from_file(pyfile) + println('import _api, capsule') + println() + for u in units: + writer = codegen.PyCodeWriter(println) + u.compile_py(writer) + + +if __name__ == '__main__': + main() diff --git a/newbinding/include/llvm_binding/auto_pyobject.h b/newbinding/include/llvm_binding/auto_pyobject.h new file mode 100644 index 0000000..451f2d9 --- /dev/null +++ b/newbinding/include/llvm_binding/auto_pyobject.h @@ -0,0 +1,38 @@ +#ifndef AUTO_PYOBJECT_H_ +#define AUTO_PYOBJECT_H_ + +#include + +class auto_pyobject{ + mutable PyObject* PO; +public: + auto_pyobject(): PO(NULL) { } + + auto_pyobject(PyObject* po) : PO(po) { } + + auto_pyobject(const auto_pyobject& other) : PO(*other){ + other.PO = NULL; + } + + ~auto_pyobject() { + Py_XDECREF(PO); + } + + bool operator ! () const { + return !PO; + } + + PyObject* operator * () const { + return PO; + } + + PyObject* get() const { + return PO; + } +private: + // disable assign + void operator = (const auto_pyobject&); +}; + +#endif AUTO_PYOBJECT_H_ + diff --git a/newbinding/include/llvm_binding/conversion.h b/newbinding/include/llvm_binding/conversion.h index c3d6e36..0e30c60 100644 --- a/newbinding/include/llvm_binding/conversion.h +++ b/newbinding/include/llvm_binding/conversion.h @@ -62,6 +62,11 @@ static PyObject* py_str_from(const std::string &str){ return PyString_FromStringAndSize(str.c_str(), str.size()); } +// +//static +//PyObject* py_str_from(const llvm::StringRef *str){ +// return py_str_from(str->str()); +//} static PyObject* py_bool_from(bool val){ diff --git a/newbinding/src/AssemblyAnnotationWriter.py b/newbinding/src/AssemblyAnnotationWriter.py index 5641232..d2b5a5d 100644 --- a/newbinding/src/AssemblyAnnotationWriter.py +++ b/newbinding/src/AssemblyAnnotationWriter.py @@ -1,6 +1,7 @@ from binding import * from namespace import llvm -AssemblyAnnotationWriter = llvm.Class() -AssemblyAnnotationWriter.include.add("llvm/Assembly/AssemblyAnnotationWriter.h") +@llvm.Class() +class AssemblyAnnotationWriter: + _include_ = "llvm/Assembly/AssemblyAnnotationWriter.h" diff --git a/newbinding/src/Constant.py b/newbinding/src/Constant.py index 24045bb..14ff6bb 100644 --- a/newbinding/src/Constant.py +++ b/newbinding/src/Constant.py @@ -2,4 +2,6 @@ from binding import * from namespace import llvm from User import User -Constant = User.Subclass() +@llvm.Class(User) +class Constant: + pass diff --git a/newbinding/src/DerivedTypes.py b/newbinding/src/DerivedTypes.py index d9dbb53..c57e01b 100644 --- a/newbinding/src/DerivedTypes.py +++ b/newbinding/src/DerivedTypes.py @@ -4,17 +4,15 @@ from LLVMContext import LLVMContext from Type import Type from SmallVector import SmallVector_Type -FunctionType = Type.Subclass() -FunctionType.include.add('llvm/DerivedTypes.h') +FunctionType = llvm.Class(Type) -_get_signatures = [(FunctionType.Pointer, - Type.Pointer, Bool.From(bool)), - (FunctionType.Pointer, - Type.Pointer, SmallVector_Type.Ref, Bool.From(bool))] +@FunctionType +class FunctionType: + _include_ = 'llvm/DerivedTypes.h' + get = StaticMethod(ptr(FunctionType), ptr(Type), cast(bool, Bool)) + get |= StaticMethod(ptr(FunctionType), ptr(Type), ref(SmallVector_Type), cast(bool, Bool)) + isVarArg = Method(cast(Bool, bool)) + getReturnType = Method(ptr(Type)) + getParamType = Method(ptr(Type), cast(int, Unsigned)) + getNumParams = Method(cast(Unsigned, int)) -get = FunctionType.staticmultimethod(*_get_signatures) - -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)) diff --git a/newbinding/src/LLVMContext.py b/newbinding/src/LLVMContext.py index 0965748..f2526db 100644 --- a/newbinding/src/LLVMContext.py +++ b/newbinding/src/LLVMContext.py @@ -1,8 +1,8 @@ from binding import * from namespace import llvm -LLVMContext = llvm.Class() -LLVMContext.include.add("llvm/LLVMContext.h") - -getGlobalContext = llvm.Function(LLVMContext.Ref) +@llvm.Class() +class LLVMContext: + _include_ = "llvm/LLVMContext.h" +llvm.Function('getGlobalContext', ref(LLVMContext)) diff --git a/newbinding/src/Module.py b/newbinding/src/Module.py index 67ac8b0..6a6a806 100644 --- a/newbinding/src/Module.py +++ b/newbinding/src/Module.py @@ -7,39 +7,39 @@ from DerivedTypes import FunctionType from raw_ostream import raw_ostream from AssemblyAnnotationWriter import AssemblyAnnotationWriter -# class Module -Module = llvm.Class() -Module.include.add("llvm/Module.h") +@llvm.Class() +class Module: + _include_ = "llvm/Module.h" + # Enumerators + Endianness = Enum('AnyEndianness', 'LittleEndian', 'BigEndian') + PointerSize = Enum('AnyPointerSize', 'Pointer32', 'Pointer64') -# Enumerators -Endianness = Module.Enum('AnyEndianness', 'LittleEndian', 'BigEndian') -PointerSize = Module.Enum('AnyPointerSize', 'Pointer32', 'Pointer64') + # Constructors & Destructors + new = Constructor(cast(str, StringRef), ref(LLVMContext)) + delete = Destructor() -# Constructors & Destructors -new = Module.new(StringRef.From(str), LLVMContext.Ref) -delete = Module.delete() + # Module Level Accessor + getModuleIdentifier = Method(cast(ConstStdString, str)) + getDataLayout = Method(cast(ConstStdString, str)) + getTargetTriple = Method(cast(ConstStdString, str)) + getEndianness = Method(Endianness) + getPointerSize = Method(PointerSize) + getContext = Method(ref(LLVMContext)) + getModuleInlineAsm = Method(cast(ConstStdString, str)) -# Module Level Accessor -getModuleIdentifier = Module.method(ConstStdString.To(str)) -getDataLayout = Module.method(ConstStdString.To(str)) -getTargetTriple = Module.method(ConstStdString.To(str)) -getEndianness = Module.method(Endianness) -getPointerSize = Module.method(PointerSize) -getContext = Module.method(LLVMContext.Ref) -getModuleInlineAsm = Module.method(ConstStdString.To(str)) + # Module Level Mutators + setModuleIdentifier = Method(Void, cast(str, StringRef)) + setDataLayout = Method(Void, cast(str, StringRef)) + setTargetTriple = Method(Void, cast(str, StringRef)) + setModuleInlineAsm = Method(Void, cast(str, StringRef)) + appendModuleInlineAsm = Method(Void, cast(str, StringRef)) -# Module Level Mutators -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)) + # Function Accessors + getOrInsertFunction = Method(ptr(Constant), cast(str, StringRef), ptr(FunctionType)) -# Function Accessors -getOrInsertFunction = Module.method(Constant.Pointer, StringRef.From(str), FunctionType.Pointer) + # Utilities + dump = Method(Void) + print_ = Method(Void, ref(raw_ostream), ptr(AssemblyAnnotationWriter)) + print_.realname = 'print' -# Utilities -dump = Module.method(Void) -print_ = Module.method(Void, raw_ostream.Ref, AssemblyAnnotationWriter.Pointer) -print_.realname = 'print' -dropAllReferences = Module.method(Void) + dropAllReferences = Method() diff --git a/newbinding/src/SmallVector.py b/newbinding/src/SmallVector.py index 225c720..d00b294 100644 --- a/newbinding/src/SmallVector.py +++ b/newbinding/src/SmallVector.py @@ -1,5 +1,6 @@ from binding import * from namespace import llvm -SmallVector_Type = llvm.Class() -delete = SmallVector_Type.delete() +@llvm.Class() +class SmallVector_Type: + delete = Destructor() diff --git a/newbinding/src/StringRef.py b/newbinding/src/StringRef.py index 554629b..fb3b896 100644 --- a/newbinding/src/StringRef.py +++ b/newbinding/src/StringRef.py @@ -1,6 +1,7 @@ from binding import * from namespace import llvm -StringRef = llvm.Class() -StringRef.include.add("llvm/ADT/StringRef.h") +@llvm.Class() +class StringRef: + _include_ = "llvm/ADT/StringRef.h" diff --git a/newbinding/src/Type.py b/newbinding/src/Type.py index 3703200..45f9444 100644 --- a/newbinding/src/Type.py +++ b/newbinding/src/Type.py @@ -4,93 +4,112 @@ from LLVMContext import LLVMContext from raw_ostream import raw_ostream Type = llvm.Class() -Type.include.add('llvm/Type.h') +IntegerType = llvm.Class(Type) +CompositeType = llvm.Class(Type) +SequentialType = llvm.Class(CompositeType) +PointerType = llvm.Class(SequentialType) -IntegerType = Type.Subclass() -CompositeType = Type.Subclass() -SequentialType = CompositeType.Subclass() -PointerType = SequentialType.Subclass() +@Type +class Type: + _include_ = 'llvm/Type.h' -getContext = Type.method(LLVMContext.Ref) -dump = Type.method(Void) -print_ = Type.method(Void, raw_ostream.Ref) -print_.realname = 'print' + getContext = Method(ref(LLVMContext)) + dump = Method() + print_ = Method(Void, ref(raw_ostream)) + print_.realname = 'print' -def type_checker(): - return Type.method(Bool.To(bool)) + def type_checker(): + return Method(cast(Bool, 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() + 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)]) + isIntegerTy = Method(cast(Bool, bool)) + isIntegerTy |= Method(cast(Bool, bool), cast(int, Unsigned)) -def type_factory(): - return Type.staticmethod(Type.Pointer, LLVMContext.Ref) + def type_factory(): + return StaticMethod(ptr(Type), ref(LLVMContext)) -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() + 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)) + getIntNTy = StaticMethod(ptr(IntegerType), ref(LLVMContext), cast(Unsigned, int)) -def integer_factory(): - return Type.staticmethod(IntegerType.Pointer, LLVMContext.Ref) + def integer_factory(): + return StaticMethod(ptr(IntegerType), ref(LLVMContext)) -getInt1Ty = integer_factory() -getInt8Ty = integer_factory() -getInt16Ty = integer_factory() -getInt32Ty = integer_factory() -getInt64Ty = integer_factory() + 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) + def pointer_factory(): + return StaticMethod(ptr(PointerType), ref(LLVMContext)) -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)) + 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 = StaticMethod(ptr(PointerType), + ref(LLVMContext), cast(int, Unsigned)) +@IntegerType +class IntegerType: + pass + + +@CompositeType +class CompositeType: + pass + +@SequentialType +class SequentialType: + pass + +@PointerType +class PointerType: + pass + diff --git a/newbinding/src/User.py b/newbinding/src/User.py index 8753983..dbc290d 100644 --- a/newbinding/src/User.py +++ b/newbinding/src/User.py @@ -2,4 +2,7 @@ from binding import * from namespace import llvm from Value import Value -User = Value.Subclass() +@llvm.Class(Value) +class User: + pass + diff --git a/newbinding/src/Value.py b/newbinding/src/Value.py index 062ad43..9d1a2dd 100644 --- a/newbinding/src/Value.py +++ b/newbinding/src/Value.py @@ -5,20 +5,23 @@ from AssemblyAnnotationWriter import AssemblyAnnotationWriter from Type import Type from LLVMContext import LLVMContext from StringRef import StringRef -# + Value = llvm.Class() -dump = Value.method(Void) +@Value +class Value: -print_ = Value.method(Void, raw_ostream.Ref, AssemblyAnnotationWriter.Pointer) -print_.realname = 'print' + dump = Method() -getType = Value.method(Type.Pointer) -getContext = Value.method(LLVMContext.Ref) + print_ = Method(Void, ref(raw_ostream), ptr(AssemblyAnnotationWriter)) + print_.realname = 'print' -hasName = Value.method(Bool.To(bool)) -# skip getValueName, setValueName -getName = Value.method(StringRef.To(str)) -setName = Value.method(Void, StringRef.From(str)) + getType = Method(ptr(Type)) + getContext = Method(ref(LLVMContext)) -replaceAllUsesWith = Value.method(Void, Value.Pointer) \ No newline at end of file + hasName = Method(cast(Bool, bool)) + # skip getValueName, setValueName + getName = Method(cast(StringRef, str)) + setName = Method(Void, cast(str, StringRef)) + + replaceAllUsesWith = Method(Void, ptr(Value)) \ No newline at end of file diff --git a/newbinding/src/__init__.py b/newbinding/src/__init__.py index e69de29..6e24918 100644 --- a/newbinding/src/__init__.py +++ b/newbinding/src/__init__.py @@ -0,0 +1,2 @@ +from . import Module + diff --git a/newbinding/src/namespace.py b/newbinding/src/namespace.py index 02af8c9..c50256d 100644 --- a/newbinding/src/namespace.py +++ b/newbinding/src/namespace.py @@ -1,4 +1,3 @@ from binding import * -extra = Namespace('llvm_extra') llvm = Namespace('llvm') diff --git a/newbinding/src/raw_ostream.py b/newbinding/src/raw_ostream.py index 64e8046..2f5a6f5 100644 --- a/newbinding/src/raw_ostream.py +++ b/newbinding/src/raw_ostream.py @@ -3,10 +3,15 @@ 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") -delete = raw_ostream.delete() +@llvm.Class() +class raw_ostream: + _include_ = "llvm/Support/raw_ostream.h" + delete = Destructor() + +@llvm.Class(raw_ostream) +class raw_svector_ostream: + _include_ = "llvm/Support/raw_os_ostream.h" + _base_ = raw_ostream + + str = Method(cast(str, StringRef)) -raw_svector_ostream = raw_ostream.Subclass() -raw_svector_ostream.include.add("llvm/Support/raw_os_ostream.h") -str = raw_svector_ostream.method(StringRef.To(str)) diff --git a/newbinding/test2.py b/newbinding/test2.py index ac74594..afb3608 100644 --- a/newbinding/test2.py +++ b/newbinding/test2.py @@ -1,4 +1,5 @@ import api +import extra import _capsule api.capsule.set_debug(True) context = api.getGlobalContext() @@ -15,7 +16,7 @@ assert m.getPointerSize() == api.Module.PointerSize.AnyPointerSize m.dump() -os = api.make_raw_ostream_for_printing() +os = extra.make_raw_ostream_for_printing() m.print_(os, None) print os.str() @@ -29,15 +30,15 @@ fnty = api.FunctionType.get(int1ty, False) fnty.dump() types = [int1ty, api.Type.getIntNTy(context, 21)] -svt = api.make_small_vector_from_types(*types) +svt = extra.make_small_vector_from_types(*types) fnty = api.FunctionType.get(int1ty, svt, False) -os = api.make_raw_ostream_for_printing() +os = extra.make_raw_ostream_for_printing() fnty.print_(os) print os.str() fn = m.getOrInsertFunction("foo", fnty) -os = api.make_raw_ostream_for_printing() +os = extra.make_raw_ostream_for_printing() fn.print_(os, None) print os.str() assert fn.hasName() diff --git a/newbinding/utils.py b/newbinding/utils.py deleted file mode 100644 index 6c39990..0000000 --- a/newbinding/utils.py +++ /dev/null @@ -1,6 +0,0 @@ - -def indent_println(println): - def _println(s): - println("%s%s" % (' '* 4, s)) - return _println -