Eolian: WIP

This commit is contained in:
Kai Huuhko 2014-09-25 18:31:27 +03:00
parent 0faee7c36e
commit 5fcb8fa569
4 changed files with 124 additions and 75 deletions

View File

@ -215,7 +215,7 @@ cdef extern from "Eolian.h":
Eolian_Function_Type eolian_function_type_get(const Eolian_Function *function_id) Eolian_Function_Type eolian_function_type_get(const Eolian_Function *function_id)
Eolian_Object_Scope eolian_function_scope_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_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) 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_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) 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) const Eolian_Type *eolian_event_type_get(const Eolian_Event *event)
Eina_Stringshare *eolian_event_description_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) 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_ctor_enable_get(const Eolian_Class *klass)
Eina_Bool eolian_class_dtor_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) const Eolian_Type *eolian_type_alias_get_by_name(const char *name)

View File

@ -221,12 +221,12 @@ cdef Type eolian_type_to_python_obj(const Eolian_Type *o):
return ret return ret
cdef TypeStructField eolian_type_struct_field_to_python_obj(const Eolian_Struct_Type_Field *o): 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) ret._set_obj(o)
return ret return ret
cdef TypeEnumField eolian_type_enum_field_to_python_obj(const Eolian_Enum_Type_Field *o): 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) ret._set_obj(o)
return ret return ret
@ -934,8 +934,8 @@ cdef class Function(object):
def __get__(self): def __get__(self):
return _ctouni(eolian_function_name_get(self.function_id)) return _ctouni(eolian_function_name_get(self.function_id))
def full_c_name_get(self, prefix): property full_c_name:
"""Returns the full C name of a function (with prefix). It's here """Returns the full C name of a function. It's here
because the C API names are deduplicated (prefix of function and suffix because the C API names are deduplicated (prefix of function and suffix
of prefix merge if applicable) and this helps generators not write the of prefix merge if applicable) and this helps generators not write the
same code over and over. same code over and over.
@ -946,12 +946,12 @@ cdef class Function(object):
:rtype: string :rtype: string
""" """
if isinstance(prefix, unicode): prefix = PyUnicode_AsUTF8String(prefix) def __get__(self):
cdef Eina_Stringshare *ret1 cdef Eina_Stringshare *ret1
ret1 = eolian_function_full_c_name_get(self.function_id, prefix) ret1 = eolian_function_full_c_name_get(self.function_id)
ret2 = _ctouni(ret1) ret2 = _ctouni(ret1)
eina_stringshare_del(ret1) eina_stringshare_del(ret1)
return ret2 return ret2
def legacy_get(self, Eolian_Function_Type f_type): def legacy_get(self, Eolian_Function_Type f_type):
"""Returns a legacy name for a function. """Returns a legacy name for a function.
@ -1385,8 +1385,9 @@ cdef class Event(object):
def __repr__(self): def __repr__(self):
return ( return (
"<%s (type=%s, description=%s, scope=%s)>" % ( "<%s (type=%s, description=%s, scope=%s, c_name=%s)>" % (
self.name, self.type, self.description, self.scope self.name, self.type, self.description, self.scope,
self.c_name
)) ))
property name: property name:
@ -1425,6 +1426,21 @@ cdef class Event(object):
def __get__(self): def __get__(self):
return ObjectScope(eolian_event_scope_get(self.event)) 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): cdef class Type(object):
@ -1439,7 +1455,7 @@ cdef class Type(object):
pass pass
def __repr__(self): def __repr__(self):
return "<%s(%s, %s)>" % ( return "<%s(type=%s, description=%s)>" % (
self.name, self.name,
self.type, self.description self.type, self.description
) )
@ -1487,7 +1503,7 @@ cdef class Type(object):
""" """
def __get__(self): def __get__(self):
cdef EinaIterator ret = EinaIterator(unicode) cdef EinaIterator ret = EinaIterator(Type)
ret._set_obj(eolian_type_arguments_get(self.tp)) ret._set_obj(eolian_type_arguments_get(self.tp))
return ret return ret
@ -1510,7 +1526,7 @@ cdef class Type(object):
""" """
def __get__(self): def __get__(self):
cdef EinaIterator ret = EinaIterator(unicode) cdef EinaIterator ret = EinaIterator(TypeStructField)
ret._set_obj(eolian_type_struct_fields_get(self.tp)) ret._set_obj(eolian_type_struct_fields_get(self.tp))
return ret return ret

