summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--giscanner/ast.py10
-rw-r--r--giscanner/girwriter.py4
-rw-r--r--giscanner/scannerlexer.l18
-rw-r--r--giscanner/transformer.py99
-rw-r--r--tests/scanner/annotation-expected.gir12
-rw-r--r--tests/scanner/annotation.c28
-rw-r--r--tests/scanner/foo-expected.gir8
8 files changed, 119 insertions, 73 deletions
diff --git a/ChangeLog b/ChangeLog
index 64e9500a..43254feb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2008-10-11 Colin Walters <walters@verbum.org>
+
+ Bug 555947 - update annotations syntax
+
+ * giscanner/ast.py: Default to None for transfer. Remove
+ default transfers for container types; we require this to
+ be specified now.
+ * giscanner/girwriter.py: Transfer is now 'none', 'container',
+ 'full' to match repository.
+ * giscanner/scannerlexer.l: Annotations now are parenthesized.
+ * giscanner/transformer.py: Update for new annotations syntax.
+ * tests/*: Update.
+
2008-10-11 Johan Bilien <jobi@litl.com>
* giscanner/scannerparser.y: ignore non-UTF-8 string constants
diff --git a/giscanner/ast.py b/giscanner/ast.py
index 906f64e3..b5608ea4 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -227,7 +227,7 @@ class Parameter(Node):
Node.__init__(self, name)
self.type = typenode
self.direction = PARAM_DIRECTION_IN
- self.transfer = False
+ self.transfer = None
self.allow_none = False
def __repr__(self):
@@ -282,11 +282,13 @@ class Field(Node):
class Return(Node):
- def __init__(self, rtype, transfer=False):
+ def __init__(self, rtype, transfer=None):
Node.__init__(self)
self.type = rtype
- self.transfer = isinstance(rtype, (List, Map, Array)) or \
- rtype.name in ('utf8', 'filename') or transfer
+ if transfer is None and rtype.name in ['utf8', 'filename']:
+ self.transfer = 'full'
+ else:
+ self.transfer = transfer
def __repr__(self):
return 'Return(%r)' % (self.type, )
diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py
index ede42b46..25328d7a 100644
--- a/giscanner/girwriter.py
+++ b/giscanner/girwriter.py
@@ -121,7 +121,7 @@ class GIRWriter(XMLWriter):
attrs = []
if return_.transfer:
attrs.append(('transfer-ownership',
- str(int(return_.transfer))))
+ return_.transfer))
with self.tagcontext('return-value', attrs):
self._write_type(return_.type)
@@ -140,7 +140,7 @@ class GIRWriter(XMLWriter):
attrs.append(('direction', parameter.direction))
if parameter.transfer:
attrs.append(('transfer-ownership',
- str(int(parameter.transfer))))
+ parameter.transfer))
if parameter.allow_none:
attrs.append(('allow-none', '1'))
with self.tagcontext('parameter', attrs):
diff --git a/giscanner/scannerlexer.l b/giscanner/scannerlexer.l
index a3efbf5b..5d94ac4f 100644
--- a/giscanner/scannerlexer.l
+++ b/giscanner/scannerlexer.l
@@ -250,20 +250,20 @@ parse_gtkdoc (GISourceScanner *scanner,
if (n_parts == 3)
{
char *ptr = g_strdup (parts[1]);
+ char *start;
+ char *end;
char **option_parts, **option_part;
- if (*ptr == '<')
+ options = NULL;
+ start = strchr (ptr, '(');
+ while (start != NULL)
{
- char *end = strchr (ptr, '>');
- if (end)
+ end = strchr (start, ')');
+ if (end)
{
- *end = '\0';
- option_parts = g_strsplit (ptr+1, ",", 0);
- for (option_part = option_parts; *option_part; option_part++)
- options = g_slist_prepend (options, g_strdup (*option_part));
- options = g_slist_reverse (options);
- g_strfreev (option_parts);
+ options = g_slist_prepend (options, g_strndup (start+1, end-(start+1)));
}
+ start = strchr (end+1, '(');
}
g_free (ptr);
value = parts[2];
diff --git a/giscanner/transformer.py b/giscanner/transformer.py
index 024a2996..be7f83fa 100644
--- a/giscanner/transformer.py
+++ b/giscanner/transformer.py
@@ -19,6 +19,7 @@
#
import os
+import re
from giscanner.ast import (Callback, Enum, Function, Namespace, Member,
Parameter, Return, Array, Struct, Field,
@@ -259,13 +260,25 @@ class Transformer(object):
if isinstance(param.type, Array):
self._pair_array(params, param)
+ # 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
+
def _create_function(self, symbol):
directives = symbol.directives()
parameters = list(self._create_parameters(
symbol.base_type, directives))
self._pair_annotations(parameters)
return_ = self._create_return(symbol.base_type.base_type,
- directives.get('return', []))
+ directives.get('return', {}))
name = self._strip_namespace_func(symbol.ident)
func = Function(name, return_, parameters, symbol.ident)
self._parse_deprecated(func, directives)
@@ -290,12 +303,14 @@ class Transformer(object):
value = 'any'
return value
- def _create_parameters(self, base_type, options=None):
- if not options:
- options = {}
+ def _create_parameters(self, base_type, directives=None):
+ if directives is None:
+ dirs = {}
+ else:
+ dirs = directives
for child in base_type.child_list:
yield self._create_parameter(
- child, options.get(child.ident, []))
+ child, dirs.get(child.ident, {}))
def _create_member(self, symbol):
ctype = symbol.base_type.type
@@ -303,7 +318,7 @@ class Transformer(object):
symbol.base_type.base_type.type == CTYPE_FUNCTION):
node = self._create_callback(symbol)
else:
- ftype = self._create_type(symbol.base_type)
+ ftype = self._create_type(symbol.base_type, {})
node = Field(symbol.ident, ftype, symbol.ident, symbol.const_int)
return node
@@ -340,7 +355,7 @@ class Transformer(object):
derefed = canonical.replace('*', '')
return derefed
- def _create_type(self, source_type, options=[]):
+ def _create_type(self, source_type, options):
ctype = self._create_source_type(source_type)
if ctype == 'va_list':
raise SkipError()
@@ -349,19 +364,19 @@ class Transformer(object):
elif ctype == 'FILE*':
raise SkipError
if ctype in self._list_ctypes:
- if len(options) > 0:
- contained_type = self._parse_ctype(options[0])
- del options[0]
+ param = options.get('element-type')
+ if param:
+ contained_type = self._parse_ctype(param[0])
else:
contained_type = None
return List(ctype.replace('*', ''),
ctype,
contained_type)
- if ctype in self._list_ctypes:
- if len(options) > 0:
- key_type = self._parse_ctype(options[0])
- value_type = self._parse_ctype(options[1])
- del options[0:2]
+ if 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
@@ -369,58 +384,74 @@ class Transformer(object):
ctype,
key_type, value_type)
if (ctype in default_array_types) or ('array' in options):
- if 'array' in options:
- options.remove('array')
derefed = ctype[:-1] # strip the *
- return Array(ctype,
+ result = Array(ctype,
self._parse_ctype(derefed))
+ array_opts = options.get('array')
+ if array_opts:
+ (_, len_name) = array_opts[0].split('=')
+ result.length_param_name = len_name
+ return result
resolved_type_name = self._parse_ctype(ctype)
# string memory management
if ctype == 'char*':
if source_type.base_type.type_qualifier & TYPE_QUALIFIER_CONST:
- options.append('notransfer')
+ options['transfer'] = ['none']
else:
- options.append('transfer')
+ options['transfer'] = ['full']
return Type(resolved_type_name, ctype)
+ 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
+
def _create_parameter(self, symbol, options):
+ options = self._parse_options(options)
if symbol.type == CSYMBOL_TYPE_ELLIPSIS:
ptype = Varargs()
else:
ptype = self._create_type(symbol.base_type, options)
param = Parameter(symbol.ident, ptype)
- for option in options:
+ 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 == 'transfer':
- param.transfer = True
- elif option == 'notransfer':
- param.transfer = False
- elif isinstance(ptype, Array) and option.startswith('length'):
- (_, index_param) = option.split('=')
- ptype.length_param_name = index_param
elif option == 'allow-none':
param.allow_none = True
+ elif option.startswith(('element-type', 'array')):
+ pass
+ elif option == 'transfer':
+ pass
else:
print 'Unhandled parameter annotation option: %r' % (
option, )
+ self._handle_generic_param_options(param, options)
return param
- def _create_return(self, source_type, options=[]):
- rtype = self._create_type(source_type, options)
+ 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)
rtype = self.resolve_param_type(rtype)
return_ = Return(rtype)
- for option in options:
+ self._handle_generic_param_options(return_, options_map)
+ for option, data in options_map.iteritems():
if option == 'transfer':
- return_.transfer = True
- elif option == 'notransfer':
- return_.transfer = False
+ pass
else:
print 'Unhandled return type annotation option: %r' % (
option, )
diff --git a/tests/scanner/annotation-expected.gir b/tests/scanner/annotation-expected.gir
index 75354048..e8298b26 100644
--- a/tests/scanner/annotation-expected.gir
+++ b/tests/scanner/annotation-expected.gir
@@ -29,7 +29,7 @@
</method>
<method name="create_object"
c:identifier="annotation_object_create_object">
- <return-value transfer-ownership="1">
+ <return-value transfer-ownership="full">
<type name="GObject.Object" c:type="GObject*"/>
</return-value>
</method>
@@ -88,7 +88,7 @@
<type name="int" c:type="gint"/>
</return-value>
<parameters>
- <parameter name="toown" direction="out" transfer-ownership="1">
+ <parameter name="toown" direction="out" transfer-ownership="full">
<type name="GObject.Object" c:type="GObject**"/>
</parameter>
</parameters>
@@ -98,23 +98,23 @@
<type name="int" c:type="gint"/>
</return-value>
<parameters>
- <parameter name="toown1" direction="out" transfer-ownership="1">
+ <parameter name="toown1" direction="out" transfer-ownership="full">
<type name="GObject.Object" c:type="GObject**"/>
</parameter>
- <parameter name="toown2" direction="out" transfer-ownership="1">
+ <parameter name="toown2" direction="out" transfer-ownership="full">
<type name="GObject.Object" c:type="GObject**"/>
</parameter>
</parameters>
</method>
<method name="get_strings" c:identifier="annotation_object_get_strings">
- <return-value transfer-ownership="1">
+ <return-value transfer-ownership="full">
<type name="GLib.List" c:type="GList*">
<type name="utf8"/>
</type>
</return-value>
</method>
<method name="get_objects" c:identifier="annotation_object_get_objects">
- <return-value transfer-ownership="1">
+ <return-value transfer-ownership="container">
<type name="GLib.SList" c:type="GSList*">
<type name="Object"/>
</type>
diff --git a/tests/scanner/annotation.c b/tests/scanner/annotation.c
index 01ee0153..4ef97b30 100644
--- a/tests/scanner/annotation.c
+++ b/tests/scanner/annotation.c
@@ -34,7 +34,7 @@ annotation_object_method (AnnotationObject *object)
*
* This is a test for out arguments
*
- * @outarg: <out>: This is an argument test
+ * @outarg: (out): This is an argument test
* Return value: an int
*/
gint
@@ -50,7 +50,7 @@ annotation_object_in (AnnotationObject *object, int *outarg)
*
* This is a test for out arguments
*
- * @outarg: <in>: This is an argument test
+ * @outarg: (in): This is an argument test
* Return value: an int
*/
gint
@@ -67,7 +67,7 @@ annotation_object_out (AnnotationObject *object, int *outarg)
*
* This is a test for out arguments
*
- * @inoutarg: <inout>: This is an argument test
+ * @inoutarg: (inout): This is an argument test
* Return value: an int
*/
gint
@@ -82,7 +82,7 @@ annotation_object_inout (AnnotationObject *object, int *inoutarg)
*
* This is a second test for out arguments
*
- * @inoutarg: <inout>: This is an argument test
+ * @inoutarg: (inout): This is an argument test
* Return value: an int
*/
gint
@@ -98,7 +98,7 @@ annotation_object_inout2 (AnnotationObject *object, int *inoutarg)
*
* This is a 3th test for out arguments
*
- * @inoutarg: <inout,allow-none>: This is an argument test
+ * @inoutarg: (inout) (allow-none): This is an argument test
* Return value: an int
*/
gint
@@ -115,7 +115,7 @@ annotation_object_inout3 (AnnotationObject *object, int *inoutarg)
*
* This is a test for out arguments
*
- * @toown: <out,transfer>: a #GObject
+ * @toown: (out) (transfer): a #GObject
* Return value: an int
*/
gint
@@ -131,8 +131,8 @@ annotation_object_calleeowns (AnnotationObject *object, GObject **toown)
*
* This is a test for out arguments
*
- * @toown1: <out,transfer>: a #GObject
- * @toown2: <out,transfer>: a #GObject
+ * @toown1: (out) (transfer): a #GObject
+ * @toown2: (out) (transfer): a #GObject
* Return value: an int
*/
gint
@@ -151,7 +151,7 @@ annotation_object_calleesowns (AnnotationObject *object,
* This is a test for returning a list of strings, where
* each string needs to be freed.
*
- * Return value: <char*,transfer>: list of strings
+ * Return value: (element-type utf8) (transfer): list of strings
*/
GList*
annotation_object_get_strings (AnnotationObject *object)
@@ -181,7 +181,7 @@ annotation_object_with_voidp (AnnotationObject *object, void *data)
* The list itself should be freed, but not the internal objects,
* intentionally similar example to gtk_container_get_children
*
- * Return value: <AnnotationObject*>: list of objects
+ * Return value: (element-type AnnotationObject) (transfer container): list of objects
*/
GSList*
annotation_object_get_objects (AnnotationObject *object)
@@ -197,7 +197,7 @@ annotation_object_get_objects (AnnotationObject *object)
*
* Test returning a caller-owned object
*
- * Return value: <transfer>: The object
+ * Return value: (transfer): The object
**/
GObject*
annotation_object_create_object (AnnotationObject *object)
@@ -215,7 +215,7 @@ annotation_object_use_buffer (AnnotationObject *object,
/**
* annotation_object_compute_sum:
* @object: a #GObject
- * @nums: <array>: Sequence of numbers
+ * @nums: (array): Sequence of numbers
*
* Test taking a zero-terminated array
**/
@@ -229,7 +229,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): Sequence of numbers
* @n_nums: Length of number array
*
* Test taking an array with length parameter
@@ -245,7 +245,7 @@ annotation_object_compute_sum_n(AnnotationObject *object,
/**
* annotation_object_allow_none:
* @object: a #GObject
- * @somearg: <allow-none>:
+ * @somearg: (allow-none):
**/
GObject*
annotation_object_allow_none (AnnotationObject *object, gchar *somearg)
diff --git a/tests/scanner/foo-expected.gir b/tests/scanner/foo-expected.gir
index 42e34cd6..1392f573 100644
--- a/tests/scanner/foo-expected.gir
+++ b/tests/scanner/foo-expected.gir
@@ -98,7 +98,7 @@
<type name="ObjectCookie" c:type="FooObjectCookie"/>
</return-value>
<parameters>
- <parameter name="target">
+ <parameter name="target" transfer-ownership="none">
<type name="utf8" c:type="char*"/>
</parameter>
</parameters>
@@ -114,12 +114,12 @@
</parameters>
</method>
<method name="get_name" c:identifier="foo_object_get_name">
- <return-value>
+ <return-value transfer-ownership="none">
<type name="utf8" c:type="char*"/>
</return-value>
</method>
<method name="dup_name" c:identifier="foo_object_dup_name">
- <return-value transfer-ownership="1">
+ <return-value transfer-ownership="full">
<type name="utf8" c:type="char*"/>
</return-value>
</method>
@@ -140,7 +140,7 @@
</parameters>
</callback>
<glib:signal name="signal">
- <return-value transfer-ownership="1">
+ <return-value transfer-ownership="full">
<type name="utf8" c:type="gchararray"/>
</return-value>
<parameters>