def export_constructor(cls): vtable = cls.vtable alloc = cls.methods.get("__alloc__") # allocderived = cls.methods.get('__alloc_derived__') if not alloc and not vtable: return SourceBlock() signature = SourceBlock("def __init__(self, *args, **kwargs):") # What to do if the class is instantiated directly if alloc: constructor_block = SourceBlock("inst = self.__alloc__(*args, **kwargs)") else: error = "raise TypeError('This class cannot be instantiated directly')" constructor_block = SourceBlock(error) # What to do if a derived class is instantiated. if vtable: derived_block = SourceBlock("inst = self.__alloc_derived__(self, self._vtable_, *args, **kwargs)") else: error = "raise TypeError('You cannot inherit from this class')" derived_block = SourceBlock(error) block = SourceBlock() block.add_block(signature) block.add_line("if type(self) == %s:" % cls.name, 1) block.add_block(constructor_block, 2) block.add_line("else:", 1) block.add_block(derived_block, 2) block.add_line("self._inst = inst", 1) block.add_line("self._ownership = True", 1) block.add_line("self._valid = True", 1) return block
def export_destructors(self, cls, full_name_underscore): block = SourceBlock() block.add_line("void %s(void*);" % self.symbol_for_destructor( cls, full_name_underscore, cls.destructor)) block.add_line("void %s(void*);" % self.symbol_for_array_destructor( cls, full_name_underscore )) return block
def export_function(f): result_name = "result" if f.returns_anything() else None block = SourceBlock() block.add_block(export_function_signature(f)) block.add_block(export_calls(f, result_name), 1) if result_name: block.add_line("return " + result_name, 1) return block
def export_callable_setup(f, result_name="signatures"): module = f.get_closest_parent_module() block = SourceBlock("%s = []" % result_name) for call in f.calls: block.add_block(export_library_import(module, call.get_library(), "lib")) block.add_block(export_call_setup(call, "signature", "lib")) block.add_line("%s.append(signature)" % result_name) return block
def export_library_import(module, library, result_name): block = SourceBlock() distance = module.get_distance_to_parent(library.parent) if distance > 0: block.add_line("from %s import _libraries" % ("." * (distance + 1))) block.add_line("%s = _libraries['%s']" % (result_name, library.name)) return block
def export(self, importer, path): self.setup(importer) block = SourceBlock('extern "C" {') block.add_block(self.export_namespace(importer.root_namespace)) block.add_line("}") with open(path, 'w') as f: f.write(block.as_text())
def export(self, importer, path): self.setup(importer) block = SourceBlock() includes = self.get_includes() if includes: block.add_line('%s\n\n' % includes) block.add_block(self.export_namespace(importer.root_namespace)) with open(path, 'w') as f: f.write(block.as_text())
def export_memory_management_after_call(call): block = SourceBlock() for arg, num in zip(call.args, count()): if not isinstance(arg.type, Class): continue if arg.invalidates: block.add_line("%s._valid = False" % arg.name) if arg.steals: block.add_line("%s._ownership = False" % arg.name) return block
def export_class_setup(cls): blocks = [] for method in cls.methods.values(): block = export_callable_setup(method) block.add_line("%s._meta['%s'] = {'signatures': signatures}" % (cls.name, method.name)) blocks.append(block) for member in cls.members.values(): getter, setter = False, False if member.getter: blocks.append(export_callable_setup(member.getter, "getter_signatures")) getter = True if member.setter: blocks.append(export_callable_setup(member.setter, "setter_signatures")) setter = True getter = "{'signatures': getter_signatures}" if getter else "None" setter = "{'signatures': setter_signatures}" if setter else "None" format = "%s._meta['%s'] = {'getter': %s, 'setter': %s}" blocks.append(SourceBlock(format % (cls.name, member.name, getter, setter))) if cls.vtable: blocks.append(export_vtable_setup(cls)) block = SourceBlock() block.add_line("def _init_cls():") block.add_line("%s._meta = {}" % cls.name, 1) block.add_line("", 1) block.add_block(SourceBlock("").join(blocks, 1)) block.add_line("_init_cls()") return block
def export_function_signature(f, call_args=None): if not call_args: call_args = get_call_args(f) takes_self = isinstance(f, Method) and f.takes_self_argument() args = ["self"] if takes_self else [] args += get_argument_list(call_args) block = SourceBlock() if isinstance(f, Method) and f.is_static(): block.add_line("@staticmethod") block.add_line("def %s(%s):" % (f.name, ", ".join(args))) return block
def export_inheritance_class(self, cls, full_name_underscore): block = SourceBlock() if cls.constructors: for constructor in cls.constructors: if not self.filter.filter_method_signature(cls, constructor, inherited = True): continue args = constructor.args_as_string() if args: args = ", " + args symbol = self.symbol_for_inheritance_constructor(cls, full_name_underscore, constructor) block.add_line("void* %s(void*, void*%s);" % (symbol, args)) else: block.add_line("void* %s(void*, void*);" % ( self.symbol_for_inheritance_constructor(cls, full_name_underscore, None), )) return block
def export_members(self, cls, full_name_underscore): block = SourceBlock() for member in cls.members: if not self.filter.filter_member(cls, member): continue returns = member.type.as_string() getter, setter = self.symbols_for_member(cls, full_name_underscore, member) block.add_line("%s %s(void*);" % ( returns, getter )) block.add_line("void %s(void*, %s);" % ( setter, member.type.as_string(), )) return block
def export_function_setup(f): block = SourceBlock() block.add_line("def _init_function():") block.add_block(export_callable_setup(f), 1) block.add_line("%s._meta = {'signatures': signatures}" % f.name, 1) block.add_line("_init_function()") return block
def export_call(call, result_name="", arg_names=(), export_type_checks=True, call_var=None): if result_name: action = "{result_name} = sig['call']({args})" else: action = "sig['call']({args})" block = SourceBlock() if not call_var: call_var = "sig" block.add_line("%s = %s" % (call_var, get_call(call))) if export_type_checks: block.add_block(export_type_checks_for_call(call)) block.add_block(export_memory_management_before_call(call)) block.add_line(action.format(result_name=result_name, args=get_converted_argument_list(call, arg_names))) block.add_block(export_memory_management_after_call(call)) if not result_name or not call.returns: return block if isinstance(call.returns.type, Class): conversion = "{0} = {1}['returns']._from_c({0}, {2})" conversion = conversion.format(result_name, call_var, repr(call.returns.ownership)) elif isinstance(call.returns, PointerType): conversion = "" else: conversion = "" if conversion: block.add_line(conversion) return block
def export_memory_management_before_call(call): block = SourceBlock() for arg, num in zip(call.args, count()): if not isinstance(arg.type, Class): continue block.add_line("if not %s._valid:" % arg.name) block.add_line("""raise RuntimeError("Invalid object passed as argument '%s'")""" % arg.name, 1) if arg.steals: block.add_line("if not %s._ownership:" % arg.name) msg = "Unowned object passed as argument '%s' to a call that steals ownership" % arg.name msg = 'raise RuntimeError("%s")' % msg block.add_line(msg, 1) return block
def export_methods(self, cls, full_name_underscore): block = SourceBlock() for method in cls.methods: for signature in method.signatures: if not self.filter.filter_method_signature(cls, signature): continue returns = signature.returns.as_string() args = "void*%s%s" % ( ", " if signature.args else '', signature.args_as_string() if signature.args else '' ) symbol = self.symbol_for_method_signature(cls, full_name_underscore, method, signature) block.add_line("%s %s(%s);" % ( returns, symbol, args )) return block
def export_method(cls, method, result_name=""): """ Exports method and stores result in result_name variable in generated code if result_name is given. If it is not given, the result will be returned. """ block = SourceBlock() call_args = get_call_args(method) if not result_name: result_name = method.name == "__init__" or method.returns_anything() result_name = "result" if result_name else "" return_result = True else: return_result = False block.add_block(export_function_signature(method, call_args)) block.add_block(export_calls(method, result_name, call_args), 1) if return_result and method.returns_anything(): block.add_line("return " + result_name, 1) return block
def export_class_vtable(self, full_name_underscore, overridable): block = SourceBlock() counter = count() block.add_line("struct %s__VTable {" % full_name_underscore) for method in overridable: for signature, num in zip(method, counter): args = (num, signature.context.name) block.add_line("void* f%d; // %s" % args, 1) block.add_line("};") return block
def export_type_check(name, type, type_var): block = SourceBlock() if isinstance(type, PointerType): pointee_type = type.type if type.outparam: if type.reference: raise UnsupportedPointerType(type) elif type.array: raise UnsupportedPointerType(type) else: raise UnsupportedPointerType(type) elif type.array: if type.reference: raise UnsupportedPointerType(type) if isinstance(pointee_type, Class): check = "if not isinstance({0}, wrappyr.runtime.CArray) " "or not issubclass({0}.cls, {2}):" else: check = "if not issubclass({0}, {1}):" error = "\"Expected array of '{0}' type for '{1}', " "got '%s'\" % {1}.__class__.__name__" error = error.format(pointee_type.name, name) block.add_line(check.format(name, pointee_type, type_var)) block.add_line("raise TypeError(%s)" % error, 1) else: raise UnsupportedPointerType(type) elif isinstance(type, Class): error = "\"Expected '{0}' type for '{1}', " "got '%s'\" % {1}.__class__.__name__" error = error.format(type.name, name) block.add_line("if not isinstance(%s, %s):" % (name, type_var)) block.add_line("raise TypeError(%s)" % error, 1) return block
def export_calls(f, result_name="", call_args=None, export_call=export_call): block = SourceBlock() call_args = call_args or get_call_args(f) if len(call_args) > 1: call, args = call_args[-1] block.add_line("if %s:" % " and ".join("%s != wrappyr.runtime.NoArgument" % arg.name for arg in args)) block.add_block(export_call(call, result_name), 1) for call, args in reversed(call_args[1:-1]): block.add_line("elif %s:" % " and ".join("%s != wrappyr.runtime.NoArgument" % arg.name for arg in args)) block.add_block(export_call(call, result_name), 1) if len(call_args) > 1: block.add_line("else:") block.add_block(export_call(call_args[0][0], result_name), int(len(call_args) > 1)) return block
def export_methods(self, cls, full_name, full_name_underscore): block = SourceBlock() for method in cls.methods: for i, signature in enumerate(method.signatures): if not self.filter.filter_method_signature(cls, signature): continue returns = signature.returns.as_string() args = "void* cls%s%s" % ( ", " if signature.args else '', signature.args_as_string(self.letters) if signature.args else '' ) block.add_line("%s %s(%s){" % ( returns, self.symbol_for_method_signature(cls, full_name_underscore, method, signature), args )) returns = signature.returns returns_stripped = returns.strip_pointers_and_references() stmt = "((%s*)cls)->%s(%s)" stmt = stmt % (full_name, method.name, self.args_as_params(signature)) if returns.is_reference(): stmt = "&" + stmt if returns_stripped.const and not returns.is_cpp_only(): pointers = returns.get_total_pointers() pointers += int(returns.is_reference()) args = (returns.get_type_name(), "*" * pointers, stmt) stmt = "const_cast<%s%s>(%s)" % args if returns.is_cpp_only(): stmt = "new %s(%s)" % (returns.get_type_name(), stmt) if signature.returns_anything(): stmt = "return " + stmt stmt += ";" block.add_line(stmt, 1) block.add_line("}") return block
def export_constructors(self, cls, full_name_underscore): block = SourceBlock() if cls.constructors: for constructor in cls.constructors: if not self.filter.filter_method_signature(cls, constructor): continue block.add_line("void* %s(%s);" % ( self.symbol_for_constructor(cls, full_name_underscore, constructor), constructor.args_as_string() )) else: block.add_line("void* %s();" % ( self.symbol_for_constructor(cls, full_name_underscore), )) # Array if cls.is_default_constructable(): block.add_line("void* %s(unsigned int);" % self.symbol_for_array_constructor( cls, full_name_underscore )) return block
def export_destructors(self, cls, full_name, full_name_underscore): block = SourceBlock() block.add_line("void %s(void* cls){" % self.symbol_for_destructor( cls, full_name_underscore, cls.destructor)) block.add_line("delete (%s*)cls;" % full_name, 1) block.add_line("}") block.add_line("void %s(void* arr){" % self.symbol_for_array_destructor( cls, full_name_underscore )) block.add_line("delete[] (%s*)arr;" % full_name, 1) block.add_line("}") return block
def export_class(self, cls): full_name = cls.get_full_name() full_name_underscore = cls.get_full_name("__") block = SourceBlock() block.add_line("") block.add_line("//") block.add_line("// Begin class '%s'" % cls.get_full_name()) block.add_line("//") # Constructor if not cls.is_abstract(): constructors = self.export_constructors(cls, full_name, full_name_underscore) block.add_block(constructors) # Destructor if not cls.destructor or cls.destructor.access == AccessSpecifier.Public: destructors = self.export_destructors(cls, full_name, full_name_underscore) block.add_block(destructors) # Class size block.add_line("unsigned int %s(){" % self.symbol_for_class_size( cls, full_name_underscore)) block.add_line("return sizeof(%s);" % full_name, 1) block.add_line("}") # Get array element block.add_line("void* %s(void* arr, unsigned int idx){" % self.symbol_for_array_element( cls, full_name_underscore )) block.add_line("return &((%s*)arr)[idx];" % full_name, 1) block.add_line("}") # Methods block.add_block(self.export_methods(cls, full_name, full_name_underscore)) # Members block.add_block(self.export_members(cls, full_name, full_name_underscore)) # C++ class to inherit from a virtual base if cls.is_dynamic(): inheritance_class = self.export_inherited_class( cls, full_name, full_name_underscore ) block.add_block(inheritance_class) return block
def export_constructors(self, cls, full_name, full_name_underscore): block = SourceBlock() if cls.constructors: for constructor in cls.constructors: if not self.filter.filter_method_signature(cls, constructor): continue block.add_line("void* %s(%s){" % ( self.symbol_for_constructor(cls, full_name_underscore, constructor), constructor.args_as_string(self.letters) )) block.add_line("return new %s(%s);" % ( full_name, self.args_as_params(constructor)) , 1) block.add_line("}") else: block.add_line("void* %s(){" % ( self.symbol_for_constructor(cls, full_name_underscore), )) block.add_line("return new %s;" % full_name, 1) block.add_line("}") # Array if cls.is_default_constructable(): block.add_line("void* %s(unsigned int n){" % self.symbol_for_array_constructor( cls, full_name_underscore )) block.add_line("return new %s[n];" % full_name, 1) block.add_line("}") return block
def export_inherited_class(self, cls, full_name, full_name_underscore): block = SourceBlock() overridable = cls.get_overridable_signatures() if not overridable: return block filtered_out = [i for method in overridable for i in method if not self.filter.filter_method_signature(cls, i, True)] if any(sig.pure for sig in filtered_out): msg = ("A pure virtual signature for class %s " "was not overridden because it was filtered out.") raise self.PureMethodNotOverridden(msg % full_name) overridable = [[i for i in method if i not in filtered_out] for method in overridable] overridable = [method for method in overridable if method] vtable = self.export_class_vtable(full_name_underscore, overridable) block.add_block(vtable) block.add_line("class %s__Inherited : public %s {" % (full_name_underscore, full_name)) block.add_line("public:", 1) block.add_block(self.export_inherited_constructors(cls, full_name, full_name_underscore), 2) block.add_block(self.export_inherited_methods(cls, full_name, full_name_underscore, overridable), 2) block.add_line("private:", 1) # block.add_line("%s* m_obj;" % full_name, 2) block.add_line("void* m_script_obj;", 2) block.add_line("void* m_vtable;", 2) block.add_line("};") if cls.constructors: for constructor in cls.constructors: if not self.filter.filter_method_signature(cls, constructor, inherited = True): continue args = constructor.args_as_string(self.letters) if args: args = ", " + args params = self.args_as_params(constructor) if params: params = "script_obj, vtable, " + params else: params = "script_obj, vtable" symbol = self.symbol_for_inheritance_constructor(cls, full_name_underscore, constructor) block.add_line("void* %s(void* script_obj, void* vtable%s){" % (symbol, args)) block.add_line("return new %s__Inherited(%s);" % (full_name_underscore, params), 1) block.add_line("}") else: block.add_line("void* %s(void* script_obj, void* vtable){" % ( self.symbol_for_inheritance_constructor(cls, full_name_underscore, None), )) block.add_line("return new %s__Inherited(script_obj, vtable);" % full_name_underscore, 1) block.add_line("}") return block
def export_inherited_methods(self, cls, full_name, full_name_underscore, overridable): block = SourceBlock() vtable_name = "%s__VTable" % full_name_underscore counter = count() for method in overridable: for signature, num in zip(method, counter): returns = signature.returns.as_string(False, False, False) args = signature.args_as_string(self.letters, False, False, False) const = " const " if signature.const else "" sig_str = "%s %s(%s)%s" % (returns, signature.context.name, args, const) returns = "return " if signature.returns_anything() else "" args_to_parent = ", ".join(self.letters[0:len(signature.args)]) fptr_cast = self.get_callback_cast(signature) deref = "*" if signature.returns.is_reference() or signature.returns.is_cpp_only() else "" nearest_implementation = cls.get_class_implementing_signature(signature) args_to_callback = ["m_script_obj"] for arg, letter in zip(signature.args, self.letters): arg_type = arg.type pointer = int(bool(arg_type.is_reference() or arg_type.is_cpp_only())) pointer = "&" * pointer args_to_callback.append(pointer + letter) args_to_callback = ", ".join(args_to_callback) block.add_line("%s{" % sig_str) block.add_line("void* fptr = ((%s*)m_vtable)->f%d;" % (vtable_name, num), 1) block.add_line("if(fptr)", 1) block.add_line("%s%s(%sfptr)(%s);" % (returns, deref, fptr_cast, args_to_callback), 2) if nearest_implementation: block.add_line("else", 1) block.add_line("%s%s::%s(%s);" % (returns, nearest_implementation.name, signature.context.name, args_to_parent), 2) block.add_line("}") return block
def export_inherited_constructors(self, cls, full_name, full_name_underscore): block = SourceBlock() if cls.constructors: for constructor in cls.constructors: if not self.filter.filter_method_signature(cls, constructor, inherited = True): continue args = constructor.args_as_string(self.letters, False, False) if args: args = ", " + args block.add_line("%s__Inherited(void* script_obj, void* vtable%s)" % ( full_name_underscore, args )) if args: args = self.args_as_params(constructor, False) block.add_line(": %s(%s)" % (full_name, args), 1) block.add_line("{") block.add_line("m_script_obj = script_obj;", 1) block.add_line("m_vtable = vtable;", 1) block.add_line("}") else: block.add_line("%s__Inherited(void* script_obj, void* vtable){" % full_name) block.add_line("m_script_obj = script_obj;", 1) block.add_line("m_vtable = vtable;", 1) block.add_line("}") return block
def export_members(self, cls, full_name, full_name_underscore): block = SourceBlock() for member in cls.members: if not self.filter.filter_member(cls, member): continue getter, setter = self.symbols_for_member(cls, full_name_underscore, member) type = member.type stripped = type.strip_pointers_and_references() # Getter returns = type.as_string() block.add_line("%s %s(void* cls){" % ( returns, getter )) stmt = "((%s*)cls)->%s" % (cls.name, member.name) if type.is_cpp_only(): stmt = "&" + stmt if stripped.const: pointers = type.get_total_pointers() pointers += int(type.is_reference()) pointers += int(type.is_cpp_only()) args = (type.get_type_name(), "*" * pointers, stmt) stmt = "const_cast<%s%s>(%s)" % args stmt = "return %s;" % stmt block.add_line(stmt, 1) block.add_line("}") # Setter block.add_line("void %s(void* cls, %s v){" % ( setter, member.type.as_string(), )) pointers = int(type.is_reference()) pointers += type.get_total_pointers() pointers += int(type.is_cpp_only()) pointers = "*" * pointers stmt = "((%s%s)v);" % (type.get_type_name(), pointers) if type.is_cpp_only(): stmt = "*" + stmt stmt = "((%s*)cls)->%s = " % (full_name, member.name) + stmt block.add_line(stmt, 1) block.add_line("}") return block
def export_module(mod, base_dir): is_pkg = isinstance(mod, Package) name = mod.name if not is_pkg else "__init__" blocks = [] block = SourceBlock() block.add_line("from __future__ import absolute_import") block.add_line("import ctypes") block.add_line("import functools") block.add_line("import wrappyr.runtime") blocks.append(block) if mod.libraries: block = SourceBlock() block.add_line("_libraries = {") for lib in mod.libraries.values(): block.add_line("'%s': ctypes.CDLL('%s')," % (lib.name, lib.path), 1) block.add_line("}") blocks.append(block) classes = sorted(mod.every_class(), key=cmp_to_key(sort_classes)) for cls in classes: blocks.append(export_class(cls)) functions = mod.every_function() for f in functions: blocks.append(export_function(f)) for cls in classes: blocks.append(export_class_setup(cls)) for f in functions: blocks.append(export_function_setup(f)) block = SourceBlock("").join(blocks) with open(os.path.join(base_dir, "%s.py" % name), "w") as f: f.write(block.as_text())