Eolian: WIP

This commit is contained in:
Kai Huuhko 2014-09-29 17:37:15 +03:00
parent 8d116e2822
commit 6b45d3429d
3 changed files with 131 additions and 57 deletions

View File

@ -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)

View File

@ -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]

View File

@ -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)