From 6b45d3429d2ede27fc0a165120b968d58ab9e426 Mon Sep 17 00:00:00 2001 From: Kai Huuhko Date: Mon, 29 Sep 2014 17:37:15 +0300 Subject: [PATCH] Eolian: WIP --- include/efl.c_eo.pxd | 8 +++ scripts/converters.py | 76 ++++++++++++++++++++------- scripts/eolian_generate.py | 104 +++++++++++++++++++++++-------------- 3 files changed, 131 insertions(+), 57 deletions(-) diff --git a/include/efl.c_eo.pxd b/include/efl.c_eo.pxd index d82e47f..1dec22a 100644 --- a/include/efl.c_eo.pxd +++ b/include/efl.c_eo.pxd @@ -17,6 +17,11 @@ from efl.eina cimport Eina_Bool +cdef extern from "*": + struct CFILE "__FILE__" + struct CLINE "__LINE__" + struct CFUNC "__FUNCTION__" + cdef extern from "Eo.h": #################################################################### # Structures @@ -85,3 +90,6 @@ cdef extern from "Eo.h": void eo_event_callback_add(const Eo_Event_Description *desc, Eo_Event_Cb cb, const void *data) void eo_event_callback_del(const Eo_Event_Description *desc, Eo_Event_Cb cb, const void *data) + + Eina_Bool _eo_do_start(const Eo *obj, const Eo_Class *cur_klass, Eina_Bool is_super, const char *file, const char *func, int line) + void _eo_do_end(const Eo **ojb) diff --git a/scripts/converters.py b/scripts/converters.py index 676cd63..461f0ad 100644 --- a/scripts/converters.py +++ b/scripts/converters.py @@ -2,6 +2,7 @@ import logging log = logging.getLogger("efl.eolian.conv") import re +import keyword from efl import eolian @@ -20,12 +21,37 @@ docstring_replacements = ( ) builtin_types = ( # automatically converted by cython + "byte", + "ubyte", + #"char", "short", "ushort", - #"char", "int", "uint", + "long", + "ulong", + "llong", + "ullong", + "int8", + "uint8", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", + "int128", + "uint128", + "size", + "ssize", + "intptr", + "uintptr", + "ptrdiff", + #"time", + "float", "double", + #"bool", + #"void", "Evas_Coord", "Evas_Real" ) @@ -38,8 +64,8 @@ mapping_in = { # c_type: pyx_type "bool": "bint", "char": "", - "Evas_Object *": "_Eo_Base", - "Eo *": "_Eo_Base", + "Evas_Object": "_Eo_Base", + "Eo": "_Eo_Base", } conversions_in = { @@ -69,6 +95,10 @@ conversions_out = { } +class EolianTypeError(TypeError): + pass + + def conv_cls_name(name): s = name.split("_") if len(s) > 1: @@ -83,54 +113,62 @@ def remove_type_prefixes(ctype): return ctype -def convert_in_param(tp, name, is_nonull=None): +def convert_in_param(tp, param_name, is_nonull=None): c_type = tp.c_type if tp.type == eolian.TypeType.POINTER: tp = tp.base_type if tp.type == eolian.TypeType.CLASS: - return None, c_type, "{0}.obj".format(tp.name) + return None, "Eo", "{0}.obj".format(param_name) key = tp.name if tp.name else c_type if key in builtin_types: - return "", "", key + return "", c_type, param_name + + if not key in mapping_in: + raise EolianTypeError("Unknown IN type: %s" % (key)) conv_expr = conversions_in.get(key) if conv_expr is not None: - conv_expr = conv_expr.format(name) - - if not key in mapping_in: - raise TypeError("Unknown IN type: %s" % (key)) + conv_expr = conv_expr.format(param_name) conv_t = mapping_in[key] #if conv_t is None: #conv_t = "" if not is_nonull: - key = "<{0}>{1} if {1} is not None else NULL".format(c_type, name) + key = "<{0}>{1} if {1} is not None else NULL".format(c_type, param_name) - return conv_expr, conv_t, key + if keyword.iskeyword(param_name): + param_name += "_" + + return conv_expr, conv_t, param_name -def convert_out_param(tp, name): +def convert_out_param(tp, param_name): if tp.type == eolian.TypeType.POINTER: tp = tp.base_type if tp.type == eolian.TypeType.CLASS: # TODO: set obj - return tp.c_type, name + return tp.c_type, param_name key = tp.name if tp.name else tp.c_type if key in builtin_types: - return tp.c_type, name + return tp.c_type, param_name if not key in mapping_out: - raise TypeError("Unknown OUT type: %s" % (key)) + raise EolianTypeError("Unknown OUT type: %s" % (key)) conv = conversions_out.get(key) - name = conv.format(name) - return tp.c_type, name + if conv: + param_name = conv.format(param_name) + + if keyword.iskeyword(param_name): + param_name += "_" + + return tp.c_type, param_name def conv_type_ret(tp): @@ -145,7 +183,7 @@ def conv_type_ret(tp): py_t = mapping_out.get(key) if py_t is None: - raise TypeError("Unknown RET type: %s" % (key)) + raise EolianTypeError("Unknown RET type: %s" % (key)) py_ret_type = py_t[0] diff --git a/scripts/eolian_generate.py b/scripts/eolian_generate.py index 5270f95..6ad0b0f 100755 --- a/scripts/eolian_generate.py +++ b/scripts/eolian_generate.py @@ -37,7 +37,8 @@ eolian.init() from converters import convert_in_param, convert_out_param, conv_type_ret, \ - conv_cls_name + conv_cls_name, EolianTypeError + class Generator(object): @@ -149,9 +150,8 @@ class PyxGenerator(Generator): self.write("%s %s" % (t, ", ".join(names))) self.dedent() - def c_call_write(self, c_name, c_params, ret_type=None, returns=None): + def c_call_write(self, c_name, c_params, ret_type=None): # TODO: Eina_Bool ret value from do_start, useful? - #self.write("_eo_do_start(self.obj, NULL, EINA_FALSE, eina_main_loop_is(), NULL, NULL, 0)") self.write("_eo_do_start(self.obj, NULL, EINA_FALSE, CFILE, CFUNC, CLINE)") c_call = "" @@ -171,7 +171,7 @@ class PyxGenerator(Generator): self.write(")") self.dedent() - #self.write("_eo_do_end(self.obj)") + self.write("_eo_do_end(self.obj)") class Function(object): @@ -207,7 +207,6 @@ class Function(object): self.c_ret_type = ret_type.c_type if ret_type.type != eolian.TypeType.UNKNOWN else "void" - def cdef_generate(self, gen): func = self.func ftypes = eolian.FunctionType @@ -233,7 +232,7 @@ class Function(object): header_params = [] c_call_params = [] return_params = [] - conv_params = [] + expand_params = [] conv_in_exps = [] out_cdefs = [] @@ -261,8 +260,9 @@ class Function(object): header_params.append((c_type, p.name)) c_call_params.append(name) elif di == eolian.ParameterDir.OUT: - out_cdefs.append((c_type, "&"+p.name)) + out_cdefs.append((c_type, p.name)) c_type, name = convert_out_param(p.type, p.name) + c_call_params.append("&" + name) return_params.append((p.type, name)) elif di == eolian.ParameterDir.INOUT: conv_expr, c_type, name = convert_in_param(p.type, p.name, p.is_nonull) @@ -276,14 +276,14 @@ class Function(object): if (func.type == ftypes.PROP_SET or func.type == ftypes.PROPERTY) and not self.isget: py_name = "__set__" c_name = "_".join((c_name, "set")) - conv_params = [] + expand_params = [] for p in list(func.property_values) + list(func.property_keys): conv_expr, c_type, name = convert_in_param(p.type, p.name, p.is_nonull) conv_in_exps.append(conv_expr) - conv_params.append(p.name) - c_call_params.append(name) + expand_params.append(p.name) + c_call_params.append(p.name) header_params = (("", "value"),) ret_type = func.return_type_get(eolian.FunctionType.PROP_SET) @@ -309,9 +309,9 @@ class Function(object): gen.method_header_write(py_name, header_params) gen.indent() - if conv_params: - conv_params = ", ".join(conv_params) - gen.write("%s = value" % (conv_params)) + if expand_params: + expand_params = ", ".join(expand_params) + gen.write("%s = value" % (expand_params)) for e in conv_in_exps: if e: @@ -324,7 +324,7 @@ class Function(object): else: ret_type2 = None - gen.c_call_write(c_name, c_call_params, ret_type2, return_params) + gen.c_call_write(c_name, c_call_params, ret_type2) if return_params: rparams = [] @@ -334,7 +334,12 @@ class Function(object): gen.write("return %s" % (", ".join([r[1] for r in rparams]))) elif ret_type.type != eolian.TypeType.UNKNOWN: ret = self.RET_PARAM - ret_type = convert_out_param(ret_type, ret) + try: + ret_type = convert_out_param(ret_type, ret) + except Exception: + gen.write("# FIXME: Unknown return type") + gen.dedent() + raise gen.write("return %s" % (ret)) gen.dedent() @@ -387,10 +392,15 @@ class Property(object): gen.indent() - self.getter.generate(gen) - self.setter.generate(gen) - - gen.dedent() + try: + self.getter.generate(gen) + self.setter.generate(gen) + except Exception: + gen.write("pass") + gen.write() + raise + finally: + gen.dedent() class Constructor(object): @@ -472,7 +482,11 @@ class Class(object): class_counter[cls.name] += 1 self.c_name = cls.name - self.lib_name, self.name = conv_cls_name(cls.name) + if cls.namespaces: + self.lib_name = ".".join(map(unicode.lower, cls.namespaces)) + self.name = cls.name + else: + self.lib_name, self.name = conv_cls_name(cls.name) header_path = cls.filename if not header_path: @@ -556,6 +570,7 @@ class Class(object): continue else: log.warn("Class %s is unknown" % (i)) + i = i.rpartition(".")[2] inherits.append("_" + i) if len(inherits) > 1: log.error( @@ -580,6 +595,8 @@ class Class(object): ): try: o.generate(gen) + except EolianTypeError: + log.info("Skipping %r because of unknown type", o) except Exception: log.exception("Error while generating %r", o) @@ -589,6 +606,8 @@ class Class(object): ): try: o.generate(gen) + except EolianTypeError: + log.info("Skipping %r because of unknown type", o) except Exception: log.exception("Error while generating %r", o) else: @@ -648,13 +667,13 @@ class File(object): def cdefs_generate(self): gen = self.pyxgen - gen.write('cdef extern from "*":') - gen.indent() - gen.write('struct CFILE "__FILE__"') - gen.write('struct CLINE "__LINE__"') - gen.write('struct CFUNC "__FUNCTION__"') - gen.dedent() - gen.write() + # gen.write('cdef extern from "*":') + # gen.indent() + # gen.write('struct CFILE "__FILE__"') + # gen.write('struct CLINE "__LINE__"') + # gen.write('struct CFUNC "__FUNCTION__"') + # gen.dedent() + # gen.write() # gen.write('cdef extern from "Eina.h":') # gen.indent() @@ -662,13 +681,13 @@ class File(object): # gen.dedent() # gen.write() - gen.write('cdef extern from "Eo.h":') - gen.indent() + # gen.write('cdef extern from "Eo.h":') + # gen.indent() #gen.write('Eina_Bool _eo_do_start(const Eo *obj, const Eo_Class *cur_klass, Eina_Bool is_super, Eina_Bool is_main_loop, const char *file, const char *func, int line)') - gen.write('Eina_Bool _eo_do_start(const Eo *obj, const Eo_Class *cur_klass, Eina_Bool is_super, const char *file, const char *func, int line)') + # gen.write('Eina_Bool _eo_do_start(const Eo *obj, const Eo_Class *cur_klass, Eina_Bool is_super, const char *file, const char *func, int line)') #gen.write('void _eo_do_end(const Eo **ojb)') - gen.dedent() - gen.write() + # gen.dedent() + # gen.write() gen.write('cdef extern from "%s":' % (self.gencls.header_path)) gen.indent() @@ -692,11 +711,15 @@ class File(object): gen.write("%s %s" % (f.type.c_type, f.name)) gen.dedent() else: - log.warning("Unhandled alias! %s %s %s %s", i.name, i.full_name, i.filename, i.description) + log.error("Unhandled alias! %s %s %s %s", i.name, i.full_name, i.filename, i.description) for i in eolian.type_structs_get_by_file(self.filepath): - log.warning("Type struct not handled! %s %s %s %s", i.name, i.full_name, i.filename, i.description) + log.error("Type struct not handled! %s %s %s %s", i.name, i.full_name, i.filename, i.description) for i in eolian.type_enums_get_by_file(self.filepath): - log.warning("Type enum not handled! %s %s %s %s", i.name, i.full_name, i.filename, i.description) + log.error("Type enum not handled! %s %s %s %s", i.name, i.full_name, i.filename, i.description) + for i in eolian.variable_constants_get_by_file(self.filepath): + log.error("Variable constant not handled! %s", i) + for i in eolian.variable_globals_get_by_file(self.filepath): + log.error("Variable global not handled! %s", i) self.gencls.cdefs_generate(gen) @@ -707,13 +730,18 @@ class File(object): self.gencls.pyx_generate(self.pyxgen) path = [args.output] + cls_name = self.cls.name.lower() + filename = cls_name + ".pxi" namespaces = [] for ns in self.cls.namespaces: namespaces.append(ns.lower()) if not namespaces: - log.error("Class %s has no namespaces defined" % (self.cls.name)) - filename = self.cls.name.lower() + ".pxi" - namespace = ".".join(namespaces) + log.warning("Class %s has no namespaces defined" % (self.cls.name)) + nstmp = cls_name.partition("_") + namespace = nstmp[0] + filename = nstmp[2] + ".pxi" + else: + namespace = ".".join(namespaces) filename = ".".join((namespace, filename)) path.append(filename) pxi_path = os.path.join(*path)