View File

@ -103,7 +103,7 @@ def convert_in_param(tp, name, is_nonull=None):
conv_t = "" conv_t = ""
if not is_nonull: 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 return conv_expr, conv_t, key

View File

@ -3,7 +3,7 @@
import os import os
import textwrap import textwrap
import keyword import keyword
from traceback import format_exc #from traceback import format_exc
from collections import Counter from collections import Counter
@ -96,8 +96,19 @@ class Generator(object):
#self.write(docs, wrapped=True) #self.write(docs, wrapped=True)
#self.write('"""') #self.write('"""')
def printout(self): def printout(self, filepath=None):
return "\n".join(self.result) 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): class PyxGenerator(Generator):
@ -139,14 +150,27 @@ class PyxGenerator(Generator):
self.dedent() 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, returns=None):
# TODO: Eina_Bool ret value, useful? # 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, eina_main_loop_is(), NULL, NULL, 0)")
c_params = ", ".join(c_params) self.write("_eo_do_start(self.obj, NULL, EINA_FALSE, CFILE, CFUNC, CLINE)")
#c_call = "eo_do(self.obj, %s(%s))" % (c_name, c_params)
c_call = "%s(%s)" % (c_name, c_params) c_call = ""
if ret_type: if ret_type:
c_call = "cdef " + ret_type + " " + self.RET_PARAM + " = " + "<{0}>".format(ret_type) + c_call c_call += "cdef " + ret_type + " " + self.RET_PARAM + " = " + "<{0}>".format(ret_type)
self.write(c_call)
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)") 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_name = func.full_c_name_get(self.prefix)
self.c_params = []
ftypes = eolian.FunctionType ftypes = eolian.FunctionType
if (func.type == ftypes.PROP_SET or func.type == ftypes.PROPERTY) and not isget: if (func.type == ftypes.PROP_SET or func.type == ftypes.PROPERTY) and not isget:
ret_type = func.return_type_get(eolian.FunctionType.PROP_SET) ret_type = func.return_type_get(eolian.FunctionType.PROP_SET)
self.c_name += "_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: if (func.type == ftypes.PROP_GET or func.type == ftypes.PROPERTY) and isget:
ret_type = func.return_type_get(eolian.FunctionType.PROP_GET) ret_type = func.return_type_get(eolian.FunctionType.PROP_GET)
self.c_name += "_get" self.c_name += "_get"
for p in func.parameters:
self.c_params.append((p.type.c_type + "*", p.name))
else: else:
ret_type = func.return_type_get(eolian.FunctionType.METHOD) 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_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): def cdef_generate(self, gen):
func = self.func func = self.func
@ -243,37 +272,25 @@ class Function(object):
ret_type = func.return_type_get(eolian.FunctionType.METHOD) ret_type = func.return_type_get(eolian.FunctionType.METHOD)
if (func.type == ftypes.PROP_SET or func.type == ftypes.PROPERTY) and not self.isget: if (func.type == ftypes.PROP_SET or func.type == ftypes.PROPERTY) and not self.isget:
py_name = "__set__" py_name = "__set__"
c_name = "_".join((c_name, "set")) c_name = "_".join((c_name, "set"))
conv_params = [] conv_params = []
for p in func.property_values: for p in list(func.property_values) + list(func.property_keys):
#assert p.direction == eolian.ParameterDir.IN, "prop %s setter has param other than IN" % (c_name)
conv_expr, c_type, name = convert_in_param(p.type, p.name, p.is_nonull) conv_expr, c_type, name = convert_in_param(p.type, p.name, p.is_nonull)
conv_in_exps.append(conv_expr) conv_in_exps.append(conv_expr)
conv_params.append(p.name) conv_params.append(p.name)
c_call_params.append(name) c_call_params.append(name)
assert conv_params, "params should not be empty for setter of: %s" % (func.name)
header_params = (("", "value"),) header_params = (("", "value"),)
ret_type = func.return_type_get(eolian.FunctionType.PROP_SET) ret_type = func.return_type_get(eolian.FunctionType.PROP_SET)
if (func.type == ftypes.PROP_GET or func.type == ftypes.PROPERTY) and self.isget: if (func.type == ftypes.PROP_GET or func.type == ftypes.PROPERTY) and self.isget:
py_name = "__get__" py_name = "__get__"
c_name = "_".join((c_name, "get")) c_name = "_".join((c_name, "get"))
for p in func.property_values: for p in list(func.property_values) + list(func.property_keys):
#assert p.direction == eolian.ParameterDir.OUT, "prop %s getter has param other than OUT" % (c_name)
c_type = p.type.c_type c_type = p.type.c_type
name = p.name name = p.name
@ -439,6 +456,7 @@ class Class(object):
self.ctor = [] self.ctor = []
self.methods = [] self.methods = []
self.props = [] self.props = []
self.events = []
self.default_ctor = None self.default_ctor = None
self.header_path = None self.header_path = None
@ -513,6 +531,10 @@ class Class(object):
generated_class_counter[cls.name] += 1 generated_class_counter[cls.name] += 1
for event in cls.events:
print(event)
#self.events.append(Event(event))
return self return self
def cdefs_generate(self, gen): def cdefs_generate(self, gen):
@ -615,15 +637,23 @@ class File(object):
def cdefs_generate(self): def cdefs_generate(self):
gen = self.pyxgen gen = self.pyxgen
gen.write('cdef extern from "Eina.h":')
gen.write('cdef extern from "*":')
gen.indent() gen.indent()
gen.write('Eina_Bool eina_main_loop_is(void)') gen.write('struct CFILE "__FILE__"')
gen.dedent() gen.write('struct CLINE "__LINE__"')
gen.write() 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.write('cdef extern from "Eo.h":')
gen.indent() 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.write('void _eo_do_end(const Eo **ojb)')
gen.dedent() gen.dedent()
gen.write() gen.write()
@ -632,11 +662,28 @@ class File(object):
gen.indent() gen.indent()
for i in eolian.type_aliases_get_by_file(self.filepath): 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): 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): 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) self.gencls.cdefs_generate(gen)
@ -646,8 +693,6 @@ class File(object):
def pyx_generate(self): def pyx_generate(self):
self.gencls.pyx_generate(self.pyxgen) self.gencls.pyx_generate(self.pyxgen)
#f_base = os.path.splitext(py_path)[0]
path = [args.output] path = [args.output]
namespaces = [] namespaces = []
for ns in self.cls.namespaces: for ns in self.cls.namespaces:
@ -660,39 +705,26 @@ class File(object):
path.append(filename) path.append(filename)
pxi_path = os.path.join(*path) pxi_path = os.path.join(*path)
o = self.pyxgen.printout() self.pyxgen.printout(filepath=pxi_path)
if o:
with open(pxi_path, "w") as f:
f.write(o.encode("utf-8"))
log.info(pxi_path + " written")
def py_generate(self): def py_generate(self):
py_path = os.path.join(args.output, "__init__" + ".py") py_path = os.path.join(args.output, "__init__" + ".py")
if os.path.exists(py_path): if os.path.exists(py_path):
os.remove(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() self.pygen.printout(filepath=py_path)
if o:
py_f.write(o.encode("utf-8"))
py_f.write("\n")
log.info(py_path + " appended")
class Alias(object): class Event(object):
def __init__(self, event):
pass
def cdef_generate(self, gen): def cdef_generate(self, gen):
pass pass
def generate(self, gen):
class Struct(object):
def cdef_generate(self, gen):
pass
class Enum(object):
def cdef_generate(self, gen):
pass pass