Small fix to handle @attributes: .... (.....) as a parameter to a function
[gnome.gobject-introspection] / giscanner / annotationparser.py
index 79cbfe8..c693a97 100644 (file)
@@ -63,6 +63,7 @@ OPT_TRANSFER = 'transfer'
 OPT_TYPE = 'type'
 OPT_CLOSURE = 'closure'
 OPT_DESTROY = 'destroy'
+OPT_SKIP = 'skip'
 
 # Specific option values
 OPT_VAL_BITFIELD = 'bitfield'
@@ -72,6 +73,9 @@ OPT_ARRAY_FIXED_SIZE = 'fixed-size'
 OPT_ARRAY_LENGTH = 'length'
 OPT_ARRAY_ZERO_TERMINATED = 'zero-terminated'
 
+OPT_SCOPE_ASYNC = 'async'
+OPT_SCOPE_CALL = 'call'
+OPT_SCOPE_NOTIFIED = 'notified'
 
 class InvalidAnnotationError(Exception):
     pass
@@ -205,8 +209,9 @@ class AnnotationParser(object):
             tag_name, value = self._split_tag_namevalue(line)
             canon_name = tag_name.lower()
             if canon_name in block.tags:
-                print >>sys.stderr, "Multiple definition of tag %r" \
-                    % (canon_name, )
+                print >> sys.stderr, (
+                    "Symbol %s has multiple definition of tag %r" % (
+                    block_name, canon_name, ))
             block.tags[canon_name] = self._create_tag(canon_name, value)
         block.comment = '\n'.join(comment_lines)
         self._blocks[block.name] = block
@@ -217,6 +222,8 @@ class AnnotationParser(object):
         if len(parts) == 1:
             tag_name = parts[0]
             value = ''
+            if tag_name.endswith(':'):
+                tag_name = tag_name[:-1]
         else:
             tag_name, value = parts
         return (tag_name, value)
@@ -409,6 +416,17 @@ class AnnotationApplier(object):
 
     def _parse_callable(self, callable, block):
         self._parse_node_common(callable, block)
+        for i, param in enumerate(callable.parameters):
+            if (param.type.ctype != 'GDestroyNotify' and
+                param.type.name != 'GLib.DestroyNotify'):
+                continue
+            if i < 2:
+                break
+            callback_param = callable.parameters[i-2]
+            if callback_param.closure_index != -1:
+                callback_param.scope = OPT_SCOPE_NOTIFIED
+                callback_param.transfer = PARAM_TRANSFER_NONE
+
         self._parse_params(callable, callable.parameters, block)
         self._parse_return(callable, callable.retval, block)
         if block:
@@ -494,6 +512,11 @@ class AnnotationApplier(object):
             if scope:
                 param.scope = scope.one()
                 param.transfer = PARAM_TRANSFER_NONE
+            elif (param.type.ctype == 'GAsyncReadyCallback' or
+                  param.type.name == 'Gio.AsyncReadyCallback'):
+                param.scope = OPT_SCOPE_ASYNC
+                param.transfer = PARAM_TRANSFER_NONE
+
             destroy = options.get(OPT_DESTROY)
             if destroy:
                 param.destroy_index = parent.get_parameter_index(destroy.one())
@@ -529,12 +552,14 @@ class AnnotationApplier(object):
         if node.direction is None:
             node.direction = self._guess_direction(node)
         node.transfer = self._extract_transfer(parent, node, options)
-        if OPT_ALLOW_NONE in options:
-            node.allow_none = True
         param_type = options.get(OPT_TYPE)
         if param_type:
             node.type = self._resolve(param_type.one(), node.type)
 
+        if (OPT_ALLOW_NONE in options or
+            node.type.ctype == 'GCancellable*'):
+            node.allow_none = True
+
         assert node.transfer is not None
         if tag is not None and tag.comment is not None:
             node.doc = tag.comment
@@ -639,9 +664,11 @@ class AnnotationApplier(object):
         def combiner(base, *rest):
             if not rest:
                 return base
-            if base.name in ['GLib.List', 'GLib.SList'] and len(rest)==1:
+            if (base.name in ['GLib.List', 'GLib.SList'] or
+                base.ctype in ['GList*', 'GSList*']) and len(rest)==1:
                 return List(base.name, base.ctype, *rest)
-            if base.name in ['GLib.HashTable'] and len(rest)==2:
+            if (base.name in ['GLib.HashTable'] or
+                base.ctype in ['GHashTable*']) and len(rest)==2:
                 return Map(base.name, base.ctype, *rest)
             print "WARNING: throwing away type parameters:", type_str
             return base
@@ -660,13 +687,15 @@ class AnnotationApplier(object):
     def _parse_element_type(self, parent, node, options):
         element_type_opt = options.get(OPT_ELEMENT_TYPE)
         element_type = element_type_opt.flat()
-        if node.type.name in ['GLib.List', 'GLib.SList']:
+        if (node.type.name in ['GLib.List', 'GLib.SList'] or
+            node.type.ctype in ['GList*', 'GSList*']):
             assert len(element_type) == 1
             container_type = List(
                 node.type.name,
                 node.type.ctype,
                 self._resolve(element_type[0]))
-        elif node.type.name in ['GLib.HashTable']:
+        elif (node.type.name in ['GLib.HashTable'] or
+              node.type.ctype in ['GHashTable*']):
             assert len(element_type) == 2
             container_type = Map(
                 node.type.name,
@@ -697,6 +726,7 @@ class AnnotationApplier(object):
         self._parse_version(node, block)
         self._parse_deprecated(node, block)
         self._parse_attributes(node, block)
+        self._parse_skip(node, block)
 
     def _parse_version(self, node, block):
         since_tag = self._get_tag(block, TAG_SINCE)
@@ -723,7 +753,13 @@ class AnnotationApplier(object):
         if annos_tag is None:
             return
         for key, value in annos_tag.options.iteritems():
-            node.attributes.append((key, value.one()))
+            if value:
+                node.attributes.append((key, value.one()))
+
+    def _parse_skip(self, node, block):
+        if block is not None:
+            if OPT_SKIP in block.options:
+                node.skip = True
 
     def _parse_rename_to_func(self, node, block):
         rename_to_tag = self._get_tag(block, TAG_RENAME_TO)