From 5fcb8fa5697ae09480375c2bd943898205b0cf0a Mon Sep 17 00:00:00 2001 From: Kai Huuhko Date: Thu, 25 Sep 2014 18:31:27 +0300 Subject: [PATCH] Eolian: WIP --- efl/eolian/__init__.pxd | 3 +- efl/eolian/__init__.pyx | 46 ++++++++---- scripts/converters.py | 2 +- scripts/eolian_generate.py | 148 ++++++++++++++++++++++--------------- 4 files changed, 124 insertions(+), 75 deletions(-) diff --git a/efl/eolian/__init__.pxd b/efl/eolian/__init__.pxd index 2eafdaf..5b5fa8a 100644 --- a/efl/eolian/__init__.pxd +++ b/efl/eolian/__init__.pxd @@ -215,7 +215,7 @@ cdef extern from "Eolian.h": Eolian_Function_Type eolian_function_type_get(const Eolian_Function *function_id) Eolian_Object_Scope eolian_function_scope_get(const Eolian_Function *function_id) Eina_Stringshare *eolian_function_name_get(const Eolian_Function *function_id) - Eina_Stringshare *eolian_function_full_c_name_get(const Eolian_Function *function_id, const char *prefix) + Eina_Stringshare *eolian_function_full_c_name_get(const Eolian_Function *function_id) const Eolian_Function *eolian_class_function_get_by_name(const Eolian_Class *klass, const char *func_name, Eolian_Function_Type f_type) Eina_Stringshare *eolian_function_legacy_get(const Eolian_Function *function_id, Eolian_Function_Type f_type) Eina_Stringshare *eolian_function_description_get(const Eolian_Function *function_id, Eolian_Function_Type f_type) @@ -258,6 +258,7 @@ cdef extern from "Eolian.h": const Eolian_Type *eolian_event_type_get(const Eolian_Event *event) Eina_Stringshare *eolian_event_description_get(const Eolian_Event *event) Eolian_Object_Scope eolian_event_scope_get(const Eolian_Event *event) + Eina_Stringshare *eolian_event_c_name_get(const Eolian_Event *event) Eina_Bool eolian_class_ctor_enable_get(const Eolian_Class *klass) Eina_Bool eolian_class_dtor_enable_get(const Eolian_Class *klass) const Eolian_Type *eolian_type_alias_get_by_name(const char *name) diff --git a/efl/eolian/__init__.pyx b/efl/eolian/__init__.pyx index f731599..da7d769 100644 --- a/efl/eolian/__init__.pyx +++ b/efl/eolian/__init__.pyx @@ -221,12 +221,12 @@ cdef Type eolian_type_to_python_obj(const Eolian_Type *o): return ret cdef TypeStructField eolian_type_struct_field_to_python_obj(const Eolian_Struct_Type_Field *o): - cdef TypeStructField ret = TypeStructField.__new__(Type) + cdef TypeStructField ret = TypeStructField.__new__(TypeStructField) ret._set_obj(o) return ret cdef TypeEnumField eolian_type_enum_field_to_python_obj(const Eolian_Enum_Type_Field *o): - cdef TypeEnumField ret = TypeEnumField.__new__(Type) + cdef TypeEnumField ret = TypeEnumField.__new__(TypeEnumField) ret._set_obj(o) return ret @@ -934,8 +934,8 @@ cdef class Function(object): def __get__(self): return _ctouni(eolian_function_name_get(self.function_id)) - def full_c_name_get(self, prefix): - """Returns the full C name of a function (with prefix). It's here + property full_c_name: + """Returns the full C name of a function. It's here because the C API names are deduplicated (prefix of function and suffix of prefix merge if applicable) and this helps generators not write the same code over and over. @@ -946,12 +946,12 @@ cdef class Function(object): :rtype: string """ - if isinstance(prefix, unicode): prefix = PyUnicode_AsUTF8String(prefix) - cdef Eina_Stringshare *ret1 - ret1 = eolian_function_full_c_name_get(self.function_id, prefix) - ret2 = _ctouni(ret1) - eina_stringshare_del(ret1) - return ret2 + def __get__(self): + cdef Eina_Stringshare *ret1 + ret1 = eolian_function_full_c_name_get(self.function_id) + ret2 = _ctouni(ret1) + eina_stringshare_del(ret1) + return ret2 def legacy_get(self, Eolian_Function_Type f_type): """Returns a legacy name for a function. @@ -1385,8 +1385,9 @@ cdef class Event(object): def __repr__(self): return ( - "<%s (type=%s, description=%s, scope=%s)>" % ( - self.name, self.type, self.description, self.scope + "<%s (type=%s, description=%s, scope=%s, c_name=%s)>" % ( + self.name, self.type, self.description, self.scope, + self.c_name )) property name: @@ -1425,6 +1426,21 @@ cdef class Event(object): def __get__(self): return ObjectScope(eolian_event_scope_get(self.event)) + property c_name: + """Returns the C name of an event + + :return: the event C name + + You're responsible for deleting the stringshare. + + """ + def __get__(self): + cdef Eina_Stringshare *ret1 + ret1 = eolian_event_c_name_get(self.event) + ret2 = _ctouni(ret1) + eina_stringshare_del(ret1) + return ret2 + cdef class Type(object): @@ -1439,7 +1455,7 @@ cdef class Type(object): pass def __repr__(self): - return "<%s(%s, %s)>" % ( + return "<%s(type=%s, description=%s)>" % ( self.name, self.type, self.description ) @@ -1487,7 +1503,7 @@ cdef class Type(object): """ def __get__(self): - cdef EinaIterator ret = EinaIterator(unicode) + cdef EinaIterator ret = EinaIterator(Type) ret._set_obj(eolian_type_arguments_get(self.tp)) return ret @@ -1510,7 +1526,7 @@ cdef class Type(object): """ def __get__(self): - cdef EinaIterator ret = EinaIterator(unicode) + cdef EinaIterator ret = EinaIterator(TypeStructField) ret._set_obj(eolian_type_struct_fields_get(self.tp)) return ret diff --git a/scripts/converters.py b/scripts/converters.py index ac551e0..2105a87 100644 --- a/scripts/converters.py +++ b/scripts/converters.py @@ -103,7 +103,7 @@ def convert_in_param(tp, name, is_nonull=None): conv_t = "" if not is_nonull: - key = "<{0}>if {1} is not None else NULL".format(c_type, name) + key = "<{0}>{1} if {1} is not None else NULL".format(c_type, name) return conv_expr, conv_t, key diff --git a/scripts/eolian_generate.py b/scripts/eolian_generate.py index 0cd155a..7516d45 100755 --- a/scripts/eolian_generate.py +++ b/scripts/eolian_generate.py @@ -3,7 +3,7 @@ import os import textwrap import keyword -from traceback import format_exc +#from traceback import format_exc from collections import Counter @@ -96,8 +96,19 @@ class Generator(object): #self.write(docs, wrapped=True) #self.write('"""') - def printout(self): - return "\n".join(self.result) + def printout(self, filepath=None): + result = "\n".join(self.result) + if filepath: + with open(filepath, "w") as f: + f.write(result.encode("utf-8")) + f.write("\n") + log.info(filepath + " written") + else: + print(result) + + def clear(self): + self.result = [] + self.level = 0 class PyxGenerator(Generator): @@ -139,14 +150,27 @@ class PyxGenerator(Generator): self.dedent() def c_call_write(self, c_name, c_params, ret_type=None, returns=None): - # TODO: Eina_Bool ret value, useful? - self.write("_eo_do_start(self.obj, NULL, EINA_FALSE, eina_main_loop_is(), NULL, NULL, 0)") - c_params = ", ".join(c_params) - #c_call = "eo_do(self.obj, %s(%s))" % (c_name, c_params) - c_call = "%s(%s)" % (c_name, c_params) + # 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 = "" if ret_type: - c_call = "cdef " + ret_type + " " + self.RET_PARAM + " = " + "<{0}>".format(ret_type) + c_call - self.write(c_call) + c_call += "cdef " + ret_type + " " + self.RET_PARAM + " = " + "<{0}>".format(ret_type) + + c_call += c_name + "(" + + if not c_params: + c_call += ")" + self.write(c_call) + else: + self.write(c_call) + self.indent() + for p in c_params: + self.write(p + ",") + self.write(")") + self.dedent() + self.write("_eo_do_end(self.obj)") @@ -161,21 +185,26 @@ class Function(object): self.c_name = func.full_c_name_get(self.prefix) + self.c_params = [] + ftypes = eolian.FunctionType if (func.type == ftypes.PROP_SET or func.type == ftypes.PROPERTY) and not isget: ret_type = func.return_type_get(eolian.FunctionType.PROP_SET) self.c_name += "_set" + for p in func.parameters: + self.c_params.append((p.type.c_type, p.name)) if (func.type == ftypes.PROP_GET or func.type == ftypes.PROPERTY) and isget: ret_type = func.return_type_get(eolian.FunctionType.PROP_GET) self.c_name += "_get" + for p in func.parameters: + self.c_params.append((p.type.c_type + "*", p.name)) else: ret_type = func.return_type_get(eolian.FunctionType.METHOD) + for p in func.parameters: + self.c_params.append((p.type.c_type, p.name)) self.c_ret_type = ret_type.c_type if ret_type.type != eolian.TypeType.UNKNOWN else "void" - self.c_params = [] - for p in func.parameters: - self.c_params.append((p.type.c_type, p.name)) def cdef_generate(self, gen): func = self.func @@ -243,37 +272,25 @@ class Function(object): ret_type = func.return_type_get(eolian.FunctionType.METHOD) 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 = [] - for p in func.property_values: - - #assert p.direction == eolian.ParameterDir.IN, "prop %s setter has param other than IN" % (c_name) - + 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) - assert conv_params, "params should not be empty for setter of: %s" % (func.name) - header_params = (("", "value"),) - ret_type = func.return_type_get(eolian.FunctionType.PROP_SET) if (func.type == ftypes.PROP_GET or func.type == ftypes.PROPERTY) and self.isget: - py_name = "__get__" c_name = "_".join((c_name, "get")) - for p in func.property_values: - - #assert p.direction == eolian.ParameterDir.OUT, "prop %s getter has param other than OUT" % (c_name) - + for p in list(func.property_values) + list(func.property_keys): c_type = p.type.c_type name = p.name @@ -439,6 +456,7 @@ class Class(object): self.ctor = [] self.methods = [] self.props = [] + self.events = [] self.default_ctor = None self.header_path = None @@ -513,6 +531,10 @@ class Class(object): generated_class_counter[cls.name] += 1 + for event in cls.events: + print(event) + #self.events.append(Event(event)) + return self def cdefs_generate(self, gen): @@ -615,15 +637,23 @@ class File(object): def cdefs_generate(self): gen = self.pyxgen - gen.write('cdef extern from "Eina.h":') + + gen.write('cdef extern from "*":') gen.indent() - gen.write('Eina_Bool eina_main_loop_is(void)') - gen.dedent() - gen.write() + gen.write('struct CFILE "__FILE__"') + gen.write('struct CLINE "__LINE__"') + gen.write('struct CFUNC "__FUNCTION__"') + + # gen.write('cdef extern from "Eina.h":') + # gen.indent() + # gen.write('Eina_Bool eina_main_loop_is(void)') + # gen.dedent() + # gen.write() 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, 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('void _eo_do_end(const Eo **ojb)') gen.dedent() gen.write() @@ -632,11 +662,28 @@ class File(object): gen.indent() for i in eolian.type_aliases_get_by_file(self.filepath): - print(i) + base = i.base_type + if base.type == eolian.TypeType.REGULAR: + gen.write("ctypedef %s %s" % (i.name, base.name)) + elif base.type == eolian.TypeType.FUNCTION: + ret = base.return_type.c_type + if ret is None: + ret = "void" + gen.write("ctypedef %s (*%s)(%s)" % ( + ret, + i.name, + ", ".join([i.c_type for i in base.arguments]))) + elif base.type == eolian.TypeType.STRUCT: + gen.write("ctypedef struct %s:" % (i.name)) + gen.indent() + for f in base.struct_fields: + gen.write("%s %s" % (f.type.c_type, f.name)) + gen.dedent() + print(i.name, i.full_name, i.filename, i.description, i.base_type) for i in eolian.type_structs_get_by_file(self.filepath): - print(i) + print(i.name, i.full_name, i.filename, i.description) for i in eolian.type_enums_get_by_file(self.filepath): - print(i) + print(i.name, i.full_name, i.filename, i.description) self.gencls.cdefs_generate(gen) @@ -646,8 +693,6 @@ class File(object): def pyx_generate(self): self.gencls.pyx_generate(self.pyxgen) - #f_base = os.path.splitext(py_path)[0] - path = [args.output] namespaces = [] for ns in self.cls.namespaces: @@ -660,39 +705,26 @@ class File(object): path.append(filename) pxi_path = os.path.join(*path) - o = self.pyxgen.printout() - if o: - with open(pxi_path, "w") as f: - f.write(o.encode("utf-8")) - log.info(pxi_path + " written") + self.pyxgen.printout(filepath=pxi_path) def py_generate(self): py_path = os.path.join(args.output, "__init__" + ".py") if os.path.exists(py_path): os.remove(py_path) - with open(py_path, "a") as py_f: - self.gencls.py_generate(self.pygen) + self.gencls.py_generate(self.pygen) - o = self.pygen.printout() - if o: - py_f.write(o.encode("utf-8")) - py_f.write("\n") - log.info(py_path + " appended") + self.pygen.printout(filepath=py_path) -class Alias(object): +class Event(object): + def __init__(self, event): + pass + def cdef_generate(self, gen): pass - -class Struct(object): - def cdef_generate(self, gen): - pass - - -class Enum(object): - def cdef_generate(self, gen): + def generate(self, gen): pass