Bug 563794 - Redo annotation parsing & applying
authorJohan Dahlin <jdahlin@async.com.br>
Mon, 12 Jan 2009 20:11:44 +0000 (20:11 +0000)
committerJohan Dahlin <johan@src.gnome.org>
Mon, 12 Jan 2009 20:11:44 +0000 (20:11 +0000)
2009-01-12  Johan Dahlin  <jdahlin@async.com.br>

    Bug 563794 - Redo annotation parsing & applying

    Thanks to Colin for helping out considerably in landing this.

    * giscanner/Makefile.am:
    * giscanner/ast.py:
    * giscanner/dumper.py:
    * giscanner/girparser.py:
    * giscanner/giscannermodule.c (pygi_source_scanner_get_comments),
    (calc_attrs_length), (pygi_collect_attributes), (init_giscanner):
    * giscanner/glibtransformer.py:
    * giscanner/scannerlexer.l:
    * giscanner/sourcescanner.c (gi_source_symbol_unref),
    (gi_source_scanner_new), (gi_source_scanner_free),
    (gi_source_scanner_get_comments):
    * giscanner/sourcescanner.h:
    * giscanner/sourcescanner.py:
    * giscanner/transformer.py:
    * giscanner/xmlwriter.py:
    * tests/scanner/annotation-1.0-expected.gir:
    * tests/scanner/annotation-1.0-expected.tgir:
    * tests/scanner/annotation.c:
    * tests/scanner/annotation.h:
    * tests/scanner/foo-1.0-expected.gir:
    * tests/scanner/foo-1.0-expected.tgir:
    * tests/scanner/foo.h:
    * tools/g-ir-scanner:

    This commit merges the annotation parser rewrite branch.
    It'll change the annotation parsing to be done completely in python
    code which will make it easier to do further annotation parsing
    easier.

svn path=/trunk/; revision=1017

22 files changed:
ChangeLog
giscanner/Makefile.am
giscanner/annotationparser.py [new file with mode: 0644]
giscanner/ast.py
giscanner/dumper.py
giscanner/girparser.py
giscanner/giscannermodule.c
giscanner/glibtransformer.py
giscanner/scannerlexer.l
giscanner/sourcescanner.c
giscanner/sourcescanner.h
giscanner/sourcescanner.py
giscanner/transformer.py
giscanner/xmlwriter.py
tests/scanner/annotation-1.0-expected.gir
tests/scanner/annotation-1.0-expected.tgir
tests/scanner/annotation.c
tests/scanner/annotation.h
tests/scanner/foo-1.0-expected.gir
tests/scanner/foo-1.0-expected.tgir
tests/scanner/foo.h
tools/g-ir-scanner

index ab812fd..a16f632 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+2009-01-12  Johan Dahlin  <jdahlin@async.com.br>
+
+       Bug 563794 - Redo annotation parsing & applying
+       
+       Thanks to Colin for helping out considerably in landing this.
+
+       * giscanner/Makefile.am:
+       * giscanner/ast.py:
+       * giscanner/dumper.py:
+       * giscanner/girparser.py:
+       * giscanner/giscannermodule.c (pygi_source_scanner_get_comments),
+       (calc_attrs_length), (pygi_collect_attributes), (init_giscanner):
+       * giscanner/glibtransformer.py:
+       * giscanner/scannerlexer.l:
+       * giscanner/sourcescanner.c (gi_source_symbol_unref),
+       (gi_source_scanner_new), (gi_source_scanner_free),
+       (gi_source_scanner_get_comments):
+       * giscanner/sourcescanner.h:
+       * giscanner/sourcescanner.py:
+       * giscanner/transformer.py:
+       * giscanner/xmlwriter.py:
+       * tests/scanner/annotation-1.0-expected.gir:
+       * tests/scanner/annotation-1.0-expected.tgir:
+       * tests/scanner/annotation.c:
+       * tests/scanner/annotation.h:
+       * tests/scanner/foo-1.0-expected.gir:
+       * tests/scanner/foo-1.0-expected.tgir:
+       * tests/scanner/foo.h:
+       * tools/g-ir-scanner:
+
+       This commit merges the annotation parser rewrite branch.
+       It'll change the annotation parsing to be done completely in python
+       code which will make it easier to do further annotation parsing 
+       easier.
+
 2009-01-03  Andreas Rottmann  <a.rottmann@gmx.at>
  
        Bug 563469 – Arrays not treated correctly in struct offset calculation
index 1d6942b..bc2977f 100644 (file)
@@ -35,6 +35,7 @@ pkgpyexecdir = $(pyexecdir)/giscanner
 pkgpyexec_LTLIBRARIES = _giscanner.la
 pkgpyexec_PYTHON =             \
        __init__.py             \
+       annotationparser.py     \
        ast.py                  \
        cachestore.py           \
        config.py               \
diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py
new file mode 100644 (file)
index 0000000..630508a
--- /dev/null
@@ -0,0 +1,505 @@
+# -*- Mode: Python -*-
+# GObject-Introspection - a framework for introspecting GObject libraries
+# Copyright (C) 2008  Johan Dahlin
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+# AnnotationParser - parses gtk-doc annotations
+
+# All gtk-doc comments needs to start with this:
+_COMMENT_HEADER = '*\n * '
+
+from .ast import (Array, Callback, Class, Enum, Field, Function, Interface,
+                  List, Map, Parameter, Record, Return, Type, Union, Varargs,
+                  default_array_types,
+                  BASIC_GIR_TYPES,
+                  PARAM_DIRECTION_INOUT,
+                  PARAM_DIRECTION_IN,
+                  PARAM_DIRECTION_OUT,
+                  PARAM_TRANSFER_NONE,
+                  PARAM_TRANSFER_CONTAINER,
+                  PARAM_TRANSFER_FULL,
+                  TYPE_ANY, TYPE_NONE)
+from .glibast import GLibBoxed
+
+
+class InvalidAnnotationError(Exception):
+    pass
+
+
+class DocBlock(object):
+
+    def __init__(self, name):
+        self.name = name
+        self.value = None
+        self.tags = {}
+
+    def __repr__(self):
+        return '<Directive %r>' % (self.name, )
+
+    def get(self, name):
+        if name == 'Returns':
+            value = self.tags.get(name)
+            if value is None:
+                return self.tags.get('Return value')
+            else:
+                return value
+        else:
+            return self.tags.get(name)
+
+
+class DocTag(object):
+
+    def __init__(self, name):
+        self.name = name
+        self.options = []
+
+
+class Option(object):
+
+    def __init__(self, option):
+        self._array = []
+        self._dict = {}
+        for p in option.split(' '):
+            if '=' in p:
+                name, value = p.split('=', 1)
+            else:
+                name = p
+                value = None
+            self._dict[name] = value
+            if value is None:
+                self._array.append(name)
+            else:
+                self._array.append((name, value))
+
+    def __repr__(self):
+        return '<Option %r>' % (self._array, )
+
+    def one(self):
+        assert len(self._array) == 1
+        return self._array[0]
+
+    def flat(self):
+        return self._array
+
+    def all(self):
+        return self._dict
+
+
+class AnnotationParser(object):
+
+    def __init__(self, namespace, source_scanner, transformer):
+        self._blocks = {}
+        self._namespace = namespace
+        self._transformer = transformer
+        for comment in source_scanner.get_comments():
+            self._parse_comment(comment)
+
+    def parse(self):
+        aa = AnnotationApplier(self._blocks, self._transformer)
+        aa.parse(self._namespace)
+
+    def _parse_comment(self, comment):
+        if not comment.startswith(_COMMENT_HEADER):
+            return
+        comment = comment[len(_COMMENT_HEADER):]
+        pos = comment.index('\n ')
+
+        block_name = comment[:pos]
+        block_name = block_name.strip()
+        if not block_name.endswith(':'):
+            return
+        block = DocBlock(block_name[:-1])
+        content = comment[pos+1:]
+        for line in content.split('\n'):
+            line = line[2:].strip() # Skip ' *'
+            if not line:
+                continue
+
+            if line.startswith('@'):
+                line = line[1:]
+            elif not ': ' in line:
+                continue
+            tag = self._parse_tag(line)
+            block.tags[tag.name] = tag
+
+        self._blocks[block.name] = block
+
+    def _parse_tag(self, value):
+        # Tag: bar
+        # Tag: bar opt1 opt2
+        parts = value.split(': ', 1)
+        if len(parts) == 1:
+            tag_name = parts[0]
+            options = ''
+        else:
+            tag_name, options = parts
+        tag = DocTag(tag_name)
+        tag.value = options
+        tag.options = self._parse_options(options)
+        return tag
+
+    def _parse_options(self, value):
+        # (foo)
+        # (bar opt1 opt2...)
+        opened = -1
+        options = {}
+        for i, c in enumerate(value):
+            if c == '(' and opened == -1:
+                opened = i+1
+            if c == ')' and opened != -1:
+                segment = value[opened:i]
+                parts = segment.split(' ', 1)
+                if len(parts) == 2:
+                    name, option = parts
+                elif len(parts) == 1:
+                    name = parts[0]
+                    option = None
+                else:
+                    raise AssertionError
+                if option is not None:
+                    option = Option(option)
+                options[name] = option
+                opened = -1
+        return options
+
+
+class AnnotationApplier(object):
+
+    def __init__(self, blocks, transformer):
+        self._blocks = blocks
+        self._transformer = transformer
+
+    def _get_tag(self, block, tag_name):
+        if block is None:
+            return None
+
+        return block.get(tag_name)
+
+    def parse(self, namespace):
+        for node in namespace.nodes:
+            self._parse_node(node)
+
+    # Boring parsing boilerplate.
+
+    def _parse_node(self, node):
+        if isinstance(node, Function):
+            self._parse_function(node)
+        elif isinstance(node, Enum):
+            self._parse_enum(node)
+        elif isinstance(node, Class):
+            self._parse_class(node)
+        elif isinstance(node, Interface):
+            self._parse_interface(node)
+        elif isinstance(node, Callback):
+            self._parse_callback(node)
+        elif isinstance(node, Record):
+            self._parse_record(node)
+        elif isinstance(node, Union):
+            self._parse_union(node)
+        elif isinstance(node, GLibBoxed):
+            self._parse_boxed(node)
+
+    def _parse_class(self, class_):
+        block = self._blocks.get(class_.name)
+        self._parse_version(class_, block)
+        self._parse_constructors(class_.constructors)
+        self._parse_methods(class_.methods)
+        self._parse_methods(class_.static_methods)
+        self._parse_properties(class_.properties)
+        self._parse_signals(class_.signals)
+        self._parse_fields(class_, class_.fields)
+
+    def _parse_interface(self, interface):
+        block = self._blocks.get(interface.name)
+        self._parse_version(interface, block)
+        self._parse_methods(interface.methods)
+        self._parse_properties(interface.properties)
+        self._parse_signals(interface.signals)
+        self._parse_fields(interface, interface.fields)
+
+    def _parse_record(self, record):
+        block = self._blocks.get(record.symbol)
+        self._parse_version(record, block)
+        self._parse_constructors(record.constructors)
+        self._parse_fields(record, record.fields)
+        if isinstance(record, GLibBoxed):
+            self._parse_methods(record.methods)
+
+    def _parse_boxed(self, boxed):
+        block = self._blocks.get(boxed.name)
+        self._parse_version(boxed, block)
+        self._parse_constructors(boxed.constructors)
+        self._parse_methods(boxed.methods)
+
+    def _parse_union(self, union):
+        block = self._blocks.get(union.name)
+        self._parse_fields(union, union.fields)
+        self._parse_constructors(union.constructors)
+        if isinstance(union, GLibBoxed):
+            self._parse_methods(union.methods)
+
+    def _parse_enum(self, enum):
+        block = self._blocks.get(enum.symbol)
+        self._parse_version(enum, block)
+
+    def _parse_constructors(self, constructors):
+        for ctor in constructors:
+            self._parse_function(ctor)
+
+    def _parse_fields(self, parent, fields):
+        for field in fields:
+            self._parse_field(parent, field)
+
+    def _parse_properties(self, properties):
+        for prop in properties:
+            self._parse_property(property)
+
+    def _parse_methods(self, methods):
+        for method in methods:
+            self._parse_function(method)
+
+    def _parse_signals(self, signals):
+        for signal in signals:
+            self._parse_signal(signal)
+
+    def _parse_property(self, prop):
+        pass
+
+    def _parse_callback(self, callback):
+        block = self._blocks.get(callback.ctype)
+        self._parse_version(callback, block)
+        self._parse_params(callback, callback.parameters, block)
+        self._parse_return(callback, callback.retval, block)
+
+    def _parse_function(self, func):
+        block = self._blocks.get(func.symbol)
+        self._parse_version(func, block)
+        self._parse_deprecated(func, block)
+        self._parse_params(func, func.parameters, block)
+        self._parse_return(func, func.retval, block)
+
+    def _parse_signal(self, signal):
+        block = self._blocks.get(signal.name)
+        self._parse_version(signal, block)
+        self._parse_params(signal, signal.parameters, block)
+        self._parse_return(signal, signal.retval, block)
+
+    def _parse_field(self, parent, field):
+        if isinstance(field, Callback):
+            self._parse_callback(field)
+
+    def _parse_params(self, parent, params, block):
+        for param in params:
+            self._parse_param(parent, param, block)
+
+    def _parse_return(self, parent, return_, block):
+        tag = self._get_tag(block, 'Returns')
+        options = getattr(tag, 'options', {})
+        self._parse_param_ret_common(parent, return_, options)
+
+    def _parse_param(self, parent, param, block):
+        tag = self._get_tag(block, param.name)
+        options = getattr(tag, 'options', {})
+
+        if isinstance(parent, Function):
+            scope = options.get('scope')
+            if scope:
+                param.scope = scope.one()
+                param.transfer = PARAM_TRANSFER_NONE
+        self._parse_param_ret_common(parent, param, options)
+
+    def _parse_param_ret_common(self, parent, node, options):
+        node.direction = self._extract_direction(node, options)
+        container_type = self._extract_container_type(
+            parent, node, options)
+        if container_type is not None:
+            node.type = container_type
+        if not node.direction:
+            node.direction = self._guess_direction(node)
+        node.transfer = self._extract_transfer(parent, node, options)
+        if 'allow-none' in options:
+            node.allow_none = True
+
+        assert node.transfer is not None
+
+    def _extract_direction(self, node, options):
+        if ('inout' in options or
+            'in-out' in options):
+            direction = PARAM_DIRECTION_INOUT
+        elif 'out' in options:
+            direction = PARAM_DIRECTION_OUT
+        elif 'in' in options:
+            direction = PARAM_DIRECTION_IN
+        else:
+            direction = node.direction
+        return direction
+
+    def _guess_array(self, node):
+        ctype = node.type.ctype
+        if ctype is None:
+            return False
+        if not ctype.endswith('*'):
+            return False
+        if node.type.canonical in default_array_types:
+            return True
+        return False
+
+    def _extract_container_type(self, parent, node, options):
+        has_element_type = 'element-type' in options
+        has_array = 'array' in options
+
+        # FIXME: This is a hack :-(
+        if (not isinstance(node, Field) and
+            (not has_element_type and
+             (node.direction is None
+              or node.direction == PARAM_DIRECTION_IN))):
+            if self._guess_array(node):
+                has_array = True
+
+        if has_array:
+            container_type = self._parse_array(parent, node, options)
+        elif has_element_type:
+            container_type = self._parse_element_type(parent, node, options)
+        else:
+            container_type = None
+
+        return container_type
+
+    def _parse_array(self, parent, node, options):
+        array_opt = options.get('array')
+        if array_opt:
+            values = array_opt.all()
+        else:
+            values = {}
+        container_type = Array(node.type.ctype, node.type.name)
+        if 'zero-terminated' in values:
+            container_type.zeroterminated = values.get(
+                'zero-terminated') == '1'
+        length = values.get('length')
+        if length is not None:
+            param_index = parent.get_parameter_index(length)
+            container_type.length_param_index = param_index
+        container_type.size = values.get('fized-size')
+        return container_type
+
+    def _parse_element_type(self, parent, node, options):
+        element_type_opt = options.get('element-type')
+        element_type = element_type_opt.flat()
+        if node.type.name in ['GLib.List', 'GLib.SList']:
+            assert len(element_type) == 1
+            etype = Type(element_type[0])
+            container_type = List(
+                node.type.name,
+                node.type.ctype,
+                self._transformer.resolve_param_type(etype))
+        elif node.type.name in ['GLib.HashTable']:
+            assert len(element_type) == 2
+            key_type = Type(element_type[0])
+            value_type = Type(element_type[1])
+            container_type = Map(
+                node.type.name,
+                node.type.ctype,
+                self._transformer.resolve_param_type(key_type),
+                self._transformer.resolve_param_type(value_type))
+        else:
+            print 'FIXME: unhandled element-type container:', node
+        return container_type
+
+    def _extract_transfer(self, parent, node, options):
+        transfer_opt = options.get('transfer')
+        if transfer_opt is None:
+            transfer = self._guess_transfer(node, options)
+        else:
+            transfer = transfer_opt.one()
+            if transfer is None:
+                transfer = PARAM_TRANSFER_FULL
+            if transfer not in [PARAM_TRANSFER_NONE,
+                                PARAM_TRANSFER_CONTAINER,
+                                PARAM_TRANSFER_FULL]:
+                raise InvalidAnnotationError(
+                    "transfer for %s of %r is invalid (%r), must be one of "
+                    "none, container, full." % (node, parent.name, transfer))
+        return transfer
+
+    def _parse_version(self, node, block):
+        since_tag = self._get_tag(block, 'Since')
+        if since_tag is None:
+            return
+        node.version = since_tag.value
+
+    def _parse_deprecated(self, node, block):
+        deprecated_tag = self._get_tag(block, 'Deprecated')
+        if deprecated_tag is None:
+            return
+        value = deprecated_tag.value
+        if ': ' in value:
+            version, desc = value.split(': ')
+        else:
+            desc = value
+            version = None
+        node.deprecated = desc
+        if version is not None:
+            node.deprecated_version = version
+
+    def _guess_direction(self, node):
+        if node.direction:
+            return node.direction
+        is_pointer = False
+        if node.type.ctype:
+            is_pointer = '*' in node.type.ctype
+
+        if is_pointer and node.type.name in BASIC_GIR_TYPES:
+            return PARAM_DIRECTION_OUT
+
+        return PARAM_DIRECTION_IN
+
+    def _guess_transfer(self, node, options):
+        if node.transfer is not None:
+            return node.transfer
+
+        if isinstance(node.type, Array):
+            return PARAM_TRANSFER_NONE
+        # Anything with 'const' gets none
+        if node.type.is_const:
+            return PARAM_TRANSFER_NONE
+
+        elif node.type.name in [TYPE_NONE, TYPE_ANY]:
+            return PARAM_TRANSFER_NONE
+        elif isinstance(node.type, Varargs):
+            return PARAM_TRANSFER_NONE
+        elif isinstance(node, Parameter):
+            if node.direction in [PARAM_DIRECTION_INOUT,
+                                  PARAM_DIRECTION_OUT]:
+                return PARAM_TRANSFER_FULL
+            # This one is a hack for compatibility; the transfer
+            # for string parameters really has no defined meaning.
+            elif node.type.canonical == 'utf8':
+                return PARAM_TRANSFER_FULL
+            else:
+                return PARAM_TRANSFER_NONE
+        elif isinstance(node, Return):
+            if (node.type.canonical in BASIC_GIR_TYPES or
+                (node.type.canonical in [TYPE_NONE, TYPE_ANY] and
+                 node.type.is_const)):
+                return PARAM_TRANSFER_NONE
+            else:
+                return PARAM_TRANSFER_FULL
+        elif isinstance(node, Field):
+            return PARAM_TRANSFER_NONE
+        else:
+            raise AssertionError(node)
index 6bd858b..c5dc436 100644 (file)
@@ -200,6 +200,17 @@ class Function(Node):
         self.parameters = parameters
         self.symbol = symbol
         self.throws = not not throws
