Eolian: WIP

This commit is contained in:
Kai Huuhko 2014-09-30 22:25:06 +03:00
parent 6b45d3429d
commit a795ec8c10
6 changed files with 166 additions and 58 deletions

View File

@ -20,14 +20,16 @@ from cpython cimport PyObject, Py_INCREF, Py_DECREF, PyUnicode_AsUTF8String
from libc.stdint cimport uintptr_t
from efl.eina cimport Eina_Bool, \
Eina_Hash, eina_hash_string_superfast_new, eina_hash_add, eina_hash_del, \
eina_hash_find, EINA_LOG_DOM_DBG, EINA_LOG_DOM_INFO
eina_hash_find, EINA_LOG_DOM_DBG, EINA_LOG_DOM_INFO, \
eina_hash_pointer_new
from efl.c_eo cimport Eo as cEo, eo_init, eo_shutdown, eo_del, eo_do, \
eo_class_name_get, eo_class_get, eo_base_class_get,\
eo_key_data_set, eo_key_data_get, eo_key_data_del, \
eo_event_callback_add, eo_event_callback_del, EO_EV_DEL, \
eo_parent_get, eo_parent_set, Eo_Event_Description, \
eo_event_freeze, eo_event_thaw, eo_event_freeze_count_get, \
eo_event_global_freeze, eo_event_global_thaw, eo_event_global_freeze_count_get
eo_event_global_freeze, eo_event_global_thaw, \
eo_event_global_freeze_count_get
cimport efl.eo.enums as enums
@ -193,6 +195,30 @@ cdef Eina_Bool _eo_event_del_cb(void *data, cEo *obj,
return enums.EO_CALLBACK_STOP
cdef Eina_Bool _py_efl_eo_event_cb(
void *data, cEo *obj, const Eo_Event_Description *desc, void *event_info):
cdef:
void* tmp
bint ret
Eo o
func = <object>data
o = object_from_instance(obj)
# create event description python object
tmp = eina_hash_find(o.event_conv_mapping, desc)
if tmp == NULL:
py_ev_info_obj = None
else:
py_ev_info_cls = <object>tmp
# use a generic class and set some conv func??
#py_ev_info_obj = py_ev_info_cls.__new__(py_ev_info_cls)
#ret = func(py_ev_desc, py_ev_info_obj) # o as first param?
#return ret
cdef class Eo(object):
"""
@ -204,6 +230,8 @@ cdef class Eo(object):
# c globals declared in eo.pxd (to make the class available to others)
def __cinit__(self):
self.event_desc_mapping = eina_hash_string_superfast_new(NULL)
self.event_conv_mapping = eina_hash_pointer_new(NULL)
self.data = dict()
def __init__(self, *args, **kwargs):
@ -296,7 +324,49 @@ cdef class Eo(object):
:return: the freeze count
:rtype: int
"""
cdef int fcount = <int>eo_do(self.obj, eo_event_freeze_count_get())
return fcount
def event_callback_add(self, event_name, func):
cdef:
void *desc
const char *ev_name
if isinstance(event_name, unicode):
event_name = PyUnicode_AsUTF8String(event_name)
ev_name = event_name
desc = eina_hash_find(self.event_desc_mapping, ev_name)
if desc is NULL:
raise RuntimeError("Unknown Eo event name: %s" % (event_name))
eo_event_callback_add(
<Eo_Event_Description *>desc,
_py_efl_eo_event_cb,
<const void *>func
)
Py_INCREF(func)
def event_callback_del(self, event_name, func):
cdef:
void *desc
const char *ev_name
if isinstance(event_name, unicode):
event_name = PyUnicode_AsUTF8String(event_name)
ev_name = event_name
desc = eina_hash_find(self.event_desc_mapping, ev_name)
if desc is NULL:
raise RuntimeError("Unknown Eo event name: %s" % (event_name))
eo_event_callback_del(
<Eo_Event_Description *>desc,
_py_efl_eo_event_cb,
<const void *>func
)
Py_DECREF(func)

View File

@ -17,7 +17,7 @@
from efl.eina cimport Eina_Bool
cdef extern from "*":
cdef extern from *:
struct CFILE "__FILE__"
struct CLINE "__LINE__"
struct CFUNC "__FUNCTION__"

View File

@ -161,6 +161,7 @@ cdef extern from "Eina.h":
unsigned int eina_list_count(Eina_List *list)
Eina_Hash *eina_hash_string_superfast_new(Eina_Free_Cb data_free_cb)
Eina_Hash *eina_hash_pointer_new(Eina_Free_Cb data_free_cb)
Eina_Bool eina_hash_add(Eina_Hash *hash, const void *key, const void *data)
Eina_Bool eina_hash_del(Eina_Hash *hash, const void *key, const void *data)
void *eina_hash_find(Eina_Hash *hash, const void *key)

View File

@ -16,11 +16,14 @@
# along with this Python-EFL. If not, see <http://www.gnu.org/licenses/>.
from efl.c_eo cimport Eo as cEo
from efl.eina cimport Eina_Hash
cdef:
class Eo(object):
cdef:
cEo *obj
Eina_Hash *event_desc_mapping
Eina_Hash *event_conv_mapping
readonly dict data
int _set_obj(self, cEo *obj) except 0

View File

@ -6,6 +6,9 @@ import keyword
from efl import eolian
class EolianTypeError(Exception):
pass
docstring_replacements = (
("@brief ", ""),
(re.compile(r"@ingroup .+", re.S), r""),
@ -95,16 +98,20 @@ conversions_out = {
}
class EolianTypeError(TypeError):
pass
def conv_cls_name(name):
s = name.split("_")
def conv_cls_name(cls):
if cls.namespaces:
lib_name = ".".join(map(unicode.lower, cls.namespaces))
name = cls.name
else:
s = cls.name.split("_")
if len(s) > 1:
return s[0], "_".join(s[1:])
lib_name = s[0]
name = "_".join(s[1:])
else:
return name, name
lib_name = s
name = s
return lib_name, name
def remove_type_prefixes(ctype):
@ -188,3 +195,7 @@ def conv_type_ret(tp):
py_ret_type = py_t[0]
return py_ret_type, c_type
def event_conversion_get(tp):
if tp.type != eolian.TypeType.UNKNOWN:
return "Eo_Event_%s" % tp.name

View File

@ -37,9 +37,12 @@ eolian.init()
from converters import convert_in_param, convert_out_param, conv_type_ret, \
conv_cls_name, EolianTypeError
conv_cls_name, EolianTypeError, event_conversion_get
class EolianSkip(Exception):
pass
class Generator(object):
@ -97,10 +100,11 @@ class Generator(object):
#self.write(docs, wrapped=True)
#self.write('"""')
def printout(self, filepath=None):
def printout(self, filepath=None, append=False):
result = "\n".join(self.result)
if filepath:
with open(filepath, "w") as f:
mode = "a" if append else "w"
with open(filepath, mode) as f:
f.write(result.encode("utf-8"))
f.write("\n")
log.info(filepath + " written")
@ -336,7 +340,7 @@ class Function(object):
ret = self.RET_PARAM
try:
ret_type = convert_out_param(ret_type, ret)
except Exception:
except EolianTypeError:
gen.write("# FIXME: Unknown return type")
gen.dedent()
raise
@ -482,11 +486,7 @@ class Class(object):
class_counter[cls.name] += 1
self.c_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)
self.lib_name, self.name = conv_cls_name(cls)
header_path = cls.filename
if not header_path:
@ -505,8 +505,8 @@ class Class(object):
self.prefix = prefix
#if cls.type == eolian.ClassType.REGULAR: # or cls.type == eolian.ClassType.MIXIN:
self.ctor.append(Constructor(cls.constructors, prefix))
if cls.type == eolian.ClassType.REGULAR: # or cls.type == eolian.ClassType.MIXIN:
self.ctor.append(Constructor(cls.constructors, prefix))
props = cls.functions_get(eolian.FunctionType.PROPERTY)
for prop in props:
@ -568,10 +568,16 @@ class Class(object):
if i_cls.type == eolian.ClassType.INTERFACE or \
i_cls.type == eolian.ClassType.MIXIN:
continue
if i_cls.full_name == "Eo.Base":
inherits.append("Eo")
continue
lib_name, name = conv_cls_name(i_cls)
#i = i.rpartition(".")[2]
inherits.append("_" + name)
else:
log.warn("Class %s is unknown" % (i))
i = i.rpartition(".")[2]
inherits.append("_" + i)
log.warn("Inherited class %s is unknown" % (i))
i = i.rpartition(".")[2]
inherits.append("_" + i)
if len(inherits) > 1:
log.error(
"Multiple inheritance is not supported in extension classes.\n"
@ -586,12 +592,24 @@ class Class(object):
gen.write("cdef class _%s(%s):" % (self.name, inherits))
gen.indent()
gen.write("def __cinit__(self):")
gen.indent()
for o in self.events:
try:
o.generate(gen)
except EolianTypeError:
log.info("Skipping %r because of unknown type", o)
except Exception:
log.exception("Error while generating %r", o)
gen.dedent()
gen.write()
if not self.ctor and not self.props and not self.methods:
gen.write("pass")
else:
for o in (
self.ctor +
list(self.events)
self.ctor #+
#list(self.events)
):
try:
o.generate(gen)
@ -625,11 +643,15 @@ class Class(object):
if i_cls.type == eolian.ClassType.REGULAR or \
i_cls.type == eolian.ClassType.ABSTRACT:
continue
lib_name, name = conv_cls_name(i_cls)
#i = i.rpartition(".")[2]
else:
log.warn("Class %s is unknown" % (i))
l, n = conv_cls_name(i)
inherits.append("_" + n)
imports.append((l, "_" + n))
i = i.rpartition(".")
lib_name, name = i[0], i[2]
inherits.append("_" + name)
imports.append((lib_name, "_" + name))
for l, n in imports:
l = l.lower()
@ -652,6 +674,8 @@ class Class(object):
gen.dedent()
gen.dedent()
gen.write()
gen.write('_object_mapping_register("%s", %s)' % (self.c_name, self.name))
gen.write()
class File(object):
@ -662,33 +686,13 @@ class File(object):
self.cls = eolian.Class.get_by_file(filepath)
if not self.cls:
raise RuntimeError("Could not get class from %s" % (filepath))
if self.cls.full_name.startswith("Eo."):
raise EolianSkip("Skipping Eo class")
self.gencls = Class.parse(self.cls)
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 "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, const char *file, const char *func, int line)')
#gen.write('void _eo_do_end(const Eo **ojb)')
# gen.dedent()
# gen.write()
gen.write('cdef extern from "%s":' % (self.gencls.header_path))
gen.indent()
@ -750,24 +754,32 @@ class File(object):
def py_generate(self):
py_path = os.path.join(args.output, "__init__" + ".py")
if os.path.exists(py_path):
os.remove(py_path)
self.gencls.py_generate(self.pygen)
self.pygen.printout(filepath=py_path)
self.pygen.printout(filepath=py_path, append=True)
class Event(object):
def __init__(self, event):
self.event = event
#print(event)
def cdef_generate(self, gen):
gen.write("enum: %s" % (self.event.c_name))
def generate(self, gen):
pass
gen.write(
'eina_hash_set(self.event_desc_mapping, "%s", %s)' % (
self.event.name, self.event.c_name
)
)
conv = event_conversion_get(self.event.type)
if conv:
gen.write(
'eina_hash_set(self.event_conv_mapping, %s, %s)' % (
self.event.c_name, conv
)
)
class_counter = Counter()
@ -775,6 +787,9 @@ generated_class_counter = Counter()
function_counter = Counter()
generated_function_counter = Counter()
py_path = os.path.join(args.output, "__init__" + ".py")
if os.path.exists(py_path):
os.remove(py_path)
for path in args.paths:
for dirpath, dirnames, filenames in os.walk(path):
@ -788,6 +803,8 @@ for path in args.paths:
try:
eolf = File(filename)
except EolianSkip:
continue
except Exception:
log.exception("Exception while creating %s" % (filename))
continue
@ -804,6 +821,12 @@ for path in args.paths:
log.exception("Exception while generating pyx for %s" % (filename))
continue
try:
eolf.py_generate()
except Exception:
log.exception("Exception while generating py for %s" % (filename))
continue
def report():
print("===============================================")