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