Add codegen to the tracked files
[platform/upstream/gst-editing-services.git] / bindings / python / codegen / definitions.py
1 # -*- Mode: Python; py-indent-offset: 4 -*-
2 import copy
3 import sys
4
5 def get_valid_scheme_definitions(defs):
6     return [x for x in defs if isinstance(x, tuple) and len(x) >= 2]
7
8 def unescape(s):
9     s = s.replace('\r\n', '\\r\\n').replace('\t', '\\t')
10     return s.replace('\r', '\\r').replace('\n', '\\n')
11
12 def make_docstring(lines):
13     return "(char *) " + '\n'.join(['"%s"' % unescape(s) for s in lines])
14
15 # New Parameter class, wich emulates a tuple for compatibility reasons
16 class Parameter(object):
17     def __init__(self, ptype, pname, pdflt, pnull, pdir=None, keeprefcount = False):
18         self.ptype = ptype
19         self.pname = pname
20         self.pdflt = pdflt
21         self.pnull = pnull
22         self.pdir = pdir
23         self.keeprefcount = keeprefcount
24         
25     def __len__(self): return 4
26     def __getitem__(self, i):
27         return (self.ptype, self.pname, self.pdflt, self.pnull)[i]
28
29     def merge(self, old):
30         if old.pdflt is not None:
31             self.pdflt = old.pdflt
32         if old.pnull is not None:
33             self.pnull = old.pnull
34
35 # Parameter for property based constructors
36 class Property(object):
37     def __init__(self, pname, optional, argname):
38         self.pname = pname
39         self.optional = optional
40         self.argname = argname
41
42     def merge(self, old):
43         if old.optional is not None:
44             self.optional = old.optional
45         if old.argname is not None:
46             self.argname = old.argname
47
48
49 class Definition:
50     docstring = "NULL"
51     def __init__(self, *args):
52         """Create a new defs object of this type.  The arguments are the
53         components of the definition"""
54         raise RuntimeError, "this is an abstract class"
55     def merge(self, old):
56         """Merge in customisations from older version of definition"""
57         raise RuntimeError, "this is an abstract class"
58     def write_defs(self, fp=sys.stdout):
59         """write out this definition in defs file format"""
60         raise RuntimeError, "this is an abstract class"
61
62     def guess_return_value_ownership(self):
63         "return 1 if caller owns return value"
64         if getattr(self, 'is_constructor_of', False):
65             self.caller_owns_return = True
66         elif self.ret in ('char*', 'gchar*', 'string'):
67             self.caller_owns_return = True
68         else:
69             self.caller_owns_return = False
70
71
72 class ObjectDef(Definition):
73     def __init__(self, name, *args):
74         self.name = name
75         self.module = None
76         self.parent = None
77         self.c_name = None
78         self.typecode = None
79         self.fields = []
80         self.implements = []
81         self.class_init_func = None
82         self.has_new_constructor_api = False
83         for arg in get_valid_scheme_definitions(args):
84             if arg[0] == 'in-module':
85                 self.module = arg[1]
86             elif arg[0] == 'docstring':
87                 self.docstring = make_docstring(arg[1:])
88             elif arg[0] == 'parent':
89                 self.parent = arg[1]
90             elif arg[0] == 'c-name':
91                 self.c_name = arg[1]
92             elif arg[0] == 'gtype-id':
93                 self.typecode = arg[1]
94             elif arg[0] == 'fields':
95                 for parg in arg[1:]:
96                     self.fields.append((parg[0], parg[1]))
97             elif arg[0] == 'implements':
98                 self.implements.append(arg[1])
99     def merge(self, old):
100         # currently the .h parser doesn't try to work out what fields of
101         # an object structure should be public, so we just copy the list
102         # from the old version ...
103         self.fields = old.fields
104         self.implements = old.implements
105     def write_defs(self, fp=sys.stdout):
106         fp.write('(define-object ' + self.name + '\n')
107         if self.module:
108             fp.write('  (in-module "' + self.module + '")\n')
109         if self.parent != (None, None):
110             fp.write('  (parent "' + self.parent + '")\n')
111         for interface in self.implements:
112             fp.write('  (implements "' + interface + '")\n')
113         if self.c_name:
114             fp.write('  (c-name "' + self.c_name + '")\n')
115         if self.typecode:
116             fp.write('  (gtype-id "' + self.typecode + '")\n')
117         if self.fields:
118             fp.write('  (fields\n')
119             for (ftype, fname) in self.fields:
120                 fp.write('    \'("' + ftype + '" "' + fname + '")\n')
121             fp.write('  )\n')
122         fp.write(')\n\n')
123
124 class MiniObjectDef(Definition):
125     def __init__(self, name, *args):
126         self.name = name
127         self.module = None
128         self.parent = None
129         self.c_name = None
130         self.typecode = None
131         self.fields = []
132         self.implements = []
133         for arg in args:
134             if type(arg) != type(()) or len(arg) < 2:
135                 continue
136             if arg[0] == 'in-module':
137                 self.module = arg[1]
138             elif arg[0] == 'parent':
139                 self.parent = arg[1]
140             elif arg[0] == 'c-name':
141                 self.c_name = arg[1]
142             elif arg[0] == 'gtype-id':
143                 self.typecode = arg[1]
144             elif arg[0] == 'fields':
145                 for parg in arg[1:]:
146                     self.fields.append((parg[0], parg[1]))
147             elif arg[0] == 'implements':
148                 self.implements.append(arg[1])
149     def merge(self, old):
150         # currently the .h parser doesn't try to work out what fields of
151         # an object structure should be public, so we just copy the list
152         # from the old version ...
153         self.fields = old.fields
154         self.implements = old.implements
155     def write_defs(self, fp=sys.stdout):
156         fp.write('(define-object ' + self.name + '\n')
157         if self.module:
158             fp.write('  (in-module "' + self.module + '")\n')
159         if self.parent != (None, None): 
160             fp.write('  (parent "' + self.parent + '")\n')
161         for interface in self.implements:
162             fp.write('  (implements "' + interface + '")\n')
163         if self.c_name:
164             fp.write('  (c-name "' + self.c_name + '")\n')
165         if self.typecode:
166             fp.write('  (gtype-id "' + self.typecode + '")\n')
167         if self.fields:
168             fp.write('  (fields\n')
169             for (ftype, fname) in self.fields:
170                 fp.write('    \'("' + ftype + '" "' + fname + '")\n')
171             fp.write('  )\n')
172         fp.write(')\n\n')
173
174
175 class InterfaceDef(Definition):
176     def __init__(self, name, *args):
177         self.name = name
178         self.module = None
179         self.c_name = None
180         self.typecode = None
181         self.vtable = None
182         self.fields = []
183         self.interface_info = None
184         for arg in get_valid_scheme_definitions(args):
185             if arg[0] == 'in-module':
186                 self.module = arg[1]
187             elif arg[0] == 'docstring':
188                 self.docstring = make_docstring(arg[1:])
189             elif arg[0] == 'c-name':
190                 self.c_name = arg[1]
191             elif arg[0] == 'gtype-id':
192                 self.typecode = arg[1]
193             elif arg[0] == 'vtable':
194                 self.vtable = arg[1]
195         if self.vtable is None:
196             self.vtable = self.c_name + "Iface"
197     def write_defs(self, fp=sys.stdout):
198         fp.write('(define-interface ' + self.name + '\n')
199         if self.module:
200             fp.write('  (in-module "' + self.module + '")\n')
201         if self.c_name:
202             fp.write('  (c-name "' + self.c_name + '")\n')
203         if self.typecode:
204             fp.write('  (gtype-id "' + self.typecode + '")\n')
205         fp.write(')\n\n')
206
207 class EnumDef(Definition):
208     def __init__(self, name, *args):
209         self.deftype = 'enum'
210         self.name = name
211         self.in_module = None
212         self.c_name = None
213         self.typecode = None
214         self.values = []
215         for arg in get_valid_scheme_definitions(args):
216             if arg[0] == 'in-module':
217                 self.in_module = arg[1]
218             elif arg[0] == 'c-name':
219                 self.c_name = arg[1]
220             elif arg[0] == 'gtype-id':
221                 self.typecode = arg[1]
222             elif arg[0] == 'values':
223                 for varg in arg[1:]:
224                     self.values.append((varg[0], varg[1]))
225     def merge(self, old):
226         pass
227     def write_defs(self, fp=sys.stdout):
228         fp.write('(define-' + self.deftype + ' ' + self.name + '\n')
229         if self.in_module:
230             fp.write('  (in-module "' + self.in_module + '")\n')
231         fp.write('  (c-name "' + self.c_name + '")\n')
232         fp.write('  (gtype-id "' + self.typecode + '")\n')
233         if self.values:
234             fp.write('  (values\n')
235             for name, val in self.values:
236                 fp.write('    \'("' + name + '" "' + val + '")\n')
237             fp.write('  )\n')
238         fp.write(')\n\n')
239
240 class FlagsDef(EnumDef):
241     def __init__(self, *args):
242         apply(EnumDef.__init__, (self,) + args)
243         self.deftype = 'flags'
244
245 class BoxedDef(Definition):
246     def __init__(self, name, *args):
247         self.name = name
248         self.module = None
249         self.c_name = None
250         self.typecode = None
251         self.copy = None
252         self.release = None
253         self.fields = []
254         for arg in get_valid_scheme_definitions(args):
255             if arg[0] == 'in-module':
256                 self.module = arg[1]
257             elif arg[0] == 'c-name':
258                 self.c_name = arg[1]
259             elif arg[0] == 'gtype-id':
260                 self.typecode = arg[1]
261             elif arg[0] == 'copy-func':
262                 self.copy = arg[1]
263             elif arg[0] == 'release-func':
264                 self.release = arg[1]
265             elif arg[0] == 'fields':
266                 for parg in arg[1:]:
267                     self.fields.append((parg[0], parg[1]))
268     def merge(self, old):
269         # currently the .h parser doesn't try to work out what fields of
270         # an object structure should be public, so we just copy the list
271         # from the old version ...
272         self.fields = old.fields
273     def write_defs(self, fp=sys.stdout):
274         fp.write('(define-boxed ' + self.name + '\n')
275         if self.module:
276             fp.write('  (in-module "' + self.module + '")\n')
277         if self.c_name:
278             fp.write('  (c-name "' + self.c_name + '")\n')
279         if self.typecode:
280             fp.write('  (gtype-id "' + self.typecode + '")\n')
281         if self.copy:
282             fp.write('  (copy-func "' + self.copy + '")\n')
283         if self.release:
284             fp.write('  (release-func "' + self.release + '")\n')
285         if self.fields:
286             fp.write('  (fields\n')
287             for (ftype, fname) in self.fields:
288                 fp.write('    \'("' + ftype + '" "' + fname + '")\n')
289             fp.write('  )\n')
290         fp.write(')\n\n')
291
292 class PointerDef(Definition):
293     def __init__(self, name, *args):
294         self.name = name
295         self.module = None
296         self.c_name = None
297         self.typecode = None
298         self.fields = []
299         for arg in get_valid_scheme_definitions(args):
300             if arg[0] == 'in-module':
301                 self.module = arg[1]
302             elif arg[0] == 'c-name':
303                 self.c_name = arg[1]
304             elif arg[0] == 'gtype-id':
305                 self.typecode = arg[1]
306             elif arg[0] == 'fields':
307                 for parg in arg[1:]:
308                     self.fields.append((parg[0], parg[1]))
309     def merge(self, old):
310         # currently the .h parser doesn't try to work out what fields of
311         # an object structure should be public, so we just copy the list
312         # from the old version ...
313         self.fields = old.fields
314     def write_defs(self, fp=sys.stdout):
315         fp.write('(define-pointer ' + self.name + '\n')
316         if self.module:
317             fp.write('  (in-module "' + self.module + '")\n')
318         if self.c_name:
319             fp.write('  (c-name "' + self.c_name + '")\n')
320         if self.typecode:
321             fp.write('  (gtype-id "' + self.typecode + '")\n')
322         if self.fields:
323             fp.write('  (fields\n')
324             for (ftype, fname) in self.fields:
325                 fp.write('    \'("' + ftype + '" "' + fname + '")\n')
326             fp.write('  )\n')
327         fp.write(')\n\n')
328
329 class MethodDefBase(Definition):
330     def __init__(self, name, *args):
331         dump = 0
332         self.name = name
333         self.ret = None
334         self.caller_owns_return = None
335         self.unblock_threads = None
336         self.c_name = None
337         self.typecode = None
338         self.of_object = None
339         self.params = [] # of form (type, name, default, nullok)
340         self.varargs = 0
341         self.deprecated = None
342         for arg in get_valid_scheme_definitions(args):
343             if arg[0] == 'of-object':
344                 self.of_object = arg[1]
345             elif arg[0] == 'docstring':
346                 self.docstring = make_docstring(arg[1:])
347             elif arg[0] == 'c-name':
348                 self.c_name = arg[1]
349             elif arg[0] == 'gtype-id':
350                 self.typecode = arg[1]
351             elif arg[0] == 'return-type':
352                 self.ret = arg[1]
353             elif arg[0] == 'caller-owns-return':
354                 self.caller_owns_return = arg[1] in ('t', '#t')
355             elif arg[0] == 'unblock-threads':
356                 self.unblock_threads = arg[1] in ('t', '#t')
357             elif arg[0] == 'parameters':
358                 for parg in arg[1:]:
359                     ptype = parg[0]
360                     pname = parg[1]
361                     pdflt = None
362                     pnull = 0
363                     pdir = None
364                     keeprefcount = False
365                     for farg in parg[2:]:
366                         assert isinstance(farg, tuple)
367                         if farg[0] == 'default':
368                             pdflt = farg[1]
369                         elif farg[0] == 'null-ok':
370                             pnull = 1
371                         elif farg[0] == 'direction':
372                             pdir = farg[1]
373                         elif farg[0] == 'keep-refcount':
374                             keeprefcount = True
375                     self.params.append(Parameter(ptype, pname, pdflt, pnull, pdir,
376                                                  keeprefcount=keeprefcount))
377             elif arg[0] == 'varargs':
378                 self.varargs = arg[1] in ('t', '#t')
379             elif arg[0] == 'deprecated':
380                 self.deprecated = arg[1]
381             else:
382                 sys.stderr.write("Warning: %s argument unsupported.\n"
383                                  % (arg[0]))
384                 dump = 1
385         if dump:
386             self.write_defs(sys.stderr)
387
388         if self.caller_owns_return is None and self.ret is not None:
389             self.guess_return_value_ownership()
390
391     def merge(self, old, parmerge):
392         self.caller_owns_return = old.caller_owns_return
393         self.varargs = old.varargs
394         # here we merge extra parameter flags accross to the new object.
395         if not parmerge:
396             self.params = copy.deepcopy(old.params)
397             return
398         for i in range(len(self.params)):
399             ptype, pname, pdflt, pnull = self.params[i]
400             for p2 in old.params:
401                 if p2[1] == pname:
402                     self.params[i] = (ptype, pname, p2[2], p2[3])
403                     break
404     def _write_defs(self, fp=sys.stdout):
405         if self.of_object != (None, None):
406             fp.write('  (of-object "' + self.of_object + '")\n')
407         if self.c_name:
408             fp.write('  (c-name "' + self.c_name + '")\n')
409         if self.typecode:
410             fp.write('  (gtype-id "' + self.typecode + '")\n')
411         if self.caller_owns_return:
412             fp.write('  (caller-owns-return #t)\n')
413         if self.unblock_threads:
414             fp.write('  (unblock_threads #t)\n')
415         if self.ret:
416             fp.write('  (return-type "' + self.ret + '")\n')
417         if self.deprecated:
418             fp.write('  (deprecated "' + self.deprecated + '")\n')
419         if self.params:
420             fp.write('  (parameters\n')
421             for ptype, pname, pdflt, pnull in self.params:
422                 fp.write('    \'("' + ptype + '" "' + pname +'"')
423                 if pdflt: fp.write(' (default "' + pdflt + '")')
424                 if pnull: fp.write(' (null-ok)')
425                 fp.write(')\n')
426             fp.write('  )\n')
427         if self.varargs:
428             fp.write('  (varargs #t)\n')
429         fp.write(')\n\n')
430
431
432 class MethodDef(MethodDefBase):
433     def __init__(self, name, *args):
434         MethodDefBase.__init__(self, name, *args)
435         for item in ('c_name', 'of_object'):
436             if self.__dict__[item] == None:
437                 self.write_defs(sys.stderr)
438                 raise RuntimeError, "definition missing required %s" % (item,)
439
440     def write_defs(self, fp=sys.stdout):
441         fp.write('(define-method ' + self.name + '\n')
442         self._write_defs(fp)
443
444 class VirtualDef(MethodDefBase):
445     def write_defs(self, fp=sys.stdout):
446         fp.write('(define-virtual ' + self.name + '\n')
447         self._write_defs(fp)
448
449 class FunctionDef(Definition):
450     def __init__(self, name, *args):
451         dump = 0
452         self.name = name
453         self.in_module = None
454         self.is_constructor_of = None
455         self.ret = None
456         self.caller_owns_return = None
457         self.unblock_threads = None
458         self.c_name = None
459         self.typecode = None
460         self.params = [] # of form (type, name, default, nullok)
461         self.varargs = 0
462         self.deprecated = None
463         for arg in get_valid_scheme_definitions(args):
464             if arg[0] == 'in-module':
465                 self.in_module = arg[1]
466             elif arg[0] == 'docstring':
467                 self.docstring = make_docstring(arg[1:])
468             elif arg[0] == 'is-constructor-of':
469                 self.is_constructor_of = arg[1]
470             elif arg[0] == 'c-name':
471                 self.c_name = arg[1]
472             elif arg[0] == 'gtype-id':
473                 self.typecode = arg[1]
474             elif arg[0] == 'return-type':
475                 self.ret = arg[1]
476             elif arg[0] == 'caller-owns-return':
477                 self.caller_owns_return = arg[1] in ('t', '#t')
478             elif arg[0] == 'unblock-threads':
479                 self.unblock_threads = arg[1] in ('t', '#t')
480             elif arg[0] == 'parameters':
481                 for parg in arg[1:]:
482                     ptype = parg[0]
483                     pname = parg[1]
484                     pdflt = None
485                     pnull = 0
486                     keeprefcount = False
487                     for farg in parg[2:]:
488                         if farg[0] == 'default':
489                             pdflt = farg[1]
490                         elif farg[0] == 'null-ok':
491                             pnull = 1
492                         elif farg[0] == 'keep-refcount':
493                             keeprefcount = True
494                     self.params.append(Parameter(ptype, pname, pdflt, pnull,
495                                                  keeprefcount = keeprefcount))
496             elif arg[0] == 'properties':
497                 if self.is_constructor_of is None:
498                     print >> sys.stderr, "Warning: (properties ...) "\
499                           "is only valid for constructors"
500                 for prop in arg[1:]:
501                     pname = prop[0]
502                     optional = False
503                     argname = pname
504                     for farg in prop[1:]:
505                         if farg[0] == 'optional':
506                             optional = True
507                         elif farg[0] == 'argname':
508                             argname = farg[1]
509                     self.params.append(Property(pname, optional, argname))
510             elif arg[0] == 'varargs':
511                 self.varargs = arg[1] in ('t', '#t')
512             elif arg[0] == 'deprecated':
513                 self.deprecated = arg[1]
514             else:
515                 sys.stderr.write("Warning: %s argument unsupported\n"
516                                  % (arg[0],))
517                 dump = 1
518         if dump:
519             self.write_defs(sys.stderr)
520
521         if self.caller_owns_return is None and self.ret is not None:
522             self.guess_return_value_ownership()
523         for item in ('c_name',):
524             if self.__dict__[item] == None:
525                 self.write_defs(sys.stderr)
526                 raise RuntimeError, "definition missing required %s" % (item,)
527
528     _method_write_defs = MethodDef.__dict__['write_defs']
529
530     def merge(self, old, parmerge):
531         self.caller_owns_return = old.caller_owns_return
532         self.varargs = old.varargs
533         if not parmerge:
534             self.params = copy.deepcopy(old.params)
535             return
536         # here we merge extra parameter flags accross to the new object.
537         def merge_param(param):
538             for old_param in old.params:
539                 if old_param.pname == param.pname:
540                     if isinstance(old_param, Property):
541                         # h2def never scans Property's, therefore if
542                         # we have one it was manually written, so we
543                         # keep it.
544                         return copy.deepcopy(old_param)
545                     else:
546                         param.merge(old_param)
547                         return param
548             raise RuntimeError, "could not find %s in old_parameters %r" % (
549                 param.pname, [p.pname for p in old.params])
550         try:
551             self.params = map(merge_param, self.params)
552         except RuntimeError:
553             # parameter names changed and we can't find a match; it's
554             # safer to keep the old parameter list untouched.
555             self.params = copy.deepcopy(old.params)
556
557         if not self.is_constructor_of:
558             try:
559                 self.is_constructor_of = old.is_constructor_of
560             except AttributeError:
561                 pass
562         if isinstance(old, MethodDef):
563             self.name = old.name
564             # transmogrify from function into method ...
565             self.write_defs = self._method_write_defs
566             self.of_object = old.of_object
567             del self.params[0]
568     def write_defs(self, fp=sys.stdout):
569         fp.write('(define-function ' + self.name + '\n')
570         if self.in_module:
571             fp.write('  (in-module "' + self.in_module + '")\n')
572         if self.is_constructor_of:
573             fp.write('  (is-constructor-of "' + self.is_constructor_of +'")\n')
574         if self.c_name:
575             fp.write('  (c-name "' + self.c_name + '")\n')
576         if self.typecode:
577             fp.write('  (gtype-id "' + self.typecode + '")\n')
578         if self.caller_owns_return:
579             fp.write('  (caller-owns-return #t)\n')
580         if self.unblock_threads:
581             fp.write('  (unblock-threads #t)\n')
582         if self.ret:
583             fp.write('  (return-type "' + self.ret + '")\n')
584         if self.deprecated:
585             fp.write('  (deprecated "' + self.deprecated + '")\n')
586         if self.params:
587             if isinstance(self.params[0], Parameter):
588                 fp.write('  (parameters\n')
589                 for ptype, pname, pdflt, pnull in self.params:
590                     fp.write('    \'("' + ptype + '" "' + pname +'"')
591                     if pdflt: fp.write(' (default "' + pdflt + '")')
592                     if pnull: fp.write(' (null-ok)')
593                     fp.write(')\n')
594                 fp.write('  )\n')
595             elif isinstance(self.params[0], Property):
596                 fp.write('  (properties\n')
597                 for prop in self.params:
598                     fp.write('    \'("' + prop.pname +'"')
599                     if prop.optional: fp.write(' (optional)')
600                     fp.write(')\n')
601                 fp.write('  )\n')
602             else:
603                 assert False, "strange parameter list %r" % self.params[0]
604         if self.varargs:
605             fp.write('  (varargs #t)\n')
606
607         fp.write(')\n\n')