diff options
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | giscanner/ast.py | 10 | ||||
-rw-r--r-- | giscanner/girwriter.py | 4 | ||||
-rw-r--r-- | giscanner/scannerlexer.l | 18 | ||||
-rw-r--r-- | giscanner/transformer.py | 99 | ||||
-rw-r--r-- | tests/scanner/annotation-expected.gir | 12 | ||||
-rw-r--r-- | tests/scanner/annotation.c | 28 | ||||
-rw-r--r-- | tests/scanner/foo-expected.gir | 8 |
8 files changed, 119 insertions, 73 deletions
@@ -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> |