summaryrefslogtreecommitdiff
path: root/giscanner/maintransformer.py
diff options
context:
space:
mode:
Diffstat (limited to 'giscanner/maintransformer.py')
-rw-r--r--giscanner/maintransformer.py665
1 files changed, 332 insertions, 333 deletions
diff --git a/giscanner/maintransformer.py b/giscanner/maintransformer.py
index d4163fae..c107beed 100644
--- a/giscanner/maintransformer.py
+++ b/giscanner/maintransformer.py
@@ -21,23 +21,19 @@ import re
from . import ast
from . import message
-from .annotationparser import (TAG_VFUNC, TAG_SINCE, TAG_DEPRECATED, TAG_RETURNS,
- TAG_ATTRIBUTES, TAG_RENAME_TO, TAG_TYPE,
- TAG_UNREF_FUNC, TAG_REF_FUNC, TAG_SET_VALUE_FUNC,
- TAG_GET_VALUE_FUNC, TAG_VALUE, TAG_TRANSFER,
- TAG_STABILITY)
-from .annotationparser import (OPT_ALLOW_NONE, OPT_ARRAY, OPT_ATTRIBUTE,
- OPT_ELEMENT_TYPE, OPT_IN, OPT_INOUT,
- OPT_INOUT_ALT, OPT_OUT, OPT_SCOPE,
- OPT_OUT_CALLER_ALLOCATES, OPT_OUT_CALLEE_ALLOCATES,
- OPT_TYPE, OPT_CLOSURE, OPT_DESTROY, OPT_TRANSFER, OPT_SKIP,
- OPT_FOREIGN, OPT_ARRAY_FIXED_SIZE,
- OPT_ARRAY_LENGTH, OPT_ARRAY_ZERO_TERMINATED,
- OPT_CONSTRUCTOR, OPT_METHOD,
- OPT_TRANSFER_NONE, OPT_TRANSFER_FLOATING)
-from .annotationparser import AnnotationParser
-from .transformer import TransformerException
-from .utils import to_underscores, to_underscores_noprefix
+from .annotationparser import (TAG_DEPRECATED, TAG_SINCE, TAG_STABILITY, TAG_RETURNS)
+from .annotationparser import (ANN_ALLOW_NONE, ANN_ARRAY, ANN_ATTRIBUTES, ANN_CLOSURE,
+ ANN_CONSTRUCTOR, ANN_DESTROY, ANN_ELEMENT_TYPE, ANN_FOREIGN,
+ ANN_GET_VALUE_FUNC, ANN_IN, ANN_INOUT, ANN_METHOD, ANN_OUT,
+ ANN_REF_FUNC, ANN_RENAME_TO, ANN_SCOPE, ANN_SET_VALUE_FUNC,
+ ANN_SKIP, ANN_TRANSFER, ANN_TYPE, ANN_UNREF_FUNC, ANN_VALUE,
+ ANN_VFUNC)
+from .annotationparser import (OPT_ARRAY_FIXED_SIZE, OPT_ARRAY_LENGTH, OPT_ARRAY_ZERO_TERMINATED,
+ OPT_OUT_CALLEE_ALLOCATES, OPT_OUT_CALLER_ALLOCATES,
+ OPT_TRANSFER_FLOATING, OPT_TRANSFER_NONE)
+
+from .utils import to_underscores_noprefix
+
class MainTransformer(object):
@@ -50,12 +46,10 @@ class MainTransformer(object):
# Public API
def transform(self):
- contents = list(self._namespace.itervalues())
- if len(contents) == 0:
- message.fatal("""Namespace is empty; likely causes are:
-* Not including .h files to be scanned
-* Broken --identifier-prefix
-""")
+ if not self._namespace.names:
+ message.fatal('Namespace is empty; likely causes are:\n'
+ '* Not including .h files to be scanned\n'
+ '* Broken --identifier-prefix')
# Some initial namespace surgery
self._namespace.walk(self._pass_fixup_hidden_fields)
@@ -109,23 +103,21 @@ class MainTransformer(object):
def _pass_fixup_hidden_fields(self, node, chain):
"""Hide all callbacks starting with _; the typical
-usage is void (*_gtk_reserved1)(void);"""
- if not isinstance(node, (ast.Class, ast.Interface,
- ast.Record, ast.Union)):
- return True
- for field in node.fields:
- if field is None:
- continue
- if (field.name.startswith('_')
+ usage is void (*_gtk_reserved1)(void);"""
+ if isinstance(node, (ast.Class, ast.Interface, ast.Record, ast.Union)):
+ for field in node.fields:
+ if (field
+ and field.name is not None
+ and field.name.startswith('_')
and field.anonymous_node is not None
and isinstance(field.anonymous_node, ast.Callback)):
- field.introspectable = False
+ field.introspectable = False
return True
def _get_validate_parameter_name(self, parent, param_name, origin):
try:
param = parent.get_parameter(param_name)
- except ValueError, e:
+ except ValueError:
param = None
if param is None:
if isinstance(origin, ast.Parameter):
@@ -139,30 +131,43 @@ usage is void (*_gtk_reserved1)(void);"""
return param.argname
+ def _get_validate_field_name(self, parent, field_name, origin):
+ try:
+ field = parent.get_field(field_name)
+ except ValueError:
+ field = None
+ if field is None:
+ origin_name = 'field %s' % (origin.name, )
+ message.log_node(
+ message.FATAL, parent,
+ "can't find field %s referenced by %s of %r"
+ % (field_name, origin_name, parent.name))
+
+ return field.name
+
def _apply_annotation_rename_to(self, node, chain, block):
if not block:
return
- rename_to = block.get_tag(TAG_RENAME_TO)
+ rename_to = block.annotations.get(ANN_RENAME_TO)
if not rename_to:
return
- rename_to = rename_to.value
+ rename_to = rename_to[0]
target = self._namespace.get_by_symbol(rename_to)
if not target:
message.warn_node(node,
- "Can't find symbol %r referenced by Rename annotation" % (
- rename_to, ))
+ "Can't find symbol %r referenced by \"rename-to\" annotation" % (rename_to, ))
elif target.shadowed_by:
message.warn_node(node,
- "Function %r already shadowed by %r, can't overwrite with %r" % (
- target.symbol,
- target.shadowed_by,
- rename_to))
+ "Function %r already shadowed by %r, can't overwrite "
+ "with %r" % (target.symbol,
+ target.shadowed_by,
+ rename_to))
elif target.shadows:
message.warn_node(node,
- "Function %r already shadows %r, can't multiply shadow with %r" % (
- target.symbol,
- target.shadows,
- rename_to))
+ "Function %r already shadows %r, can't multiply shadow "
+ "with %r" % (target.symbol,
+ target.shadows,
+ rename_to))
else:
target.shadowed_by = node.name
node.shadows = target.name
@@ -192,7 +197,7 @@ usage is void (*_gtk_reserved1)(void);"""
def _get_annotation_name(self, node):
if isinstance(node, (ast.Class, ast.Interface, ast.Record,
ast.Union, ast.Enum, ast.Bitfield,
- ast.Callback, ast.Alias)):
+ ast.Callback, ast.Alias, ast.Constant)):
if node.ctype is not None:
return node.ctype
elif isinstance(node, ast.Registered) and node.gtype_name is not None:
@@ -211,19 +216,21 @@ usage is void (*_gtk_reserved1)(void);"""
if isinstance(node, ast.Function):
self._apply_annotations_function(node, chain)
if isinstance(node, ast.Callback):
- self._apply_annotations_callable(node, chain, block = self._get_block(node))
+ self._apply_annotations_callable(node, chain, block=self._get_block(node))
if isinstance(node, (ast.Class, ast.Interface, ast.Union, ast.Enum,
ast.Bitfield, ast.Callback)):
self._apply_annotations_annotated(node, self._get_block(node))
+ if isinstance(node, (ast.Enum, ast.Bitfield)):
+ self._apply_annotations_enum_members(node, self._get_block(node))
if isinstance(node, (ast.Class, ast.Interface, ast.Record, ast.Union)):
block = self._get_block(node)
for field in node.fields:
self._apply_annotations_field(node, block, field)
name = self._get_annotation_name(node)
- section_name = 'SECTION:' + name.lower()
+ section_name = 'SECTION:%s' % (name.lower(), )
block = self._blocks.get(section_name)
- if block:
- node.doc = block.comment
+ if block and block.description:
+ node.doc = block.description
if isinstance(node, (ast.Class, ast.Interface)):
for prop in node.properties:
self._apply_annotations_property(node, prop)
@@ -232,29 +239,26 @@ usage is void (*_gtk_reserved1)(void);"""
if isinstance(node, ast.Class):
block = self._get_block(node)
if block:
- tag = block.get_tag(TAG_UNREF_FUNC)
- node.unref_func = tag.value if tag else None
- tag = block.get_tag(TAG_REF_FUNC)
- node.ref_func = tag.value if tag else None
- tag = block.get_tag(TAG_SET_VALUE_FUNC)
- node.set_value_func = tag.value if tag else None
- tag = block.get_tag(TAG_GET_VALUE_FUNC)
- node.get_value_func = tag.value if tag else None
+ annotation = block.annotations.get(ANN_UNREF_FUNC)
+ node.unref_func = annotation[0] if annotation else None
+ annotation = block.annotations.get(ANN_REF_FUNC)
+ node.ref_func = annotation[0] if annotation else None
+ annotation = block.annotations.get(ANN_SET_VALUE_FUNC)
+ node.set_value_func = annotation[0] if annotation else None
+ annotation = block.annotations.get(ANN_GET_VALUE_FUNC)
+ node.get_value_func = annotation[0] if annotation else None
if isinstance(node, ast.Constant):
self._apply_annotations_constant(node)
return True
- def _adjust_container_type(self, parent, node, options):
- has_element_type = OPT_ELEMENT_TYPE in options
- has_array = OPT_ARRAY in options
-
- if has_array:
- self._apply_annotations_array(parent, node, options)
- elif has_element_type:
- self._apply_annotations_element_type(parent, node, options)
+ def _adjust_container_type(self, parent, node, annotations):
+ if ANN_ARRAY in annotations:
+ self._apply_annotations_array(parent, node, annotations)
+ elif ANN_ELEMENT_TYPE in annotations:
+ self._apply_annotations_element_type(parent, node, annotations)
if isinstance(node.type, ast.Array):
- self._check_array_element_type(node.type, options)
+ self._check_array_element_type(node.type, annotations)
def _resolve(self, type_str, type_node=None, node=None, parent=None):
def grab_one(type_str, resolver, top_combiner, combiner):
@@ -262,7 +266,7 @@ usage is void (*_gtk_reserved1)(void);"""
Use resolver() on each identifier, and combiner() on the parts of
each complete type. (top_combiner is used on the top-most type.)"""
bits = re.split(r'([,<>()])', type_str, 1)
- first, sep, rest = [bits[0], '', ''] if (len(bits)==1) else bits
+ first, sep, rest = [bits[0], '', ''] if (len(bits) == 1) else bits
args = [resolver(first)]
if sep == '<' or sep == '(':
lastsep = '>' if (sep == '<') else ')'
@@ -273,9 +277,11 @@ usage is void (*_gtk_reserved1)(void);"""
else:
rest = sep + rest
return top_combiner(*args), rest
+
def resolver(ident):
res = self._transformer.create_type_from_user_string(ident)
return res
+
def combiner(base, *rest):
if not rest:
return base
@@ -286,6 +292,7 @@ usage is void (*_gtk_reserved1)(void);"""
message.warn(
"Too many parameters in type specification %r" % (type_str, ))
return base
+
def top_combiner(base, *rest):
if type_node is not None and isinstance(type_node, ast.Type):
base.is_const = type_node.is_const
@@ -304,7 +311,7 @@ usage is void (*_gtk_reserved1)(void);"""
else:
text = type_str
message.warn_node(parent, "%s: Unknown type: %r" %
- (text, result.ctype), positions=position)
+ (text, type_str), positions=position)
return result
def _resolve_toplevel(self, type_str, type_node=None, node=None, parent=None):
@@ -320,50 +327,43 @@ usage is void (*_gtk_reserved1)(void);"""
block = self._blocks.get(func.symbol)
if block:
if isinstance(param, ast.Parameter):
- tag = block.params.get(param.argname)
+ part = block.params.get(param.argname)
elif isinstance(param, ast.Return):
- tag = block.tags.get(TAG_RETURNS)
+ part = block.tags.get(TAG_RETURNS)
else:
- tag = None
+ part = None
- if tag.position:
- return tag.position
+ if part.position:
+ return part.position
return block.position
- def _check_array_element_type(self, array, options):
+ def _check_array_element_type(self, array, annotations):
+ array_type = array.array_type
+ element_type = array.element_type
+
# GPtrArrays are allowed to contain non basic types
# (except enums and flags) or basic types that are
# as big as a gpointer
- if array.array_type == ast.Array.GLIB_PTRARRAY and \
- ((array.element_type in ast.BASIC_GIR_TYPES
- and not array.element_type in ast.POINTER_TYPES) or
- isinstance(array.element_type, ast.Enum) or
- isinstance(array.element_type, ast.Bitfield)):
- message.warn("invalid (element-type) for a GPtrArray, "
- "must be a pointer", options.position)
+ if array_type == ast.Array.GLIB_PTRARRAY:
+ if ((element_type in ast.BASIC_GIR_TYPES and not element_type in ast.POINTER_TYPES)
+ or isinstance(element_type, (ast.Enum, ast.Bitfield))):
+ message.warn("invalid (element-type) for a GPtrArray, "
+ "must be a pointer", annotations.position)
# GByteArrays have (element-type) guint8 by default
- if array.array_type == ast.Array.GLIB_BYTEARRAY:
- if array.element_type == ast.TYPE_ANY:
+ if array_type == ast.Array.GLIB_BYTEARRAY:
+ if element_type == ast.TYPE_ANY:
array.element_type = ast.TYPE_UINT8
- elif not array.element_type in [ast.TYPE_UINT8,
- ast.TYPE_INT8,
- ast.TYPE_CHAR]:
+ elif not element_type in [ast.TYPE_UINT8, ast.TYPE_INT8, ast.TYPE_CHAR]:
message.warn("invalid (element-type) for a GByteArray, "
"must be one of guint8, gint8 or gchar",
- options.position)
-
- def _apply_annotations_array(self, parent, node, options):
- array_opt = options.get(OPT_ARRAY)
- if array_opt:
- array_values = array_opt.all()
- else:
- array_values = {}
+ annotations.position)
- element_type = options.get(OPT_ELEMENT_TYPE)
- if element_type is not None:
- element_type_node = self._resolve(element_type.one(),
+ def _apply_annotations_array(self, parent, node, annotations):
+ element_type_options = annotations.get(ANN_ELEMENT_TYPE)
+ if element_type_options:
+ element_type_node = self._resolve(element_type_options[0],
node.type, node, parent)
elif isinstance(node.type, ast.Array):
element_type_node = node.type.element_type
@@ -372,82 +372,82 @@ usage is void (*_gtk_reserved1)(void);"""
# and no (element-type) means array of Foo
element_type_node = node.type.clone()
# The element's ctype is the array's dereferenced
- if element_type_node.ctype is not None and \
- element_type_node.ctype.endswith('*'):
+ if element_type_node.ctype is not None and element_type_node.ctype.endswith('*'):
element_type_node.ctype = element_type_node.ctype[:-1]
if isinstance(node.type, ast.Array):
array_type = node.type.array_type
else:
array_type = None
- container_type = ast.Array(array_type, element_type_node,
- ctype=node.type.ctype,
- is_const=node.type.is_const)
- if OPT_ARRAY_ZERO_TERMINATED in array_values:
- container_type.zeroterminated = array_values.get(
- OPT_ARRAY_ZERO_TERMINATED) == '1'
+
+ array_options = annotations.get(ANN_ARRAY)
+ container_type = ast.Array(array_type, element_type_node, ctype=node.type.ctype,
+ is_const=node.type.is_const)
+ if OPT_ARRAY_ZERO_TERMINATED in array_options:
+ container_type.zeroterminated = array_options.get(OPT_ARRAY_ZERO_TERMINATED) == '1'
else:
container_type.zeroterminated = False
- length = array_values.get(OPT_ARRAY_LENGTH)
- if length is not None:
- paramname = self._get_validate_parameter_name(parent, length, node)
+
+ length = array_options.get(OPT_ARRAY_LENGTH)
+ if length:
+ if isinstance(parent, ast.Compound):
+ paramname = self._get_validate_field_name(parent, length, node)
+ else:
+ paramname = self._get_validate_parameter_name(parent, length, node)
+ if paramname:
+ param = parent.get_parameter(paramname)
+ param.direction = node.direction
+ if param.direction == ast.PARAM_DIRECTION_OUT:
+ param.transfer = ast.PARAM_TRANSFER_FULL
if paramname:
- param = parent.get_parameter(paramname)
- param.direction = node.direction
- if param.direction == ast.PARAM_DIRECTION_OUT:
- param.transfer = ast.PARAM_TRANSFER_FULL
- container_type.length_param_name = param.argname
- fixed = array_values.get(OPT_ARRAY_FIXED_SIZE)
+ container_type.length_param_name = paramname
+ fixed = array_options.get(OPT_ARRAY_FIXED_SIZE)
if fixed:
try:
container_type.size = int(fixed)
- except ValueError:
+ except (TypeError, ValueError):
# Already warned in annotationparser.py
return
node.type = container_type
- def _apply_annotations_element_type(self, parent, node, options):
- element_type_opt = options.get(OPT_ELEMENT_TYPE)
- if element_type_opt is None:
- message.warn(
- 'element-type annotation takes at least one option, '
- 'none given',
- options.position)
+ def _apply_annotations_element_type(self, parent, node, annotations):
+ element_type_options = annotations.get(ANN_ELEMENT_TYPE)
+ if element_type_options is None:
return
if isinstance(node.type, ast.List):
- if element_type_opt.length() != 1:
+ if len(element_type_options) != 1:
message.warn(
- 'element-type annotation for a list must have exactly '
- 'one option, not %d options' % (element_type_opt.length(), ),
- options.position)
+ '"element-type" annotation for a list must have exactly '
+ 'one option, not %d options' % (len(element_type_options), ),
+ annotations.position)
return
- node.type.element_type = self._resolve(element_type_opt.one(),
+ node.type.element_type = self._resolve(element_type_options[0],
node.type, node, parent)
elif isinstance(node.type, ast.Map):
- if element_type_opt.length() != 2:
+ if len(element_type_options) != 2:
message.warn(
- 'element-type annotation for a hash table must have exactly '
- 'two options, not %d option(s)' % (element_type_opt.length(), ),
- options.position)
+ '"element-type" annotation for a hash table must have exactly '
+ 'two options, not %d option(s)' % (len(element_type_options), ),
+ annotations.position)
return
- element_type = element_type_opt.flat()
- node.type.key_type = self._resolve(element_type[0],
+ node.type.key_type = self._resolve(element_type_options[0],
node.type, node, parent)
- node.type.value_type = self._resolve(element_type[1],
+ node.type.value_type = self._resolve(element_type_options[1],
node.type, node, parent)
elif isinstance(node.type, ast.Array):
- if element_type_opt.length() != 1:
+ if len(element_type_options) != 1:
message.warn(
- 'element-type annotation for an array must have exactly '
- 'one option, not %d options' % (element_type_opt.length(), ),
- options.position)
+ '"element-type" annotation for an array must have exactly '
+ 'one option, not %d options' % (len(element_type_options), ),
+ annotations.position)
return
- node.type.element_type = self._resolve(element_type_opt.one(),
+ node.type.element_type = self._resolve(element_type_options[0],
node.type, node, parent)
else:
- message.warn_node(parent,
- "Unknown container %r for element-type annotation" % (node.type, ))
+ message.warn(
+ "Unknown container %r for element-type annotation" % (node.type, ),
+ annotations.position)
def _get_transfer_default_param(self, parent, node):
if node.direction in [ast.PARAM_DIRECTION_INOUT,
@@ -459,8 +459,8 @@ usage is void (*_gtk_reserved1)(void);"""
def _get_transfer_default_returntype_basic(self, typeval):
if (typeval.is_equiv(ast.BASIC_GIR_TYPES)
- or typeval.is_const
- or typeval.is_equiv(ast.TYPE_NONE)):
+ or typeval.is_const
+ or typeval.is_equiv(ast.TYPE_NONE)):
return ast.PARAM_TRANSFER_NONE
elif typeval.is_equiv(ast.TYPE_STRING):
# Non-const strings default to FULL
@@ -477,8 +477,8 @@ usage is void (*_gtk_reserved1)(void);"""
assert supercls
if cls is supercls:
return True
- if cls.parent and cls.parent.target_giname != 'GObject.Object':
- return self._is_gi_subclass(cls.parent, supercls_type)
+ if cls.parent_type and cls.parent_type.target_giname != 'GObject.Object':
+ return self._is_gi_subclass(cls.parent_type, supercls_type)
return False
def _get_transfer_default_return(self, parent, node):
@@ -531,24 +531,22 @@ usage is void (*_gtk_reserved1)(void);"""
raise AssertionError(node)
def _apply_annotations_param_ret_common(self, parent, node, tag):
- options = getattr(tag, 'options', {})
+ annotations = tag.annotations if tag else {}
- param_type = options.get(OPT_TYPE)
- if param_type:
- node.type = self._resolve_toplevel(param_type.one(),
+ type_annotation = annotations.get(ANN_TYPE)
+ if type_annotation:
+ node.type = self._resolve_toplevel(type_annotation[0],
node.type, node, parent)
caller_allocates = False
annotated_direction = None
- if (OPT_INOUT in options or
- OPT_INOUT_ALT in options):
+ if ANN_INOUT in annotations:
annotated_direction = ast.PARAM_DIRECTION_INOUT
- elif OPT_OUT in options:
- subtype = options[OPT_OUT]
- if subtype is not None:
- subtype = subtype.one()
+ elif ANN_OUT in annotations:
annotated_direction = ast.PARAM_DIRECTION_OUT
- if subtype in (None, ''):
+
+ options = annotations[ANN_OUT]
+ if len(options) == 0:
if node.type.target_giname and node.type.ctype:
target = self._transformer.lookup_giname(node.type.target_giname)
target = self._transformer.resolve_aliases(target)
@@ -557,11 +555,13 @@ usage is void (*_gtk_reserved1)(void);"""
caller_allocates = (not has_double_indirection and is_structure_or_union)
else:
caller_allocates = False
- elif subtype == OPT_OUT_CALLER_ALLOCATES:
- caller_allocates = True
- elif subtype == OPT_OUT_CALLEE_ALLOCATES:
- caller_allocates = False
- elif OPT_IN in options:
+ else:
+ option = options[0]
+ if option == OPT_OUT_CALLER_ALLOCATES:
+ caller_allocates = True
+ elif option == OPT_OUT_CALLEE_ALLOCATES:
+ caller_allocates = False
+ elif ANN_IN in annotations:
annotated_direction = ast.PARAM_DIRECTION_IN
if (annotated_direction is not None) and (annotated_direction != node.direction):
@@ -570,79 +570,77 @@ usage is void (*_gtk_reserved1)(void);"""
# Also reset the transfer default if we're toggling direction
node.transfer = self._get_transfer_default(parent, node)
- transfer_tag = options.get(OPT_TRANSFER)
- if transfer_tag and transfer_tag.length() == 1:
- transfer = transfer_tag.one()
+ transfer_annotation = annotations.get(ANN_TRANSFER)
+ if transfer_annotation and len(transfer_annotation) == 1:
+ transfer = transfer_annotation[0]
if transfer == OPT_TRANSFER_FLOATING:
transfer = OPT_TRANSFER_NONE
node.transfer = transfer
- self._adjust_container_type(parent, node, options)
+ self._adjust_container_type(parent, node, annotations)
- if (OPT_ALLOW_NONE in options or
- node.type.target_giname == 'Gio.AsyncReadyCallback' or
- node.type.target_giname == 'Gio.Cancellable'):
+ if (ANN_ALLOW_NONE in annotations
+ or node.type.target_giname == 'Gio.AsyncReadyCallback'
+ or node.type.target_giname == 'Gio.Cancellable'):
node.allow_none = True
- if tag is not None and tag.comment is not None:
- node.doc = tag.comment
+ if tag and tag.description:
+ node.doc = tag.description
- if OPT_SKIP in options:
+ if ANN_SKIP in annotations:
node.skip = True
- if options:
- for attribute in options.getall(OPT_ATTRIBUTE):
- node.attributes.append(attribute.flat())
+ if annotations:
+ attributes_annotation = annotations.get(ANN_ATTRIBUTES)
+ if attributes_annotation is not None:
+ for key, value in attributes_annotation.items():
+ if value:
+ node.attributes[key] = value
def _apply_annotations_annotated(self, node, block):
if block is None:
return
- node.doc = block.comment
+ if block.description:
+ node.doc = block.description
- since_tag = block.get_tag(TAG_SINCE)
+ since_tag = block.tags.get(TAG_SINCE)
if since_tag is not None:
- node.version = since_tag.value
+ if since_tag.value:
+ node.version = since_tag.value
+ if since_tag.description:
+ node.version_doc = since_tag.description
- deprecated_tag = block.get_tag(TAG_DEPRECATED)
+ deprecated_tag = block.tags.get(TAG_DEPRECATED)
if deprecated_tag is not None:
- value = deprecated_tag.value
- if ': ' in value:
- colon = value.find(': ')
- version = value[:colon]
- desc = value[colon+2:]
- else:
- desc = value
- version = None
- node.deprecated = desc
- if version is not None:
- node.deprecated_version = version
+ if deprecated_tag.value:
+ node.deprecated = deprecated_tag.value
+ if deprecated_tag.description:
+ node.deprecated_doc = deprecated_tag.description
- stability_tag = block.get_tag(TAG_STABILITY)
+ stability_tag = block.tags.get(TAG_STABILITY)
if stability_tag is not None:
- stability = stability_tag.value.capitalize()
- if stability in ["Stable", "Unstable", "Private", "Internal"]:
- node.stability = stability
- else:
- message.warn('unknown value "%s" for Stability tag' % (
- stability_tag.value), stability_tag.position)
-
- annos_tag = block.get_tag(TAG_ATTRIBUTES)
- if annos_tag is not None:
- for key, value in annos_tag.options.iteritems():
+ if stability_tag.value:
+ node.stability = stability_tag.value
+ if stability_tag.description:
+ node.stability_doc = stability_tag.description
+
+ attributes_annotation = block.annotations.get(ANN_ATTRIBUTES)
+ if attributes_annotation is not None:
+ for key, value in attributes_annotation.items():
if value:
- node.attributes.append((key, value.one()))
+ node.attributes[key] = value
- if OPT_SKIP in block.options:
+ if ANN_SKIP in block.annotations:
node.skip = True
- if OPT_FOREIGN in block.options:
+ if ANN_FOREIGN in block.annotations:
node.foreign = True
- if OPT_CONSTRUCTOR in block.options and isinstance(node, ast.Function):
+ if ANN_CONSTRUCTOR in block.annotations and isinstance(node, ast.Function):
node.is_constructor = True
- if OPT_METHOD in block.options:
+ if ANN_METHOD in block.annotations:
node.is_method = True
def _apply_annotations_alias(self, node, chain):
@@ -650,20 +648,18 @@ usage is void (*_gtk_reserved1)(void);"""
self._apply_annotations_annotated(node, block)
def _apply_annotations_param(self, parent, param, tag):
- if tag:
- options = tag.options
- else:
- options = {}
+ annotations = tag.annotations if tag else {}
+
if isinstance(parent, (ast.Function, ast.VFunction)):
- scope = options.get(OPT_SCOPE)
- if scope and scope.length() == 1:
- param.scope = scope.one()
+ scope_annotation = annotations.get(ANN_SCOPE)
+ if scope_annotation and len(scope_annotation) == 1:
+ param.scope = scope_annotation[0]
param.transfer = ast.PARAM_TRANSFER_NONE
- destroy = options.get(OPT_DESTROY)
- if destroy:
+ destroy_annotation = annotations.get(ANN_DESTROY)
+ if destroy_annotation:
param.destroy_name = self._get_validate_parameter_name(parent,
- destroy.one(),
+ destroy_annotation[0],
param)
if param.destroy_name is not None:
param.scope = ast.PARAM_SCOPE_NOTIFIED
@@ -672,13 +668,14 @@ usage is void (*_gtk_reserved1)(void);"""
# itself. But this helps avoid tripping a warning from finaltransformer,
# since we don't have a way right now to flag this callback a destroy.
destroy_param.scope = ast.PARAM_SCOPE_NOTIFIED
- closure = options.get(OPT_CLOSURE)
- if closure and closure.length() == 1:
+
+ closure_annotation = annotations.get(ANN_CLOSURE)
+ if closure_annotation and len(closure_annotation) == 1:
param.closure_name = self._get_validate_parameter_name(parent,
- closure.one(),
- param)
+ closure_annotation[0],
+ param)
elif isinstance(parent, ast.Callback):
- if OPT_CLOSURE in options:
+ if ANN_CLOSURE in annotations:
# For callbacks, (closure) appears without an
# argument, and tags a parameter that is a closure. We
# represent it (weirdly) in the gir and typelib by
@@ -689,7 +686,7 @@ usage is void (*_gtk_reserved1)(void);"""
def _apply_annotations_return(self, parent, return_, block):
if block:
- tag = block.get_tag(TAG_RETURNS)
+ tag = block.tags.get(TAG_RETURNS)
else:
tag = None
self._apply_annotations_param_ret_common(parent, return_, tag)
@@ -697,13 +694,19 @@ usage is void (*_gtk_reserved1)(void);"""
def _apply_annotations_params(self, parent, params, block):
declparams = set([])
if parent.instance_parameter:
+ if block:
+ doc_param = block.params.get(parent.instance_parameter.argname)
+ else:
+ doc_param = None
+ self._apply_annotations_param(parent, parent.instance_parameter, doc_param)
declparams.add(parent.instance_parameter.argname)
+
for param in params:
if block:
- tag = block.get_param(param.argname)
+ doc_param = block.params.get(param.argname)
else:
- tag = None
- self._apply_annotations_param(parent, param, tag)
+ doc_param = None
+ self._apply_annotations_param(parent, param, doc_param)
declparams.add(param.argname)
if not block:
@@ -714,57 +717,38 @@ usage is void (*_gtk_reserved1)(void);"""
unused = declparams - docparams
for doc_name in unknown:
- # Skip varargs, see #629759
- if doc_name.lower() in ['...', 'varargs', TAG_RETURNS]:
- continue
if len(unused) == 0:
text = ''
elif len(unused) == 1:
(param, ) = unused
text = ', should be %r' % (param, )
else:
- text = ', should be one of %s' % (
- ', '.join(repr(p) for p in unused), )
+ text = ', should be one of %s' % (', '.join(repr(p) for p in unused), )
- tag = block.get_param(doc_name)
- message.warn(
- '%s: unknown parameter %r in documentation comment%s' % (
- block.name, doc_name, text),
- tag.position)
+ param = block.params.get(doc_name)
+ message.warn('%s: unknown parameter %r in documentation '
+ 'comment%s' % (block.name, doc_name, text),
+ param.position)
def _apply_annotations_callable(self, node, chain, block):
self._apply_annotations_annotated(node, block)
self._apply_annotations_params(node, node.parameters, block)
self._apply_annotations_return(node, node.retval, block)
- def _check_arg_annotations(self, parent, params, block):
- if block is None:
- return
- for tag in block.tags.keys():
- if tag == TAG_RETURNS:
- continue
- for param in params:
- if param.argname == tag:
- break
- else:
- message.warn(
- "Annotation for '%s' refers to unknown argument '%s'"
- % (parent.name, tag))
-
def _apply_annotations_field(self, parent, block, field):
if not block:
return
- tag = block.get_param(field.name)
+ tag = block.params.get(field.name)
if not tag:
return
- t = tag.options.get(OPT_TYPE)
- if t:
- field.type = self._transformer.create_type_from_user_string(t.one())
-
+ type_annotation = tag.annotations.get(ANN_TYPE)
+ if type_annotation:
+ field.type = self._transformer.create_type_from_user_string(type_annotation[0])
+ field.doc = tag.description
try:
- self._adjust_container_type(parent, field, tag.options)
- except AttributeError:
- pass
+ self._adjust_container_type(parent, field, tag.annotations)
+ except AttributeError, ex:
+ print ex
def _apply_annotations_property(self, parent, prop):
prefix = self._get_annotation_name(parent)
@@ -772,83 +756,99 @@ usage is void (*_gtk_reserved1)(void);"""
self._apply_annotations_annotated(prop, block)
if not block:
return
- transfer_tag = block.get_tag(TAG_TRANSFER)
- if transfer_tag is not None:
- transfer = transfer_tag.value
+ transfer_annotation = block.annotations.get(ANN_TRANSFER)
+ if transfer_annotation is not None:
+ transfer = transfer_annotation[0]
if transfer == OPT_TRANSFER_FLOATING:
transfer = OPT_TRANSFER_NONE
prop.transfer = transfer
else:
prop.transfer = self._get_transfer_default(parent, prop)
- type_tag = block.get_tag(TAG_TYPE)
- if type_tag:
- prop.type = self._resolve_toplevel(type_tag.value, prop.type, prop, parent)
+ type_annotation = block.annotations.get(ANN_TYPE)
+ if type_annotation:
+ prop.type = self._resolve_toplevel(type_annotation[0], prop.type, prop, parent)
def _apply_annotations_signal(self, parent, signal):
+ names = []
prefix = self._get_annotation_name(parent)
block = self._blocks.get('%s::%s' % (prefix, signal.name))
- self._apply_annotations_annotated(signal, block)
- # We're only attempting to name the signal parameters if
- # the number of parameter tags (@foo) is the same or greater
- # than the number of signal parameters
- if block and len(block.params) > len(signal.parameters):
- names = block.params.items()
- # Resolve real parameter names early, so that in later
- # phase we can refer to them while resolving annotations.
- for i, param in enumerate(signal.parameters):
- param.argname, tag = names[i+1]
- else:
- names = []
+
+ if block:
+ self._apply_annotations_annotated(signal, block)
+
+ # We're only attempting to name the signal parameters if
+ # the number of parameters (@foo) is the same or greater
+ # than the number of signal parameters
+ if len(block.params) > len(signal.parameters):
+ names = block.params.items()
+ # Resolve real parameter names early, so that in later
+ # phase we can refer to them while resolving annotations.
+ for i, param in enumerate(signal.parameters):
+ param.argname, tag = names[i + 1]
+ elif len(signal.parameters) != 0:
+ # Only warn about missing params if there are actually parameters
+ # besides implicit self.
+ message.warn("incorrect number of parameters in comment block, "
+ "parameter annotations will be ignored.", block.position)
+
for i, param in enumerate(signal.parameters):
if names:
- name, tag = names[i+1]
- options = getattr(tag, 'options', {})
- param_type = options.get(OPT_TYPE)
- if param_type:
- param.type = self._resolve_toplevel(param_type.one(), param.type,
- param, parent)
+ name, tag = names[i + 1]
+ if tag:
+ type_annotation = tag.annotations.get(ANN_TYPE)
+ if type_annotation:
+ param.type = self._resolve_toplevel(type_annotation[0], param.type,
+ param, parent)
else:
tag = None
self._apply_annotations_param(signal, param, tag)
self._apply_annotations_return(signal, signal.retval, block)
def _apply_annotations_constant(self, node):
- block = self._blocks.get(node.ctype)
- if not block:
+ block = self._get_block(node)
+ if block is None:
return
- tag = block.get_tag(TAG_VALUE)
- if tag:
- node.value = tag.value
- def _pass_read_annotations2(self, node, chain):
- if isinstance(node, ast.Function):
- self._apply_annotations2_function(node, chain)
- return True
-
- def _apply_annotations2_function(self, node, chain):
- block = self._blocks.get(node.symbol)
+ self._apply_annotations_annotated(node, block)
- self._apply_annotation_rename_to(node, chain, block)
+ value_annotation = block.annotations.get(ANN_VALUE)
+ if value_annotation:
+ node.value = value_annotation[0]
- # Handle virtual invokers
- parent = chain[-1] if chain else None
- if not (block and parent):
- return
- virtual = block.get_tag(TAG_VFUNC)
- if not virtual:
+ def _apply_annotations_enum_members(self, node, block):
+ if block is None:
return
- invoker_name = virtual.value
- matched = False
- for vfunc in parent.virtual_methods:
- if vfunc.name == invoker_name:
- matched = True
- vfunc.invoker = node.name
- # Also merge in annotations
- self._apply_annotations_callable(vfunc, [parent], block)
- break
- if not matched:
- message.warn_node(node,
- "Virtual slot %r not found for %r annotation" % (invoker_name, TAG_VFUNC))
+
+ for m in node.members:
+ param = block.params.get(m.symbol, None)
+ if param and param.description:
+ m.doc = param.description
+
+ def _pass_read_annotations2(self, node, chain):
+ if isinstance(node, ast.Function):
+ block = self._blocks.get(node.symbol)
+
+ self._apply_annotation_rename_to(node, chain, block)
+
+ # Handle virtual invokers
+ parent = chain[-1] if chain else None
+ if (block and parent):
+ virtual_annotation = block.annotations.get(ANN_VFUNC)
+ if virtual_annotation:
+ invoker_name = virtual_annotation[0]
+ matched = False
+ for vfunc in parent.virtual_methods:
+ if vfunc.name == invoker_name:
+ matched = True
+ vfunc.invoker = node.name
+ # Also merge in annotations
+ self._apply_annotations_callable(vfunc, [parent], block)
+ break
+ if not matched:
+ message.warn_node(node,
+ "Virtual slot %r not found for %r annotation" % (invoker_name,
+ ANN_VFUNC))
+ return True
def _resolve_and_filter_type_list(self, typelist):
"""Given a list of Type instances, return a new list of types with
@@ -877,19 +877,18 @@ the ones that failed to resolve removed."""
else:
self._transformer.resolve_type(field.type)
if isinstance(node, (ast.Class, ast.Interface)):
- resolved_parent = None
for parent in node.parent_chain:
try:
self._transformer.resolve_type(parent)
- except ValueError, e:
+ except ValueError:
continue
target = self._transformer.lookup_typenode(parent)
if target:
- node.parent = parent
+ node.parent_type = parent
break
else:
if isinstance(node, ast.Interface):
- node.parent = ast.Type(target_giname='GObject.Object')
+ node.parent_type = ast.Type(target_giname='GObject.Object')
for prop in node.properties:
self._transformer.resolve_type(prop.type)
for sig in node.signals:
@@ -1156,9 +1155,9 @@ method or constructor of some type."""
origin_node = self._get_constructor_class(func, subsymbol)
if origin_node is None:
if func.is_constructor:
- message.warn_node(func,
- "Can't find matching type for constructor; symbol=%r" \
- % (func.symbol, ))
+ message.warn_node(
+ func,
+ "Can't find matching type for constructor; symbol=%r" % (func.symbol, ))
return False
# Some sanity checks; only objects and boxeds can have ctors
@@ -1184,26 +1183,26 @@ method or constructor of some type."""
while parent and (not parent.gi_name == 'GObject.Object'):
if parent == target:
break
- if parent.parent:
- parent = self._transformer.lookup_typenode(parent.parent)
+ if parent.parent_type:
+ parent = self._transformer.lookup_typenode(parent.parent_type)
else:
parent = None
if parent is None:
message.warn_node(func,
- "Return value is not superclass for constructor; "
- "symbol=%r constructed=%r return=%r" % (
- func.symbol,
- str(origin_node.create_type()),
- str(func.retval.type)))
+ "Return value is not superclass for constructor; "
+ "symbol=%r constructed=%r return=%r" %
+ (func.symbol,
+ str(origin_node.create_type()),
+ str(func.retval.type)))
return False
else:
if origin_node != target:
message.warn_node(func,
- "Constructor return type mismatch symbol=%r "
- "constructed=%r return=%r" % (
- func.symbol,
- str(origin_node.create_type()),
- str(func.retval.type)))
+ "Constructor return type mismatch symbol=%r "
+ "constructed=%r return=%r" %
+ (func.symbol,
+ str(origin_node.create_type()),
+ str(func.retval.type)))
return False
return True
@@ -1282,7 +1281,7 @@ method or constructor of some type."""
params = node.parameters
# First, do defaults for well-known callback types
- for i, param in enumerate(params):
+ for param in params:
argnode = self._transformer.lookup_typenode(param.type)
if isinstance(argnode, ast.Callback):
if param.type.target_giname in ('Gio.AsyncReadyCallback',
@@ -1291,7 +1290,7 @@ method or constructor of some type."""
param.transfer = ast.PARAM_TRANSFER_NONE
callback_param = None
- for i, param in enumerate(params):
+ for param in params:
argnode = self._transformer.lookup_typenode(param.type)
is_destroynotify = False
if isinstance(argnode, ast.Callback):