summaryrefslogtreecommitdiff
path: root/giscanner
diff options
context:
space:
mode:
authorJohan Dahlin <jdahlin@async.com.br>2009-01-12 20:11:44 +0000
committerJohan Dahlin <johan@src.gnome.org>2009-01-12 20:11:44 +0000
commit7dbbda9abea9882d2c98726f382a905fa8738706 (patch)
treebdf438fc921de19ddee90d7f2c5972cf76fec48f /giscanner
parentba4ee2e606545ac703941698aa25e6d865e6976f (diff)
downloadgobject-introspection-7dbbda9abea9882d2c98726f382a905fa8738706.tar.gz
Bug 563794 - Redo annotation parsing & applying
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
Diffstat (limited to 'giscanner')
-rw-r--r--giscanner/Makefile.am1
-rw-r--r--giscanner/annotationparser.py505
-rw-r--r--giscanner/ast.py32
-rw-r--r--giscanner/dumper.py2
-rw-r--r--giscanner/girparser.py11
-rw-r--r--giscanner/giscannermodule.c128
-rw-r--r--giscanner/glibtransformer.py36
-rw-r--r--giscanner/scannerlexer.l172
-rw-r--r--giscanner/sourcescanner.c33
-rw-r--r--giscanner/sourcescanner.h19
-rw-r--r--giscanner/sourcescanner.py11
-rw-r--r--giscanner/transformer.py390
-rw-r--r--giscanner/xmlwriter.py2
13 files changed, 659 insertions, 683 deletions
diff --git a/giscanner/Makefile.am b/giscanner/Makefile.am
index 1d6942b4..bc2977f6 100644
--- a/giscanner/Makefile.am
+++ b/giscanner/Makefile.am
@@ -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
index 00000000..630508a9
--- /dev/null
+++ b/giscanner/annotationparser.py
@@ -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)
diff --git a/giscanner/ast.py b/giscanner/ast.py
index 6bd858b2..c5dc436c 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -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):
diff --git a/giscanner/dumper.py b/giscanner/dumper.py
index c85ae807..45dcc25f 100644
--- a/giscanner/dumper.py
+++ b/giscanner/dumper.py
@@ -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)
diff --git a/giscanner/girparser.py b/giscanner/girparser.py
index 17f53521..3e2432ed 100644
--- a/giscanner/girparser.py
+++ b/giscanner/girparser.py
@@ -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))
diff --git a/giscanner/giscannermodule.c b/giscanner/giscannermodule.c
index df1ba095..afa4c29c 100644
--- a/giscanner/giscannermodule.c
+++ b/giscanner/giscannermodule.c
@@ -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);
diff --git a/giscanner/glibtransformer.py b/giscanner/glibtransformer.py
index aacaa508..ee39862e 100644
--- a/giscanner/glibtransformer.py
+++ b/giscanner/glibtransformer.py
@@ -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
diff --git a/giscanner/scannerlexer.l b/giscanner/scannerlexer.l
index 27072cd4..53603e25 100644
--- a/giscanner/scannerlexer.l
+++ b/giscanner/scannerlexer.l
@@ -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
diff --git a/giscanner/sourcescanner.c b/giscanner/sourcescanner.c
index 08f4b586..cf412362 100644
--- a/giscanner/sourcescanner.c
+++ b/giscanner/sourcescanner.c
@@ -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);
}
diff --git a/giscanner/sourcescanner.h b/giscanner/sourcescanner.h
index 3a391d85..69417d11 100644
--- a/giscanner/sourcescanner.h
+++ b/giscanner/sourcescanner.h
@@ -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);
diff --git a/giscanner/sourcescanner.py b/giscanner/sourcescanner.py
index 3188b262..5018bf43 100644
--- a/giscanner/sourcescanner.py
+++ b/giscanner/sourcescanner.py
@@ -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
diff --git a/giscanner/transformer.py b/giscanner/transformer.py
index 0ed7ca00..7493a353 100644
--- a/giscanner/transformer.py
+++ b/giscanner/transformer.py
@@ -19,14 +19,12 @@
#
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:
diff --git a/giscanner/xmlwriter.py b/giscanner/xmlwriter.py
index 6fd03f44..bed3f991 100644
--- a/giscanner/xmlwriter.py
+++ b/giscanner/xmlwriter.py
@@ -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()