summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Andreoli <dave@gurumeditation.it>2016-04-13 22:06:04 +0200
committerDave Andreoli <dave@gurumeditation.it>2016-04-13 22:06:04 +0200
commit56cb944b0d8d25eaf004869292d7de8276cce07a (patch)
treee02cd513ab5807191c8c4e5fb3a8491c0c580854
parent97e4354cd9f10bf8892e5075077d6dae9c86ba09 (diff)
some more typedecl supported, and lots of cleanupsHEADmaster
-rw-r--r--CODING12
-rw-r--r--pyolian/eolian.py28
-rw-r--r--pyolian/generator.py197
3 files changed, 128 insertions, 109 deletions
diff --git a/CODING b/CODING
index 2a23778..caf9fc5 100644
--- a/CODING
+++ b/CODING
@@ -1,3 +1,15 @@
1Problems found wrt eolian and eo
2================================
3
4* is Idler a class or a namespace ?
5 class Ecore.Idler (Eo.Base)
6 class Ecore.Idle.Exiter (Eo.Base)
7 This should not be a problem in py (because we lowercase modules as:
8 ecore.Idler and ecore.idler.Exiter) but still seems wrong to me. Exiter
9 is way too generic for a class name. I think it should be:
10 class Ecore.Idler (Eo.Base)
11 class Ecore.Idle_Exiter (Eo.Base)
12
1 13
2Style 14Style
3===== 15=====
diff --git a/pyolian/eolian.py b/pyolian/eolian.py
index 43bd56e..e13cbd5 100644
--- a/pyolian/eolian.py
+++ b/pyolian/eolian.py
@@ -94,7 +94,10 @@ class Iterator:
94 def free(self): 94 def free(self):
95 lib.eina_iterator_free(self._iter) 95 lib.eina_iterator_free(self._iter)
96 96
97PY_KW = ['in'] 97# python reserved keywords, args with this names will be underscored (del_)
98PY_KW = """del and from not while as elif global or with assert else if pass
99yield break except import print class exec in raise continue finally is return
100def for lambda try""".split()
98 101
99def _c_eolian_event_to_py(f): 102def _c_eolian_event_to_py(f):
100 return Event(f) 103 return Event(f)
@@ -169,12 +172,13 @@ EOLIAN_TYPEDECL_ENUM = lib.EOLIAN_TYPEDECL_ENUM
169EOLIAN_TYPEDECL_ALIAS = lib.EOLIAN_TYPEDECL_ALIAS 172EOLIAN_TYPEDECL_ALIAS = lib.EOLIAN_TYPEDECL_ALIAS
170 173
171### module level functions ################################################### 174### module level functions ###################################################
175
172def file_parse(fname): 176def file_parse(fname):
173 return bool(lib.eolian_file_parse(_pystr_to_bytes(fname))) 177 return bool(lib.eolian_file_parse(_pystr_to_bytes(fname)))
174 178
175def all_eot_files_parse(): 179def all_eot_files_parse():
176 return bool(lib.eolian_all_eot_files_parse()) 180 return bool(lib.eolian_all_eot_files_parse())
177 181
178def system_directory_scan(): 182def system_directory_scan():
179 return bool(lib.eolian_system_directory_scan()) 183 return bool(lib.eolian_system_directory_scan())
180 184
@@ -184,11 +188,14 @@ def database_validate(silent_types=False):
184def typedecl_enums_get_by_file(fname): 188def typedecl_enums_get_by_file(fname):
185 return Iterator(_c_eolian_typedecl_to_py, lib.eolian_typedecl_enums_get_by_file(fname)) 189 return Iterator(_c_eolian_typedecl_to_py, lib.eolian_typedecl_enums_get_by_file(fname))
186 190
191def typedecl_aliases_get_by_file(fname):
192 return Iterator(_c_eolian_typedecl_to_py, lib.eolian_typedecl_aliases_get_by_file(fname))
193
187def declarations_get_by_file(fname): 194def declarations_get_by_file(fname):
188 return Iterator(_c_eolian_declaration_to_py, lib.eolian_declarations_get_by_file(fname)) 195 return Iterator(_c_eolian_declaration_to_py, lib.eolian_declarations_get_by_file(fname))
189# Eina_Iterator *eolian_declarations_get_by_file(const char *fname);
190 196
191### eolian.Class ############################################################ 197
198### Classes #################################################################
192 199
193class Class(object): 200class Class(object):
194 def __init__(self, eo_file=None, c_class=None): 201 def __init__(self, eo_file=None, c_class=None):
@@ -424,7 +431,8 @@ class Parameter(object):
424 431
425 @property 432 @property
426 def type(self): 433 def type(self):
427 return Type(lib.eolian_parameter_type_get(self._obj)) 434 c_type = lib.eolian_parameter_type_get(self._obj)
435 return Type(c_type) if c_type != ffi.NULL else None
428 436
429 437
430class Type(object): 438class Type(object):
@@ -469,8 +477,6 @@ class Type(object):
469 return Type(c_type) if c_type != ffi.NULL else None 477 return Type(c_type) if c_type != ffi.NULL else None
470 478
471 479
472
473
474class Typedecl(object): 480class Typedecl(object):
475 def __init__(self, c_typedecl): 481 def __init__(self, c_typedecl):
476 self._obj = c_typedecl # const Eolian_Typedecl * 482 self._obj = c_typedecl # const Eolian_Typedecl *
@@ -498,6 +504,11 @@ class Typedecl(object):
498 def type(self): 504 def type(self):
499 return lib.eolian_typedecl_type_get(self._obj) 505 return lib.eolian_typedecl_type_get(self._obj)
500 506
507 @property
508 def aliased_base(self):
509 c_type = lib.eolian_typedecl_aliased_base_get(self._obj)
510 return Type(c_type) if c_type != ffi.NULL else None
511
501 512
502class Enum_Type_Field(object): 513class Enum_Type_Field(object):
503 def __init__(self, c_enum_field): 514 def __init__(self, c_enum_field):
@@ -557,3 +568,4 @@ class Variable(object):
557 @property 568 @property
558 def full_name(self): 569 def full_name(self):
559 return _cstr_to_unicode(ffi, lib.eolian_variable_full_name_get(self._obj)) 570 return _cstr_to_unicode(ffi, lib.eolian_variable_full_name_get(self._obj))
571
diff --git a/pyolian/generator.py b/pyolian/generator.py
index aa55ef8..ca911cb 100644
--- a/pyolian/generator.py
+++ b/pyolian/generator.py
@@ -22,20 +22,72 @@ def uncapitalize(s):
22 return s[0].lower() + s[1:] 22 return s[0].lower() + s[1:]
23 23
24 24
25### Files to be generated ### 25### Generator configuration ###
26
26 27
27EO_FILES = [ 28EO_FILES = [
28('ecore_mainloop.eo', 'ecore'), 29 # (eo_filename, destination python module)
30 ('evas_types.eot', 'evas'),
31 # ('evas_object.eo', 'evas'),
32
33# ('ecore_mainloop.eo', 'ecore'),
29# ('ecore_timer.eo', 'ecore'), # double constructor & custom event system 34# ('ecore_timer.eo', 'ecore'), # double constructor & custom event system
30# ('ecore_mainloop.eo', 'ecore'), 35# ('ecore_mainloop.eo', 'ecore'),
31# ('ecore_timer.eo', 'ecore'), 36# ('ecore_timer.eo', 'ecore'),
32# ('efl_gfx_base.eo', 'gfx'), # should be efl/gfx 37# ('efl_gfx_base.eo', 'gfx'), # should be efl/gfx
33('evas_object.eo', 'evas'), 38
34('elm_widget.eo', 'elm'), 39
40# ('elm_widget.eo', 'elm'),
35# ('elm_win.eo', 'elm'), 41# ('elm_win.eo', 'elm'),
36# ('elm_label.eo', 'elm'), 42# ('elm_label.eo', 'elm'),
37] 43]
38 44
45MANUAL_CONSTRUCTORS = {
46'Elm.Win': """
47 def __init__(self, name, type, *args, **kargs):
48 # custom constructor
49 eo.Base.__init__(self, lib.ELM_WIN_CLASS, ffi.NULL, False)
50 lib.elm_obj_win_type_set(self._obj, type)
51 lib.elm_obj_win_name_set(self._obj, _to_bytes(name))
52 eo.Base.__init__end__(self, **kargs)
53
54 print("Win INIT")
55""",
56'Ecore.Timer': """
57 def __init__(self, in_, callback, *args, **kargs):
58
59 userdata = ffi.new_handle(self)
60
61 # custom constructor
62 eo.Base.__init__(self, lib.ecore_timer_class_get(), None, False)
63 lib.ecore_obj_timer_constructor(self._obj, in_, lib._timer_cb, userdata)
64 eo.Base.__init__end__(self, **kargs)
65
66 # print("Timer INIT", in_)
67
68 self._priv['self_h'] = userdata # must keep this alive! :/
69 self._priv['cb'] = callback
70 self._priv['cb_args'] = args
71 self._priv['cb_kargs'] = kargs
72""",
73}
74
75MANUAL_EXCLUDES = [
76'ecore_mainloop_select_func_get', # type @extern Ecore_Select_Function: __undefined_type;
77'evas_obj_clipees_get', # Eina_list*
78# 'evas_obj_map_get', # const Evas_Map *
79'evas_obj_smart_data_get', # void *
80'elm_obj_widget_cursor_add','elm_obj_widget_cursor_del', # Elm_Cursor *
81'elm_obj_widget_event', # void *
82'elm_obj_widget_event_callback_add', # Elm_Event_Cb
83'elm_obj_widget_event_callback_del', # Elm_Event_Cb
84'elm_obj_widget_event_propagate', # void *
85'elm_obj_widget_focus_list_direction_get', # const Eina_List *
86'elm_obj_widget_focus_list_next_get', # const Eina_List *
87# 'elm_obj_win_illume_command_send', # eolian.Type 'Elm.Illume_Command'
88
89]
90
39### Templates ### 91### Templates ###
40 92
41COPYRIGHT = """{0} PYOLIAN AUTOGENERATED FILE (never change this line) 93COPYRIGHT = """{0} PYOLIAN AUTOGENERATED FILE (never change this line)
@@ -115,57 +167,6 @@ CLASS_SETTER = """
115 \""" {2} \""" 167 \""" {2} \"""
116""" 168"""
117 169
118MANUAL_CONSTRUCTORS = {
119'Elm.Win': """
120 def __init__(self, name, type, *args, **kargs):
121 # custom constructor
122 eo.Base.__init__(self, lib.ELM_WIN_CLASS, ffi.NULL, False)
123 lib.elm_obj_win_type_set(self._obj, type)
124 lib.elm_obj_win_name_set(self._obj, _to_bytes(name))
125 eo.Base.__init__end__(self, **kargs)
126
127 print("Win INIT")
128""",
129'Ecore.Timer': """
130 def __init__(self, in_, callback, *args, **kargs):
131
132 userdata = ffi.new_handle(self)
133
134 # custom constructor
135 eo.Base.__init__(self, lib.ecore_timer_class_get(), None, False)
136 lib.ecore_obj_timer_constructor(self._obj, in_, lib._timer_cb, userdata)
137 eo.Base.__init__end__(self, **kargs)
138
139 # print("Timer INIT", in_)
140
141 self._priv['self_h'] = userdata # must keep this alive! :/
142 self._priv['cb'] = callback
143 self._priv['cb_args'] = args
144 self._priv['cb_kargs'] = kargs
145""",
146}
147
148MANUAL_EXCLUDES = [
149'ecore_mainloop_select_func_get', # type @extern Ecore_Select_Function: __undefined_type;
150'evas_obj_clipees_get', # Eina_list*
151'evas_obj_map_get', # const Evas_Map *
152'evas_obj_smart_data_get', # void *
153'elm_obj_widget_cursor_add','elm_obj_widget_cursor_del', # Elm_Cursor *
154'elm_obj_widget_event', # void *
155'elm_obj_widget_event_callback_add', # Elm_Event_Cb
156'elm_obj_widget_event_callback_del', # Elm_Event_Cb
157'elm_obj_widget_event_propagate', # void *
158'elm_obj_widget_focus_highlight_geometry_get', # 'Evas_Coord * THIS IS STRANGE! WRONG EO FILE?
159'elm_obj_widget_focus_list_direction_get', # const Eina_List *
160'elm_obj_widget_focus_list_next_get', # const Eina_List *
161
162
163# 'elm_obj_widget_event_callback_del', # return void *
164# 'elm_obj_win_illume_command_send', # eolian.Type 'Elm.Illume_Command'
165# 'evas_obj_clipees_get', # return Eina_List *
166# 'evas_obj_smart_data_get', # return void *
167# 'evas_obj_map_get', # const Evas_Map *
168]
169 170
170class Generator(object): 171class Generator(object):
171 def __init__(self, main_py_path, headers_path, verbose=False): 172 def __init__(self, main_py_path, headers_path, verbose=False):
@@ -212,7 +213,7 @@ class Generator(object):
212 return False 213 return False
213 214
214 # header file 215 # header file
215 header_fname = os.path.join(self.headers_path, eo_fname.replace('.eo', '.h')) 216 header_fname = os.path.join(self.headers_path, os.path.splitext(eo_fname)[0] + '.h')
216 VRB('to header: ', REL(header_fname)) 217 VRB('to header: ', REL(header_fname))
217 218
218 # package __init__.py file 219 # package __init__.py file
@@ -224,10 +225,9 @@ class Generator(object):
224 VRB('to package: ', REL(init_fname)) 225 VRB('to package: ', REL(init_fname))
225 226
226 # python file 227 # python file
227 py_fname = os.path.join(py_pkg, eo_fname.replace('.eo', '.py')) 228 py_fname = os.path.join(py_pkg, os.path.splitext(eo_fname)[0] + '.py')
228 VRB('to python: ', REL(py_fname)) 229 VRB('to python: ', REL(py_fname))
229 230
230
231 # open initf 231 # open initf
232 mode = 'a' if init_fname in self.already_started_init_files else 'w' 232 mode = 'a' if init_fname in self.already_started_init_files else 'w'
233 with open(init_fname, mode) as initf: 233 with open(init_fname, mode) as initf:
@@ -251,7 +251,8 @@ class Generator(object):
251 ### generate all ### 251 ### generate all ###
252 self.emit_enums(eo_fname, f, headerf, initf) 252 self.emit_enums(eo_fname, f, headerf, initf)
253 self.emit_typedefs(eo_fname, f, headerf, initf) 253 self.emit_typedefs(eo_fname, f, headerf, initf)
254 self.emit_class(eo_fname, f, headerf, initf)#, excludes) 254 if not eo_fname.endswith('.eot'):
255 self.emit_class(eo_fname, f, headerf, initf)#, excludes)
255 256
256 initf.write('from .{} import *\n'.format(eo_fname.replace('.eo', ''))) 257 initf.write('from .{} import *\n'.format(eo_fname.replace('.eo', '')))
257 258
@@ -263,6 +264,7 @@ class Generator(object):
263 264
264 def emit_enums(self, eo_fname, f, headerf, initf): 265 def emit_enums(self, eo_fname, f, headerf, initf):
265 # TODO generate "new style" Enums instead 266 # TODO generate "new style" Enums instead
267 headerf.write('\n// enums\n')
266 for enum in eolian.typedecl_enums_get_by_file(eo_fname): 268 for enum in eolian.typedecl_enums_get_by_file(eo_fname):
267 c_name = enum.full_name.replace('.', '_') 269 c_name = enum.full_name.replace('.', '_')
268 VRB('gen enum:', enum.full_name) 270 VRB('gen enum:', enum.full_name)
@@ -275,20 +277,38 @@ class Generator(object):
275 headerf.write('}} {0};\n'.format(c_name)) 277 headerf.write('}} {0};\n'.format(c_name))
276 278
277 def emit_typedefs(self, eo_fname, f, headerf, initf): 279 def emit_typedefs(self, eo_fname, f, headerf, initf):
280 headerf.write('\n// typedefs\n')
278 for d in eolian.declarations_get_by_file(eo_fname): 281 for d in eolian.declarations_get_by_file(eo_fname):
279 t = d.type 282 t = d.type # declaration type
283 td = d.data_type # declaration Typedecl
280 c_name = d.name.replace('.', '_') 284 c_name = d.name.replace('.', '_')
281 285
282 if t == eolian.EOLIAN_DECL_CLASS: 286 if t == eolian.EOLIAN_DECL_ENUM:
287 pass
288
289 elif t == eolian.EOLIAN_DECL_CLASS:
283 VRB('gen class typedef:', d.name) 290 VRB('gen class typedef:', d.name)
284 headerf.write(CLASS_TYPEDEF.format(d.name, c_name, d.class_.c_get_function_name)) 291 headerf.write(CLASS_TYPEDEF.format(d.name, c_name, d.class_.c_get_function_name))
285 292
286 elif t == eolian.EOLIAN_DECL_ENUM: 293 elif t == eolian.EOLIAN_DECL_STRUCT:
287 # headerf.write('typedef enum _{0} {0};\n'.format(c_name)) 294 VRB('gen struct typedef:', d.name)
288 pass 295 name = td.full_name.replace('.', '_') # TODO why is needed ??
296 if td.type == eolian.EOLIAN_TYPEDECL_STRUCT_OPAQUE:
297 headerf.write('typedef struct _{0} {0};\n'.format(name))
298 else:
299 WRN('Unknown struct type (%d) for: %s' % (td.type, td.full_name))
300
301 elif t == eolian.EOLIAN_DECL_ALIAS:
302 VRB('gen alias typedef:', d.name)
303 base = td.aliased_base
304 if base.type != eolian.EOLIAN_TYPE_UNDEFINED:
305 name = td.full_name.replace('.', '_') # TODO why is needed ??
306 headerf.write('typedef {0} {1};\n'.format(base.c_type, name))
307 else:
308 WRN('Undefined base type for: %s' % (td.full_name))
289 309
290 else: 310 else:
291 WRN('Unknow typedef type: ', t) 311 WRN('Unknown declaration type (%d) for: %s' % (t, d.name))
292 312
293 def emit_class(self, eo_fname, f, headerf, initf): 313 def emit_class(self, eo_fname, f, headerf, initf):
294 klass = eolian.Class(eo_fname) 314 klass = eolian.Class(eo_fname)
@@ -401,7 +421,6 @@ class Generator(object):
401 in_pars = ['self'] 421 in_pars = ['self']
402 out_pars = [] 422 out_pars = []
403 for p in func.parameters: 423 for p in func.parameters:
404 print(p)
405 if p.direction == eolian.EOLIAN_IN_PARAM: 424 if p.direction == eolian.EOLIAN_IN_PARAM:
406 in_pars.append(p.name) 425 in_pars.append(p.name)
407 elif p.direction == eolian.EOLIAN_OUT_PARAM: 426 elif p.direction == eolian.EOLIAN_OUT_PARAM:
@@ -432,9 +451,8 @@ class Generator(object):
432 451
433 params = ', '.join(params) 452 params = ', '.join(params)
434 ret = '' 453 ret = ''
435 if func.return_type_get(eolian.EOLIAN_METHOD):# or ftype == eolian.EOLIAN_PROP_GET: 454 if func.return_type_get(eolian.EOLIAN_METHOD):
436 ret = 'ret = ' 455 ret = 'ret = '
437
438 f.write(' {}lib.{}({})\n'.format(ret, func.full_c_name_get(eolian.EOLIAN_METHOD), params)) 456 f.write(' {}lib.{}({})\n'.format(ret, func.full_c_name_get(eolian.EOLIAN_METHOD), params))
439 457
440 # return a tuple with all the out args 458 # return a tuple with all the out args
@@ -545,7 +563,12 @@ def _type_conv(ty, expr, isin):
545 conv_dict = CONVERSIONS_FROM_PY if isin else CONVERSIONS_FROM_C 563 conv_dict = CONVERSIONS_FROM_PY if isin else CONVERSIONS_FROM_C
546 564
547 # use the base type (ex: Evas.Coord -> int) 565 # use the base type (ex: Evas.Coord -> int)
548 ty = ty.aliased_base 566 base = ty.aliased_base
567 if base and base.name: # :/
568 ty = base
569
570 if ty.type == eolian.EOLIAN_TYPE_UNDEFINED:
571 raise RuntimeError('Cannot handle undefined type: %s' % ty.name)
549 572
550 # an eo object instance ? 573 # an eo object instance ?
551 if ty.type == eolian.EOLIAN_TYPE_POINTER: 574 if ty.type == eolian.EOLIAN_TYPE_POINTER:
@@ -559,45 +582,18 @@ def _type_conv(ty, expr, isin):
559 except AttributeError: 582 except AttributeError:
560 pass 583 pass
561 584
585
562 # or just use the mapping dict 586 # or just use the mapping dict
563 tname = ty.name2 587 tname = ty.name2
564 try: 588 try:
565 fmt = conv_dict[tname] 589 fmt = conv_dict[tname]
566 except: 590 except:
567 raise RuntimeError('Unsupported conversion for type: %s' % ty) 591 raise RuntimeError('Unsupported conversion for type: %s' % ty)
568 # ERR('Unsupported conversion for type:\n', ty) 592 # ERR('Unsupported conversion for type:', ty)
569 return 'XXXXXX(%s)' % tname ####################################################### 593 # return 'XXXXXX(%s)' % tname
570 else: 594 else:
571 return fmt.format(expr) 595 return fmt.format(expr)
572 596
573def _type_conv_py2c(ty, expr, isin):
574
575 # use the base type (ex: Evas.Coord -> int)
576 ty = ty.aliased_base
577
578 # an eo object instance ?
579 if ty.type == eolian.EOLIAN_TYPE_POINTER:
580 if ty.base_type.type == eolian.EOLIAN_TYPE_CLASS:
581 return CONVERSIONS_FROM_PY['eo_objects'].format(expr)
582
583 # an enum ?
584 try:
585 if ty.typedecl.type == eolian.EOLIAN_TYPEDECL_ENUM:
586 return CONVERSIONS_FROM_PY['enums'].format(expr)
587 except AttributeError:
588 pass
589
590 # or just use the mapping dict
591 tname = ty.name2
592 try:
593 fmt = CONVERSIONS_FROM_PY[tname]
594 except:
595 # raise RuntimeError('Unsupported conversion from py to c for type: %s' % ty)
596 ERR('Unsupported conversion from py to c for type:\n', ty)
597 return 'XXXXXX(%s)' % tname #######################################################
598 else:
599 return fmt.format(expr)
600
601# how to convert a python type to a c type (that can be passed to c functions) 597# how to convert a python type to a c type (that can be passed to c functions)
602CONVERSIONS_FROM_PY = { 598CONVERSIONS_FROM_PY = {
603 # default types (as reported by type.name2) 599 # default types (as reported by type.name2)
@@ -624,7 +620,6 @@ CONVERSIONS_FROM_C = {
624 'eo_objects': '_object_from_instance({0})', # TODO rename and implement _object_from_instance 620 'eo_objects': '_object_from_instance({0})', # TODO rename and implement _object_from_instance
625 'enums': '{0}', 621 'enums': '{0}',
626 622
627 # 'char': '{0}.decode("utf-8")',
628 # "Elm_Object_Item": 'object_item_to_python({0})', 623 # "Elm_Object_Item": 'object_item_to_python({0})',
629 # "Evas_Object": 'object_from_instance({0})', 624 # "Evas_Object": 'object_from_instance({0})',
630 # "Eo": 'object_from_instance({0})', 625 # "Eo": 'object_from_instance({0})',
@@ -633,6 +628,6 @@ CONVERSIONS_FROM_C = {
633 628
634if __name__ == '__main__': 629if __name__ == '__main__':
635 630
636 print('Usage: "python setup.py generate" from the package root dir.') 631 print('Usage: "python setup.py generate [-v]" from the package root dir.')
637 632
638 633