+        self.is_method = False
+
+    def get_parameter_index(self, name):
+        for i, parameter in enumerate(self.parameters):
+            if parameter.name == name:
+                return i + int(self.is_method)
+
+    def get_parameter(self, name):
+        for parameter in self.parameters:
+            if parameter.name == name:
+                return parameter
 
     def __repr__(self):
         return '%s(%r, %r, %r)' % (self.__class__.__name__,
@@ -217,6 +228,9 @@ class Type(Node):
         Node.__init__(self, name)
         self.ctype = ctype
         self.resolved = False
+        self.is_const = False
+        self.canonical = None
+        self.derefed_canonical = None
 
 
 class Varargs(Type):
@@ -236,7 +250,7 @@ class Array(Type):
         self.size = None
 
     def __repr__(self):
-        return 'Array(%r of %r)' % (self.name, self.element_type, )
+        return 'Array(%r, %r)' % (self.name, self.element_type, )
 
 
 class List(Type):
@@ -282,22 +296,19 @@ class TypeContainer(Node):
         else:
             self.transfer = None
 
-        # transformer.py overrides this as needed
-        self.transfer_inferred = False
-
 
 class Parameter(TypeContainer):
 
-    def __init__(self, name, typenode, direction=PARAM_DIRECTION_IN,
+    def __init__(self, name, typenode, direction=None,
                  transfer=None, allow_none=False, scope=None):
         TypeContainer.__init__(self, name, typenode, transfer)
         if direction in [PARAM_DIRECTION_IN, PARAM_DIRECTION_OUT,
-                         PARAM_DIRECTION_INOUT]:
+                         PARAM_DIRECTION_INOUT, None]:
             self.direction = direction
         else:
             self.direction = PARAM_DIRECTION_IN
 
-        self.allow_none = not not allow_none
+        self.allow_none = allow_none
         self.scope = scope
         self.closure_index = -1
         self.destroy_index = -1
@@ -328,7 +339,7 @@ class Member(Node):
         return 'Member(%r, %r)' % (self.name, self.value)
 
 
-class Struct(Node):
+class Record(Node):
 
     def __init__(self, name, symbol, disguised=False):
         Node.__init__(self, name)
@@ -337,6 +348,9 @@ class Struct(Node):
         self.symbol = symbol
         self.disguised = disguised
 
+# BW compat, remove
+Struct = Record
+
 
 class Field(Node):
 
@@ -359,6 +373,7 @@ class Return(TypeContainer):
 
     def __init__(self, rtype, transfer=None):
         TypeContainer.__init__(self, None, rtype, transfer)
+        self.direction = PARAM_DIRECTION_OUT
 
     def __repr__(self):
         return 'Return(%r)' % (self.type, )
@@ -431,6 +446,7 @@ class Property(Node):
 
 # FIXME: Inherit from Function
 
+
 class Callback(Node):
 
     def __init__(self, name, retval, parameters, ctype=None):
index c85ae80..45dcc25 100644 (file)
@@ -88,6 +88,7 @@ class DumpCompiler(object):
             self._packages.append('gobject-introspection-1.0')
 
     # Public API
+
     def run(self):
         c_path = self._generate_tempfile('.c')
         f = open(c_path, 'w')
@@ -112,6 +113,7 @@ class DumpCompiler(object):
         return IntrospectionBinary([bin_path], self._tmpdir)
 
     # Private API
+
     def _generate_tempfile(self, suffix=''):
         tmpl = '%s-%s%s' % (self._options.namespace_name,
                             self._options.namespace_version, suffix)
index 17f5352..3e2432e 100644 (file)
@@ -53,6 +53,7 @@ class GIRParser(object):
         self._namespace = None
 
     # Public API
+
     def parse(self, filename):
         tree = parse(filename)
         self.parse_tree(tree)
@@ -79,6 +80,7 @@ class GIRParser(object):
         self._include_parsing = include_parsing
 
     # Private
+
     def _add_node(self, node):
         self._namespace.nodes.append(node)
 
@@ -152,7 +154,9 @@ class GIRParser(object):
         for iface in node.findall(_corens('prerequisites')):
             obj.prerequisities.append(iface.attrib['name'])
         for method in node.findall(_corens('method')):
-            obj.methods.append(self._parse_function_common(method, Function))
+            func = self._parse_function_common(method, Function)
+            func.is_method = True
+            obj.methods.append(func)
         for ctor in node.findall(_corens('constructor')):
             obj.constructors.append(
                 self._parse_function_common(ctor, Function))
@@ -284,8 +288,9 @@ class GIRParser(object):
         if self._include_parsing:
             return
         for method in node.findall(_corens('method')):
-            obj.methods.append(
-                self._parse_function_common(method, Function))
+            func = self._parse_function_common(method, Function)
+            func.is_method = True
+            obj.methods.append(func)
         for ctor in node.findall(_corens('constructor')):
             obj.constructors.append(
                 self._parse_function_common(ctor, Function))
index df1ba09..afa4c29 100644 (file)
@@ -64,11 +64,6 @@ PyTypeObject Py##cname##_Type = {             \
 
 typedef struct {
   PyObject_HEAD
-  GISourceDirective *directive;
-} PyGISourceDirective;
-
-typedef struct {
-  PyObject_HEAD
   GISourceType *type;
 } PyGISourceType;
 
@@ -77,7 +72,6 @@ static PyObject * pygi_source_type_new (GISourceType *type);
 typedef struct {
   PyObject_HEAD
   GISourceSymbol *symbol;
-  PyObject *directives;
 } PyGISourceSymbol;
 
 typedef struct {
@@ -85,76 +79,11 @@ typedef struct {
   GISourceScanner *scanner;
 } PyGISourceScanner;
 
-NEW_CLASS (PyGISourceDirective, "SourceDirective", GISourceDirective);
 NEW_CLASS (PyGISourceSymbol, "SourceSymbol", GISourceSymbol);
 NEW_CLASS (PyGISourceType, "SourceType", GISourceType);
 NEW_CLASS (PyGISourceScanner, "SourceScanner", GISourceScanner);
 
 
-/* Directive */
-
-static PyObject *
-pygi_source_directive_new (GISourceDirective *directive)
-{
-  PyGISourceDirective *self;
-
-  if (directive == NULL)
-    {
-      Py_INCREF (Py_None);
-      return Py_None;
-    }
-    
-  self = (PyGISourceDirective *)PyObject_New (PyGISourceDirective,
-                                             &PyGISourceDirective_Type);
-  self->directive = directive;
-  return (PyObject*)self;
-}
-
-static PyObject *
-directive_get_name (PyGISourceDirective *self,
-                   void                *context)
-{
-  return PyString_FromString (self->directive->name);
-}
-
-static PyObject *
-directive_get_value (PyGISourceDirective *self,
-                    void                *context)
-{
-  return PyString_FromString (self->directive->value);
-}
-
-static PyObject *
-directive_get_options (PyGISourceDirective *self,
-                      void                *context)
-{
-  GSList *l;
-  PyObject *list;
-  int i = 0;
-
-  if (!self->directive)
-    return Py_BuildValue("[]");
-  
-  list = PyList_New (g_slist_length (self->directive->options));
-  
-  for (l = self->directive->options; l; l = l->next)
-    {
-      PyObject *item = PyString_FromString (l->data);
-      PyList_SetItem (list, i++, item);
-      Py_INCREF (item);
-    }
-
-  Py_INCREF (list);
-  return list;
-}
-
-static const PyGetSetDef _PyGISourceDirective_getsets[] = {
-  { "name", (getter)directive_get_name, NULL, NULL},
-  { "value", (getter)directive_get_value, NULL, NULL},
-  { "options", (getter)directive_get_options, NULL, NULL},
-  { 0 }
-};
-
 /* Symbol */
 
 static PyObject *
@@ -222,26 +151,6 @@ symbol_get_const_string (PyGISourceSymbol *self,
   return PyString_FromString (self->symbol->const_string);
 }
 
-static PyObject *
-symbol_get_directives (PyGISourceSymbol *self,
-                      void             *context)
-{
-  if (!self->directives)
-    self->directives = Py_BuildValue("[]");
-  Py_INCREF (self->directives);
-  return self->directives;
-}
-
-static int
-symbol_set_directives (PyGISourceSymbol *self,
-                      PyObject         *value,
-                      void             *context)
-{
-  self->directives = value;
-  Py_INCREF(value);
-  return 0;
-}
-
 static const PyGetSetDef _PyGISourceSymbol_getsets[] = {
   /* int ref_count; */
   { "type", (getter)symbol_get_type, NULL, NULL},
@@ -251,8 +160,6 @@ static const PyGetSetDef _PyGISourceSymbol_getsets[] = {
   /* gboolean const_int_set; */
   { "const_int", (getter)symbol_get_const_int, NULL, NULL},  
   { "const_string", (getter)symbol_get_const_string, NULL, NULL},  
-  { "directives", (getter)symbol_get_directives,
-    (setter)symbol_set_directives, NULL},  
   { 0 }
 };
 
@@ -555,23 +462,18 @@ pygi_source_scanner_get_symbols (PyGISourceScanner *self)
 }
 
 static PyObject *
-pygi_source_scanner_get_directives (PyGISourceScanner *self,
-                                   PyObject          *args)
+pygi_source_scanner_get_comments (PyGISourceScanner *self)
 {
-  GSList *l, *directives;
+  GSList *l, *comments;
   PyObject *list;
   int i = 0;
-  char *name;
-  
-  if (!PyArg_ParseTuple (args, "s:SourceScanner.get_directives", &name))
-    return NULL;
   
-  directives = gi_source_scanner_get_directives (self->scanner, name);
-  list = PyList_New (g_slist_length (directives));
+  comments = gi_source_scanner_get_comments (self->scanner);
+  list = PyList_New (g_slist_length (comments));
   
-  for (l = directives; l; l = l->next)
+  for (l = comments; l; l = l->next)
     {
-      PyObject *item = pygi_source_directive_new (l->data);
+      PyObject *item = PyString_FromString (l->data);
       PyList_SetItem (list, i++, item);
       Py_INCREF (item);
     }
@@ -581,7 +483,7 @@ pygi_source_scanner_get_directives (PyGISourceScanner *self,
 }
 
 static const PyMethodDef _PyGISourceScanner_methods[] = {
-  { "get_directives", (PyCFunction) pygi_source_scanner_get_directives, METH_VARARGS },
+  { "get_comments", (PyCFunction) pygi_source_scanner_get_comments, METH_NOARGS },
   { "get_symbols", (PyCFunction) pygi_source_scanner_get_symbols, METH_NOARGS },
   { "append_filename", (PyCFunction) pygi_source_scanner_append_filename, METH_VARARGS },
   { "parse_file", (PyCFunction) pygi_source_scanner_parse_file, METH_VARARGS },
@@ -611,7 +513,8 @@ static int calc_attrs_length(PyObject *attributes, int indent,
       if (PyTuple_GetItem(tuple, 1) == Py_None)
        continue;
 
-      g_assert(PyArg_ParseTuple(tuple, "ss", &attr, &value));
+      if (!PyArg_ParseTuple(tuple, "ss", &attr, &value))
+        return -1;
       
       escaped = g_markup_escape_text (value, -1);
       attr_length += 2 + strlen(attr) + strlen(escaped) + 2;
@@ -631,6 +534,7 @@ pygi_collect_attributes (PyObject *self,
   char *indent_char;
   gboolean first;
   GString *attr_value;
+  int len;
   
   if (!PyArg_ParseTuple(args, "sOisi",
                        &tag_name, &attributes,
@@ -641,7 +545,10 @@ pygi_collect_attributes (PyObject *self,
   if (attributes == Py_None || !PyList_Size(attributes))
     return PyString_FromString("");
 
-  if (calc_attrs_length(attributes, indent, self_indent) > 79)
+  len = calc_attrs_length(attributes, indent, self_indent);
+  if (len < 0)
+    return NULL;
+  if (len > 79)
     indent_len = self_indent + strlen(tag_name) + 1;
   else
     indent_len = 0;
@@ -660,7 +567,9 @@ pygi_collect_attributes (PyObject *self,
       if (PyTuple_GetItem(tuple, 1) == Py_None)
        continue;
 
-      g_assert(PyArg_ParseTuple(tuple, "ss", &attr, &value));
+      /* this leaks, but we exit after, so */
+      if (!PyArg_ParseTuple(tuple, "ss", &attr, &value))
+        return NULL;
 
       if (indent_len && !first)
        {
@@ -699,9 +608,6 @@ init_giscanner(void)
                       (PyMethodDef*)pyscanner_functions);
     d = PyModule_GetDict (m);
 
-    PyGISourceDirective_Type.tp_getset = (PyGetSetDef*)_PyGISourceDirective_getsets;
-    REGISTER_TYPE (d, "SourceDirective", PyGISourceDirective_Type);
-
     PyGISourceScanner_Type.tp_init = (initproc)pygi_source_scanner_init;
     PyGISourceScanner_Type.tp_methods = (PyMethodDef*)_PyGISourceScanner_methods;
     REGISTER_TYPE (d, "SourceScanner", PyGISourceScanner_Type);
index aacaa50..ee39862 100644 (file)
@@ -28,7 +28,7 @@ import subprocess
 from .ast import (Callback, Constant, Enum, Function, Member, Namespace,
                   Parameter, Property, Return, Struct, Type, Alias,
                   Union, Field, type_name_from_ctype,
-                  default_array_types, TYPE_UINT8, PARAM_DIRECTION_IN)
+                  default_array_types, TYPE_UINT8, PARAM_TRANSFER_FULL)
 from .transformer import Names
 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
                       GLibInterface, GLibObject, GLibSignal, GLibBoxedStruct,
@@ -85,8 +85,6 @@ class GLibTransformer(object):
     def __init__(self, transformer, noclosure=False):
         self._transformer = transformer
         self._noclosure = noclosure
-        self._transformer.set_container_types(['GList*', 'GSList*'],
-                                              ['GHashTable*'])
         self._namespace_name = None
         self._names = Names()
         self._uscore_type_names = {}
@@ -99,6 +97,7 @@ class GLibTransformer(object):
         self._validating = False
 
     # Public API
+
     def set_introspection_binary(self, binary):
         self._binary = binary
 
@@ -165,6 +164,7 @@ class GLibTransformer(object):
         return namespace
 
     # Private
+
     def _add_attribute(self, node, replace=False):
         node_name = node.name
         if (not replace) and node_name in self._names.names:
@@ -203,6 +203,7 @@ class GLibTransformer(object):
         self._uscore_type_names[no_uscore_prefixed] = node
 
     # Helper functions
+
     def _resolve_gtypename(self, gtype_name):
         try:
             return self._transformer.gtypename_to_giname(gtype_name,
@@ -254,6 +255,7 @@ class GLibTransformer(object):
         self._register_internal_type(type_name, gnode)
 
     # Parser
+
     def _parse_node(self, node):
         if isinstance(node, Enum):
             self._parse_enum(node)
@@ -345,6 +347,7 @@ class GLibTransformer(object):
         self._remove_attribute(func.name)
         func.name = methname
         target_klass.static_methods.append(func)
+        func.is_method = True
         return func
 
     def _parse_method(self, func):
@@ -431,6 +434,7 @@ class GLibTransformer(object):
             # We don't need the "this" parameter
             del func.parameters[0]
             klass.methods.append(func)
+            func.is_method = True
         else:
             klass.constructors.append(func)
         return func
@@ -512,6 +516,7 @@ class GLibTransformer(object):
             del self._names.names[maybe_class.name]
 
     # Introspection
+
     def _introspect_type(self, xmlnode):
         if xmlnode.tag in ('enum', 'flags'):
             self._introspect_enum(xmlnode)
@@ -627,7 +632,7 @@ class GLibTransformer(object):
             rctype = signal_info.attrib['return']
             rtype = Type(self._transformer.parse_ctype(rctype), rctype)
             return_ = Return(rtype, signal_info.attrib['return'])
-            return_.transfer = 'full'
+            return_.transfer = PARAM_TRANSFER_FULL
             signal = GLibSignal(signal_info.attrib['name'], return_)
             for i, parameter in enumerate(signal_info.findall('param')):
                 if i == 0:
@@ -642,6 +647,7 @@ class GLibTransformer(object):
             node.signals.append(signal)
 
     # Resolver
+
     def _resolve_type_name(self, type_name, ctype=None):
         # Workaround glib bug #548689, to be included in 2.18.0
         if type_name == "GParam":
@@ -784,25 +790,6 @@ class GLibTransformer(object):
     def _resolve_property(self, prop):
         prop.type = self._resolve_param_type(prop.type, allow_invalid=False)
 
-    def _adjust_transfer(self, param):
-        if not (param.transfer is None or param.transfer_inferred):
-            return
-
-        # Do GLib/GObject-specific type transformations here
-        node = self._lookup_node(param.type.name)
-        if node is None:
-            return
-
-        if isinstance(param, Parameter):
-            if param.direction != PARAM_DIRECTION_IN:
-                transfer = 'full'
-            else:
-                transfer = 'none'
-        else:
-            transfer = 'full'
-
-        param.transfer = transfer
-
     def _adjust_throws(self, func):
         if func.parameters == []:
             return
@@ -820,12 +807,10 @@ class GLibTransformer(object):
         self._resolve_parameters(func.parameters)
         func.retval.type = self._resolve_param_type(func.retval.type)
         self._adjust_throws(func)
-        self._adjust_transfer(func.retval)
 
     def _resolve_parameters(self, parameters):
         for parameter in parameters:
             parameter.type = self._resolve_param_type(parameter.type)
-            self._adjust_transfer(parameter)
 
     def _resolve_field(self, field):
         if isinstance(field, Callback):
@@ -837,6 +822,7 @@ class GLibTransformer(object):
         alias.target = self._resolve_type_name(alias.target, alias.target)
 
     # Validation
+
     def _validate(self, nodes):
         nodes = list(self._names.names.itervalues())
         i = 0
index 27072cd..53603e2 100644 (file)
@@ -200,187 +200,27 @@ yywrap (void)
 
 
 static void
-parse_gtkdoc (GISourceScanner *scanner,
-             gchar           *symbol,
-             int             *c1,
-             int             *c2)
-{
-  gboolean isline = FALSE;
-  GString *line_buf;
-  char *line;
-  gchar **parts;
-  GISourceDirective *directive;
-  char *name,*value;
-  GSList *directives;
-  GSList *options = NULL;
-  char *rname;
-  int n_parts;
-
-  line_buf = g_string_new ("");
-
-  do 
-    {
-      *c1 = *c2;
-      if (*c1 == '\n')
-        {
-          isline = TRUE;
-          break;
-        }
-      g_string_append_c (line_buf, *c1);
-      *c2 = input();
-    } while (*c2 != EOF && !(*c1 == '*' && *c2 == '/'));
-  
-  if (!isline)
-    {
-      g_string_free (line_buf, TRUE);
-      return;
-    }
-
-  line = g_string_free (line_buf, FALSE);
-
-  /* Ignore lines that don't have a : - this is a hack but avoids
-   * trying to parse too many things as annotations
-   */
-  if (!strchr (line, ':'))
-    {
-      g_free (line);
-      return;
-    }
-
-  parts = g_strsplit (line, ":", 3);
-  n_parts = g_strv_length (parts);
-
-  if (g_ascii_strcasecmp (parts[0], "eprecated") == 0)
-    {
-      if (n_parts == 3)
-       options = g_slist_prepend (options, g_strdup_printf ("%s: %s", parts[1], parts[2]));
-      else if (n_parts == 2)
-       options = g_slist_prepend (options, g_strdup (parts[1]));
-      else
-       options = g_slist_prepend (options, g_strdup (""));
-      name = parts[0];
-      value = NULL;
-    }
-  else if (g_ascii_strcasecmp (parts[0], "ince") == 0)
-    {
-      if (n_parts == 2)
-       options = g_slist_prepend (options, g_strdup (parts[1]));
-      else
-       options = g_slist_prepend (options, g_strdup (""));
-      name = parts[0];
-      value = NULL;
-    }
-  else if (n_parts >= 2)
-    {
-      name = parts[0];
-
-      if (n_parts == 3) 
-        {
-          char *ptr = g_strdup (parts[1]);
-         char *start;
-         char *end;
-
-         options = NULL;
-         start = strchr (ptr, '(');
-         while (start != NULL) 
-           {
-             end = strchr (start, ')');
-             if (end)
-               {
-                 options = g_slist_prepend (options, g_strndup (start+1, end-(start+1)));
-                 start = strchr (end+1, '(');
-               }
-             else
-               {
-                 break;
-               }
-           }
-         g_free (ptr);
-          value = parts[2];
-        } 
-      else
-        value = parts[1];
-    }
-  else /* parts == 1 */
-    {
-      name = parts[0];
-      value = NULL;
-    }
-
-  /*
-   * Special cases for global annotations.
-   * Context-sensitive parsing would probably be the right way to go.
-   */
-  if (g_ascii_strncasecmp ("eturn", name, 5) == 0)
-    rname = "return";
-  else if (g_ascii_strncasecmp ("eprecated", name, 9) == 0)
-    rname = "deprecated";
-  else if (g_ascii_strncasecmp ("ince", name, 4) == 0)
-    rname = "since";
-  else
-    rname = name;
-
-  directive = gi_source_directive_new (rname, value, options);
-  directives = g_hash_table_lookup (scanner->directives_map, symbol);
-  directives = g_slist_prepend (directives, directive);
-  g_hash_table_replace (scanner->directives_map,
-                       g_strdup (symbol), directives);
-
-  g_strfreev (parts);
-  g_free (line);
-}
-
-
-static void
 parse_comment (GISourceScanner *scanner)
 {
-  GString *symbol = NULL;
-  gboolean startofline = FALSE, have_symbol = FALSE, start1 = FALSE, start_symbol = FALSE;
+  GString *comment;
   int c1, c2;
 
   c1 = input();
   c2 = input();
 
+  comment = g_string_new ("");
+
   while (c2 != EOF && !(c1 == '*' && c2 == '/'))
     {
-      if (c1 == ':')
-        have_symbol = TRUE;
-      else if (c1 == '\n')
-         start1 = TRUE;
-      else if (c1 == '*' && start1)
-         start_symbol = TRUE;
-      else if (!have_symbol && start_symbol) 
-        {
-          if (!symbol)
-            symbol = g_string_new ("");
-          if (c1 != ' ')
-            g_string_append_c (symbol, c1);
-        }
-
-      if (c1 == '\n') 
-        {
-          ++lineno;
-          startofline = TRUE;
-        }
+      g_string_append_c (comment, c1);
 
       c1 = c2;
       c2 = input();
 
-      if ((c1 != '*' && c1 != ' '))
-          startofline = FALSE;
-
-      if (startofline && (c1 == ' ') && ((c2 == '@') || (c2 == 'r') || (c2 == 'R') || (c2 == 'D') || (c2 == 'S')))
-        {
-           c1 = c2;
-           c2 = input();
-           if (symbol)
-             parse_gtkdoc (scanner, symbol->str, &c1, &c2);
-        }
     }
 
-  if (symbol)
-    g_string_free (symbol, TRUE);
-  
+  scanner->comments = g_slist_prepend (scanner->comments,
+                                       g_string_free (comment, FALSE));
 }
 
 static int
index 08f4b58..cf41236 100644 (file)
@@ -60,8 +60,6 @@ gi_source_symbol_unref (GISourceSymbol * symbol)
       if (symbol->base_type)
         ctype_free (symbol->base_type);
       g_free (symbol->const_string);
-      g_slist_foreach (symbol->directives, (GFunc)gi_source_directive_free, NULL);
-      g_slist_free (symbol->directives);
       g_slice_free (GISourceSymbol, symbol);
     }
 }
@@ -178,28 +176,6 @@ gi_source_function_new (void)
   return func;
 }
 
-GISourceDirective *
-gi_source_directive_new (const gchar *name,
-                        const gchar *value,
-                        GSList *options)
-{
-  GISourceDirective *directive;
-    
-  directive = g_slice_new (GISourceDirective);
-  directive->name = g_strdup (name);
-  directive->value = g_strdup (value);
-  directive->options = options;
-  return directive;
-}
-
-void
-gi_source_directive_free (GISourceDirective *directive)
-{
-  g_free (directive->name);
-  g_free (directive->value);
-  g_slice_free (GISourceDirective, directive);
-}
-
 GISourceScanner *
 gi_source_scanner_new (void)
 {
@@ -208,7 +184,6 @@ gi_source_scanner_new (void)
   scanner = g_slice_new0 (GISourceScanner);
   scanner->typedef_table = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                  g_free, NULL);
-  scanner->directives_map = g_hash_table_new (g_str_hash, g_str_equal);
   scanner->struct_or_union_or_enum_table =
     g_hash_table_new_full (g_str_hash, g_str_equal,
                           g_free, (GDestroyNotify)gi_source_symbol_unref);
@@ -221,10 +196,11 @@ gi_source_scanner_free (GISourceScanner *scanner)
 {
   g_free (scanner->current_filename);
 
-  g_hash_table_destroy (scanner->directives_map);
   g_hash_table_destroy (scanner->typedef_table);
   g_hash_table_destroy (scanner->struct_or_union_or_enum_table);
 
+  g_slist_foreach (scanner->comments, (GFunc)g_free, NULL);
+  g_slist_free (scanner->comments);
   g_slist_foreach (scanner->symbols, (GFunc)gi_source_symbol_unref, NULL);
   g_slist_free (scanner->symbols);
 
@@ -295,8 +271,7 @@ gi_source_scanner_get_symbols (GISourceScanner  *scanner)
 }
 
 GSList *
-gi_source_scanner_get_directives(GISourceScanner  *scanner,
-                                const gchar      *name)
+gi_source_scanner_get_comments(GISourceScanner  *scanner)
 {
-  return g_hash_table_lookup (scanner->directives_map, name);
+  return g_slist_reverse (scanner->comments);
 }
index 3a391d8..69417d1 100644 (file)
@@ -31,7 +31,6 @@ G_BEGIN_DECLS
 typedef struct _GISourceScanner GISourceScanner;
 typedef struct _GISourceSymbol GISourceSymbol;
 typedef struct _GISourceType GISourceType;
-typedef struct _GISourceDirective GISourceDirective;
 
 typedef enum
 {
@@ -102,7 +101,7 @@ struct _GISourceScanner
   gboolean macro_scan;
   GSList *symbols;
   GList *filenames;
-  GHashTable *directives_map;
+  GSList *comments;
   GHashTable *typedef_table;
   GHashTable *struct_or_union_or_enum_table;
 };
@@ -117,7 +116,6 @@ struct _GISourceSymbol
   gboolean const_int_set;
   int const_int;
   char *const_string;
-  GSList *directives; /* list of GISourceDirective */
 };
 
 struct _GISourceType
@@ -131,13 +129,6 @@ struct _GISourceType
   GList *child_list; /* list of GISourceSymbol */
 };
 
-struct _GISourceDirective
-{
-  char *name;
-  char *value;
-  GSList *options; /* list of options (key=value) */
-};
-
 GISourceScanner *   gi_source_scanner_new              (void);
 gboolean            gi_source_scanner_lex_filename     (GISourceScanner  *igenerator,
                                                        const gchar      *filename);
@@ -148,8 +139,7 @@ void                gi_source_scanner_parse_macros     (GISourceScanner  *scanne
 void                gi_source_scanner_set_macro_scan   (GISourceScanner  *scanner,
                                                        gboolean          macro_scan);
 GSList *            gi_source_scanner_get_symbols      (GISourceScanner  *scanner);
-GSList *            gi_source_scanner_get_directives   (GISourceScanner  *scanner,
-                                                       const gchar      *name);
+GSList *            gi_source_scanner_get_comments     (GISourceScanner  *scanner);
 void                gi_source_scanner_free             (GISourceScanner  *scanner);
 
 GISourceSymbol *    gi_source_symbol_new               (GISourceSymbolType  type);
@@ -157,11 +147,6 @@ gboolean            gi_source_symbol_get_const_boolean (GISourceSymbol     *symb
 GISourceSymbol *    gi_source_symbol_ref               (GISourceSymbol     *symbol);
 void                gi_source_symbol_unref             (GISourceSymbol     *symbol);
 
-GISourceDirective * gi_source_directive_new            (const gchar       *name,
-                                                       const gchar        *value,
-                                                       GSList             *options);
-void                gi_source_directive_free           (GISourceDirective  *directive);
-
 /* Private */
 void                gi_source_scanner_add_symbol       (GISourceScanner  *scanner,
                                                        GISourceSymbol   *symbol);
index 3188b26..5018bf4 100644 (file)
@@ -154,12 +154,6 @@ class SourceSymbol(object):
             symbol_type_name(self.type),
             self.ident)
 
-    def directives(self):
-        mapping = {}
-        for directive in self._scanner.get_directives(self._symbol.ident):
-            mapping[directive.name] = directive.options
-        return mapping
-
     @property
     def const_int(self):
         return self._symbol.const_int
@@ -192,6 +186,7 @@ class SourceScanner(object):
         self._cpp_options = []
 
     # Public API
+
     def set_cpp_options(self, includes, defines, undefines):
         for prefix, args in [('-I', includes),
                              ('-D', defines),
@@ -226,12 +221,16 @@ class SourceScanner(object):
         for symbol in self._scanner.get_symbols():
             yield SourceSymbol(self._scanner, symbol)
 
+    def get_comments(self):
+        return self._scanner.get_comments()
+
     def dump(self):
         print '-'*30
         for symbol in self._scanner.get_symbols():
             print symbol.ident, symbol.base_type.name, symbol.type
 
     # Private
+
     def _parse(self, filenames):
         if not filenames:
             return
index 0ed7ca0..7493a35 100644 (file)
 #
 
 import os
-import re
 
 from .ast import (Callback, Enum, Function, Namespace, Member,
-                  Parameter, Return, Array, Struct, Field,
-                  Type, Alias, Interface, Class, Node, Union,
-                  List, Map, Varargs, Constant, type_name_from_ctype,
-                  type_names, default_array_types, default_out_types,
-                  TYPE_STRING, BASIC_GIR_TYPES, TYPE_NONE)
+                  Parameter, Return, Struct, Field,
+                  Type, Array, Alias, Interface, Class, Node, Union,
+                  Varargs, Constant, type_name_from_ctype,
+                  type_names, TYPE_STRING, BASIC_GIR_TYPES)
 from .config import DATADIR
 from .glibast import GLibBoxed
 from .girparser import GIRParser
@@ -75,8 +73,6 @@ class Transformer(object):
         self._strip_prefix = ''
         self._includes = set()
         self._includepaths = []
-        self._list_ctypes = []
-        self._map_ctypes = []
 
     def get_names(self):
         return self._names
@@ -84,10 +80,6 @@ class Transformer(object):
     def get_includes(self):
         return self._includes
 
-    def set_container_types(self, list_ctypes, map_ctypes):
-        self._list_ctypes = list_ctypes
-        self._map_ctypes = map_ctypes
-
     def set_strip_prefix(self, strip_prefix):
         self._strip_prefix = strip_prefix
 
@@ -109,6 +101,7 @@ class Transformer(object):
         self._includes.add(include)
 
     # Private
+
     def _find_include(self, include):
         searchdirs = self._includepaths[:]
         for path in _xdg_data_dirs:
@@ -210,7 +203,6 @@ class Transformer(object):
 
     def _create_enum(self, symbol):
         members = []
-        directives = symbol.directives()
         for child in symbol.base_type.child_list:
             name = strip_common_prefix(symbol.ident, child.ident).lower()
             members.append(Member(name,
@@ -219,7 +211,6 @@ class Transformer(object):
 
         enum_name = self.remove_prefix(symbol.ident)
         enum = Enum(enum_name, symbol.ident, members)
-        self._parse_version(enum, directives)
         self._names.type_names[symbol.ident] = (None, enum)
         return enum
 
@@ -227,48 +218,6 @@ class Transformer(object):
         return Member(symbol.ident, symbol.base_type.name,
                       symbol.ident)
 
-    def _parse_deprecated(self, node, directives):
-        deprecated = directives.get('deprecated', False)
-        if deprecated:
-            deprecated_value = deprecated[0]
-            if ':' in deprecated_value:
-                # Split out gtk-doc version
-                (node.deprecated_version, node.deprecated) = \
-                    [x.strip() for x in deprecated_value.split(':', 1)]
-            else:
-                # No version, just include str
-                node.deprecated = deprecated_value.strip()
-
-    def _parse_version(self, node, directives):
-        version = directives.get('since', False)
-        if version:
-            version_value = version[0]
-            node.version = version_value.strip()
-
-    def _pair_array(self, params, array):
-        if not array.type.length_param_name:
-            return
-        target_name = array.type.length_param_name
-        for i, param in enumerate(params):
-            if param.name == array.type.length_param_name:
-                array.type.length_param_index = i
-                return
-        raise ValueError("Unmatched length parameter name %r"\
-                             % (target_name, ))
-
-    def _pair_annotations(self, params, return_):
-        names = {}
-        for param in params:
-            if param.name in names:
-                raise ValueError("Duplicate parameter name %r"\
-                                     % (param.name, ))
-            names[param.name] = 1
-            if isinstance(param.type, Array):
-                self._pair_array(params, param)
-
-        if isinstance(return_.type, Array):
-            self._pair_array(params, return_)
-
     def _type_is_callback(self, type):
         if (isinstance(type, Callback) or
             isinstance(self._typedefs_ns.get(type.name), Callback)):
@@ -294,50 +243,35 @@ class Transformer(object):
 
     def _augment_callback_params(self, params):
         for i, param in enumerate(params):
-            if self._type_is_callback(param.type):
-                # j is the index where we look for closure/destroy to
-                # group with the callback param
-                j = i + 1
-                if j == len(params):
-                    continue # no more args -> nothing to group look
-                # at the param directly following for either a closure
-                # or a destroy; only one of these will fire
-                had_closure = self._handle_closure(param, j, params[j])
-                had_destroy = self._handle_destroy(param, j, params[j])
-                j += 1
-                # are we out of params, or did we find neither?
-                if j == len(params) or (not had_closure and not had_destroy):
-                    continue
-                # we found either a closure or a destroy; check the
-                # parameter following for the other
-                if not had_closure:
-                    self._handle_closure(param, j, params[j])
-                if not had_destroy:
-                    self._handle_destroy(param, j, params[j])
-
-    # We take the annotations from the parser as strings; here we
-    # want to split them into components, so:
-    # (transfer full) -> {'transfer' : [ 'full' ]}
-    def _parse_options(self, options):
-        ret = {}
-        ws_re = re.compile(r'\s+')
-        for opt in options:
-            items = ws_re.split(opt)
-            ret[items[0]] = items[1:]
-        return ret
+            if not self._type_is_callback(param.type):
+                continue
+
+            # j is the index where we look for closure/destroy to
+            # group with the callback param
+            j = i + 1
+            if j == len(params):
+                continue # no more args -> nothing to group look
+            # at the param directly following for either a closure
+            # or a destroy; only one of these will fire
+            had_closure = self._handle_closure(param, j, params[j])
+            had_destroy = self._handle_destroy(param, j, params[j])
+            j += 1
+            # are we out of params, or did we find neither?
+            if j == len(params) or (not had_closure and not had_destroy):
+                continue
+            # we found either a closure or a destroy; check the
+            # parameter following for the other
+            if not had_closure:
+                self._handle_closure(param, j, params[j])
+            if not had_destroy:
+                self._handle_destroy(param, j, params[j])
 
     def _create_function(self, symbol):
-        directives = symbol.directives()
-        parameters = list(self._create_parameters(
-            symbol.base_type, directives))
-        return_ = self._create_return(symbol.base_type.base_type,
-                                      directives.get('return', {}))
+        parameters = list(self._create_parameters(symbol.base_type))
+        return_ = self._create_return(symbol.base_type.base_type)
         self._augment_callback_params(parameters)
-        self._pair_annotations(parameters, return_)
         name = self._strip_namespace_func(symbol.ident)
         func = Function(name, return_, parameters, symbol.ident)
-        self._parse_version(func, directives)
-        self._parse_deprecated(func, directives)
         return func
 
     def _create_source_type(self, source_type):
@@ -357,47 +291,42 @@ class Transformer(object):
             value = 'any'
         return value
 
-    def _create_parameters(self, base_type, directives=None):
-        if directives is None:
-            dirs = {}
-        else:
-            dirs = directives
+    def _create_parameters(self, base_type):
 
         # warn if we see annotations for unknown parameters
         param_names = set(child.ident for child in base_type.child_list)
-        dirs_for = set(dirs)
-        dirs_for = dirs_for.difference(param_names)
-        dirs_for.discard('return')
-        dirs_for.discard('deprecated')
-        dirs_for.discard('since')
-        if dirs_for:
-            print 'Unexpected annotations for %s, parameters are %s' % (
-                list(dirs_for), list(param_names), )
-
         for child in base_type.child_list:
-            yield self._create_parameter(
-                child, dirs.get(child.ident, {}))
+            yield self._create_parameter(child)
 
     def _create_member(self, symbol):
-        ctype = symbol.base_type.type
-        if (ctype == CTYPE_POINTER and
+        source_type = symbol.base_type
+        if (source_type.type == CTYPE_POINTER and
             symbol.base_type.base_type.type == CTYPE_FUNCTION):
             node = self._create_callback(symbol)
         else:
-            opts = {}
-            if ctype == CTYPE_ARRAY:
-                opts['array'] = []
+            # Special handling for fields; we don't have annotations on them
+            # to apply later, yet.
+            if source_type.type == CTYPE_ARRAY:
+                ctype = self._create_source_type(source_type)
+                canonical_ctype = self._canonicalize_ctype(ctype)
+                if canonical_ctype[-1] == '*':
+                    derefed_name = canonical_ctype[:-1]
+                else:
+                    derefed_name = canonical_ctype
+                derefed_name = self.resolve_param_type(derefed_name)
+                ftype = Array(ctype, self.parse_ctype(derefed_name))
                 child_list = list(symbol.base_type.child_list)
+                ftype.zeroterminated = False
                 if child_list:
-                    size_opt = 'fixed-size=%d' % (child_list[0].const_int, )
-                    opts['array'].append(size_opt)
-            ftype = self._create_type(symbol.base_type, opts,
-                                      is_param=False, is_retval=False)
+                    ftype.size = '%d' % (child_list[0].const_int, )
+            else:
+                ftype = self._create_type(symbol.base_type,
+                                          is_param=False, is_retval=False)
             ftype = self.resolve_param_type(ftype)
             # Fields are assumed to be read-write
             # (except for Objects, see also glibtransformer.py)
-            node = Field(symbol.ident, ftype, symbol.ident,
-                       readable=True, writable=True, bits=symbol.const_int)
+            node = Field(symbol.ident, ftype, ftype.name,
+                         readable=True, writable=True, bits=symbol.const_int)
         return node
 
     def _create_typedef(self, symbol):
@@ -473,7 +402,7 @@ class Transformer(object):
         else:
             return derefed_typename
 
-    def _create_type(self, source_type, options, is_param, is_retval):
+    def _create_type(self, source_type, is_param, is_retval):
         ctype = self._create_source_type(source_type)
         if ctype == 'va_list':
             raise SkipError()
@@ -482,188 +411,37 @@ class Transformer(object):
         elif ctype == 'FILE*':
             raise SkipError
 
-        canonical_ctype = self._canonicalize_ctype(ctype)
-
-        # Now check for a list/map/array type
-        if canonical_ctype in self._list_ctypes:
-            param = options.get('element-type')
-            if param:
-                contained_type = self.parse_ctype(param[0])
-            else:
-                contained_type = None
-            derefed_name = self.parse_ctype(ctype)
-            rettype = List(derefed_name,
-                           ctype,
-                           contained_type)
-        elif canonical_ctype in self._map_ctypes:
-            param = options.get('element-type')
-            if param:
-                key_type = self.parse_ctype(param[0])
-                value_type = self.parse_ctype(param[1])
-            else:
-                key_type = None
-                value_type = None
-            derefed_name = self.parse_ctype(ctype)
-            rettype = Map(derefed_name,
-                          ctype,
-                          key_type, value_type)
-        elif ((is_param and canonical_ctype in default_array_types
-               and not 'out' in options)
-              or ('array' in options)):
-            if canonical_ctype[-1] == '*':
-                derefed_name = canonical_ctype[:-1]
-            else:
-                derefed_name = canonical_ctype
-            rettype = Array(ctype,
-                            self.parse_ctype(derefed_name))
-            array_opts = dict([opt.split('=')
-                               for opt in options.get('array', [])])
-            if 'length' in array_opts:
-                rettype.length_param_name = array_opts['length']
-                rettype.zeroterminated = False
-            if 'fixed-size' in array_opts:
-                rettype.size = array_opts['fixed-size']
-                rettype.zeroterminated = False
-            if 'zero-terminated' in array_opts:
-                rettype.zeroterminated = array_opts['zero-terminated'] != '0'
-        else:
-            derefed_name = self.parse_ctype(ctype,
-                                            not (is_param or is_retval))
-            rettype = Type(derefed_name, ctype)
-
-        # Deduce direction for some types passed by reference that
-        # aren't arrays; modifies the options array.
-        if ('array' not in options and
-            not ('out' in options or
-                 'in' in options or
-                 'inout' in options or
-                 'in-out' in options) and
-            source_type.type == CTYPE_POINTER and
-            derefed_name in default_out_types):
-            options['out'] = []
-
-        if 'transfer' in options:
-            # Transfer is specified, we don't question it.
-            return rettype
+        is_member = not (is_param or is_retval)
+        # Here we handle basic type parsing; most of the heavy lifting
+        # and inference comes in annotationparser.py when we merge
+        # in annotation data.
+        derefed_name = self.parse_ctype(ctype, is_member)
+        rettype = Type(derefed_name, ctype)
+        rettype.canonical = self._canonicalize_ctype(ctype)
+        derefed_ctype = ctype.replace('*', '')
+        rettype.derefed_canonical = self._canonicalize_ctype(derefed_ctype)
 
         canontype = type_name_from_ctype(ctype)
-
-        # Since no transfer is specified, we drop into a bunch of
-        # heuristics to guess it.  This mutates the options array to
-        # set the 'transfer' option.
-        # Note that we inferred the transfer
-        options['transfer-inferred'] = []
-        stype = source_type
-        if canontype == TYPE_STRING:
-            # It's a string - we just look at 'const'
-            if source_type.base_type.type_qualifier & TYPE_QUALIFIER_CONST:
-                options['transfer'] = ['none']
-            else:
-                options['transfer'] = ['full']
-        elif 'array' in options or stype.type == CTYPE_ARRAY:
-            # It's rare to mutate arrays in public GObject APIs
-            options['transfer'] = ['none']
-        elif (canontype in BASIC_GIR_TYPES or
-              canontype == TYPE_NONE or
-              stype.type == CTYPE_ENUM):
-            # Basic types default to 'none'
-            options['transfer'] = ['none']
-        elif (stype.type == CTYPE_POINTER and
-              stype.base_type.type_qualifier & TYPE_QUALIFIER_CONST):
-            # Anything with 'const' gets none
-            options['transfer'] = ['none']
-        elif is_param and stype.type == CTYPE_POINTER:
-            # For generic pointer types, let's look at the argument
-            # direction.  An out/inout argument gets full, everything
-            # else none.
-            if ('out' in options or
-                'inout' in options or
-                'in-out' in options):
-                options['transfer'] = ['full']
-            else:
-                options['transfer'] = ['none']
-        else:
-            # For anything else we default to none for parameters;
-            # this covers enums and possibly some other corner cases.
-            # Return values of structures and the like will end up
-            # full.
-            if is_param:
-                options['transfer'] = ['none']
-            else:
-                options['transfer'] = ['full']
-
+        if ((canontype == TYPE_STRING or
+             source_type.type == CTYPE_POINTER) and
+            source_type.base_type.type_qualifier & TYPE_QUALIFIER_CONST):
+            rettype.is_const = True
         return rettype
 
-    def _handle_generic_param_options(self, param, options):
-        for option, data in options.iteritems():
-            if option == 'transfer':
-                if data:
-                    depth = data[0]
-                    if depth not in ('none', 'container', 'full'):
-                        raise ValueError("Invalid transfer %r" % (depth, ))
-                else:
-                    depth = 'full'
-                param.transfer = depth
-            elif option == 'transfer-inferred':
-                # This is a purely internal flag; we don't expect
-                # people to write it
-                param.transfer_inferred = True
-
-    def _create_parameter(self, symbol, options):
-        options = self._parse_options(options)
+    def _create_parameter(self, symbol):
         if symbol.type == CSYMBOL_TYPE_ELLIPSIS:
             ptype = Varargs()
-            if 'transfer' not in options:
-                options['transfer'] = ['none']
         else:
-            ptype = self._create_type(symbol.base_type, options,
+            ptype = self._create_type(symbol.base_type,
                                       is_param=True, is_retval=False)
             ptype = self.resolve_param_type(ptype)
-        param = Parameter(symbol.ident, ptype)
-        for option, data in options.iteritems():
-            if option in ['in-out', 'inout']:
-                param.direction = 'inout'
-            elif option == 'in':
-                param.direction = 'in'
-            elif option == 'out':
-                param.direction = 'out'
-            elif option == 'allow-none':
-                param.allow_none = True
-            elif option.startswith(('element-type', 'array')):
-                pass
-            elif option in ('transfer', 'transfer-inferred'):
-                pass
-            elif option == 'scope':
-                param.scope = data[0]
-            else:
-                print 'Unhandled parameter annotation option: %r' % (
-                    option, )
-        self._handle_generic_param_options(param, options)
+        return Parameter(symbol.ident, ptype)
 
-        assert param.transfer is not None, param
-        return param
-
-    def _create_return(self, source_type, options=None):
-        if options is None:
-            options_map = {}
-        else:
-            options_map = self._parse_options(options)
-        rtype = self._create_type(source_type, options_map,
+    def _create_return(self, source_type):
+        rtype = self._create_type(source_type,
                                   is_param=False, is_retval=True)
         rtype = self.resolve_param_type(rtype)
         return_ = Return(rtype)
-        self._handle_generic_param_options(return_, options_map)
-        for option, data in options_map.iteritems():
-            if option in ('transfer', 'transfer-inferred',
-                          'element-type', 'out'):
-                pass
-            elif option.startswith(('element-type', 'array')):
-                pass
-            else:
-                print 'Unhandled return type annotation option: %r' % (
-                    option, )
-
-        assert return_.transfer is not None, return_
         return return_
 
     def _create_const(self, symbol):
@@ -697,7 +475,6 @@ class Transformer(object):
         return callback
 
     def _create_struct(self, symbol):
-        directives = symbol.directives()
         struct = self._typedefs_ns.get(symbol.ident, None)
         if struct is None:
             # This is a bit of a hack; really we should try
@@ -715,12 +492,9 @@ class Transformer(object):
             if field:
                 struct.fields.append(field)
 
-        self._parse_version(struct, directives)
-
         return struct
 
     def _create_union(self, symbol):
-        directives = symbol.directives()
         union = self._typedefs_ns.get(symbol.ident, None)
         if union is None:
             # This is a bit of a hack; really we should try
@@ -738,24 +512,17 @@ class Transformer(object):
             if field:
                 union.fields.append(field)
 
-        self._parse_version(union, directives)
-
         return union
 
     def _create_callback(self, symbol):
-        directives = symbol.directives()
-        parameters = self._create_parameters(symbol.base_type.base_type,
-            directives)
-        retval = self._create_return(symbol.base_type.base_type.base_type,
-            directives.get('return', {}))
+        parameters = self._create_parameters(symbol.base_type.base_type)
+        retval = self._create_return(symbol.base_type.base_type.base_type)
         if symbol.ident.find('_') > 0:
             name = self.remove_prefix(symbol.ident, True)
         else:
             name = self.remove_prefix(symbol.ident)
         callback = Callback(name, retval, list(parameters), symbol.ident)
 
-        self._parse_version(callback, directives)
-
         return callback
 
     def _typepair_to_str(self, item):
@@ -833,19 +600,6 @@ class Transformer(object):
             ptype.name = self.resolve_type_name_full(ptype.name,
                                                      self.ctype_of(ptype),
                                                      names, **kwargs)
-            if isinstance(ptype, (Array, List)):
-                if ptype.element_type is not None:
-                    ptype.element_type = \
-                        self.resolve_param_type_full(ptype.element_type,
-                                                     names, **kwargs)
-            if isinstance(ptype, Map):
-                if ptype.key_type is not None:
-                    ptype.key_type = \
-                        self.resolve_param_type_full(ptype.key_type,
-                                                     names, **kwargs)
-                    ptype.value_type = \
-                        self.resolve_param_type_full(ptype.value_type,
-                                                     names, **kwargs)
         elif isinstance(ptype, basestring):
             return self.resolve_type_name_full(ptype, None, names, **kwargs)
         else:
index 6fd03f4..bed3f99 100644 (file)
@@ -82,6 +82,7 @@ class XMLWriter(object):
         self._indent_char = ' '
 
     # Private
+
     def _open_tag(self, tag_name, attributes=None):
         attrs = collect_attributes(
             tag_name, attributes, self._indent,
@@ -93,6 +94,7 @@ class XMLWriter(object):
         self.write_line('</%s>' % (tag_name, ))
 
     # Public API
+
     def get_xml(self):
         return self._data.getvalue()
 
index 155b9c4..a0c2a68 100644 (file)
         <type name="none" c:type="void"/>
       </return-value>
     </function>
+    <record name="Struct" c:type="_AnnotationStruct">
+      <field name="objects" writable="1">
+        <array zero-terminated="0" c:type="AnnotationObject*" fixed-size="10">
+          <type name="Object"/>
+        </array>
+      </field>
+    </record>
   </namespace>
 </repository>
index 576d6d7..0a654d5 100644 (file)
         <type name="none"/>
       </return-value>
     </function>
+    <record name="Struct">
+      <field name="objects" writable="1">
+        <array fixed-size="10">
+          <type name="Object"/>
+        </array>
+      </field>
+    </record>
   </namespace>
 </repository>
index 6278b6c..8fa6d8e 100644 (file)
@@ -50,7 +50,7 @@ annotation_object_out (AnnotationObject *object, int *outarg)
  *
  * This is a test for in arguments
  *
- * @inarg: (in): This is an argument test
+ * @inarg: (in): (transfer none): This is an argument test
  * Return value: an int
  */
 gint
@@ -246,7 +246,7 @@ annotation_object_compute_sum  (AnnotationObject *object,
 /**
  * annotation_object_compute_sum_n:
  * @object: a #GObject
- * @nums: (array length=n_nums): Sequence of numbers
+ * @nums: (array length=n_nums zero-terminated=0): Sequence of numbers
  * @n_nums: Length of number array
  *
  * Test taking an array with length parameter
index 8794660..ddafeb6 100644 (file)
@@ -90,4 +90,9 @@ void     annotation_init                (int              *argc,
 char **  annotation_return_array        (int             *length);
 void     annotation_versioned           (void);
 
+struct _AnnotationStruct
+{
+  AnnotationObject *objects[10];
+};
+
 #endif /* __ANNOTATION_OBJECT_H__ */
index db76f27..84a5cc3 100644 (file)
         </parameter>
       </parameters>
     </function>
+    <function name="test_const_char_retval"
+              c:identifier="foo_test_const_char_retval">
+      <return-value transfer-ownership="none">
+        <type name="utf8" c:type="char*"/>
+      </return-value>
+    </function>
+    <function name="test_const_struct_retval"
+              c:identifier="foo_test_const_struct_retval">
+      <return-value transfer-ownership="none">
+        <type name="Struct" c:type="FooStruct*"/>
+      </return-value>
+    </function>
+    <function name="test_const_char_param"
+              c:identifier="foo_test_const_char_param">
+      <return-value transfer-ownership="none">
+        <type name="none" c:type="void"/>
+      </return-value>
+      <parameters>
+        <parameter name="param" transfer-ownership="none">
+          <type name="utf8" c:type="char*"/>
+        </parameter>
+      </parameters>
+    </function>
+    <function name="test_const_struct_param"
+              c:identifier="foo_test_const_struct_param">
+      <return-value transfer-ownership="none">
+        <type name="none" c:type="void"/>
+      </return-value>
+      <parameters>
+        <parameter name="param" transfer-ownership="none">
+          <type name="Struct" c:type="FooStruct*"/>
+        </parameter>
+      </parameters>
+    </function>
     <constant name="SUCCESS_INT" value="4408">
       <type name="int"/>
     </constant>
index 168373e..8c205a9 100644 (file)
         </parameter>
       </parameters>
     </function>
+    <function name="test_const_char_retval" c:identifier="foo_test_const_char_retval">
+      <return-value transfer-ownership="none">
+        <type name="utf8"/>
+      </return-value>
+    </function>
+    <function name="test_const_struct_retval" c:identifier="foo_test_const_struct_retval">
+      <return-value transfer-ownership="none">
+        <type name="Struct"/>
+      </return-value>
+    </function>
+    <function name="test_const_char_param" c:identifier="foo_test_const_char_param">
+      <return-value transfer-ownership="none">
+        <type name="none"/>
+      </return-value>
+      <parameters>
+        <parameter name="param" transfer-ownership="none">
+          <type name="utf8"/>
+        </parameter>
+      </parameters>
+    </function>
+    <function name="test_const_struct_param" c:identifier="foo_test_const_struct_param">
+      <return-value transfer-ownership="none">
+        <type name="none"/>
+      </return-value>
+      <parameters>
+        <parameter name="param" transfer-ownership="none">
+          <type name="Struct"/>
+        </parameter>
+      </parameters>
+    </function>
     <constant name="SUCCESS_INT" value="4408">
       <type name="int"/>
     </constant>
index b51d0c8..dbef015 100644 (file)
@@ -281,4 +281,9 @@ void foo_test_string_array (char **array);
 
 void foo_test_string_array_with_g (gchar **array);
 
+const char * foo_test_const_char_retval (void);
+const FooStruct * foo_test_const_struct_retval (void);
+void foo_test_const_char_param (const char * param);
+void foo_test_const_struct_param (const FooStruct * param);
+
 #endif /* __FOO_OBJECT_H__ */
index f69bdeb..2152611 100755 (executable)
@@ -41,6 +41,7 @@ else:
                         'site-packages')
 sys.path.insert(0, path)
 
+from giscanner.annotationparser import AnnotationParser, InvalidAnnotationError
 from giscanner.ast import Include
 from giscanner.cachestore import CacheStore
 from giscanner.dumper import compile_introspection_binary
@@ -313,6 +314,12 @@ def main(args):
 
     namespace = glibtransformer.parse()
 
+    ap = AnnotationParser(namespace, ss, transformer)
+    try:
+        ap.parse()
+    except InvalidAnnotationError, e:
+        raise SystemExit("ERROR in annotation: %s" % (str(e), ))
+
     # Write out AST
     writer = Writer(namespace, libraries, transformer.get_includes())
     data = writer.get_xml()