girparser.py 26.9 KB
Newer Older
1 2 3 4
# -*- Mode: Python -*-
# GObject-Introspection - a framework for introspecting GObject libraries
# Copyright (C) 2008  Johan Dahlin
#
5 6 7 8
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
9
#
10
# This library is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12 13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
14
#
15 16 17 18
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
19 20
#

21 22
import os

23
from collections import OrderedDict
24
from xml.etree.cElementTree import parse
25

Colin Walters's avatar
Colin Walters committed
26
from . import ast
27
from .girwriter import COMPATIBLE_GIR_VERSION
28
from .message import Position
29

30
CORE_NS = "http://www.gtk.org/introspection/core/1.0"
31
C_NS = "http://www.gtk.org/introspection/c/1.0"
32
GLIB_NS = "http://www.gtk.org/introspection/glib/1.0"
33

Johan Dahlin's avatar
Johan Dahlin committed
34

35 36 37
def _corens(tag):
    return '{%s}%s' % (CORE_NS, tag)

Johan Dahlin's avatar
Johan Dahlin committed
38

39 40
def _glibns(tag):
    return '{%s}%s' % (GLIB_NS, tag)
41

42

43 44
def _cns(tag):
    return '{%s}%s' % (C_NS, tag)
45

46

47
class GIRParser(object):
Johan Dahlin's avatar
Johan Dahlin committed
48

49 50
    def __init__(self, types_only=False):
        self._types_only = types_only
51
        self._namespace = None
52
        self._filename_stack = []
53

54
    # Public API
55

56
    def parse(self, filename):
57 58
        filename = os.path.abspath(filename)
        self._filename_stack.append(filename)
59 60
        tree = parse(filename)
        self.parse_tree(tree)
61
        self._filename_stack.pop()
62

63 64
    def parse_tree(self, tree):
        self._namespace = None
65
        self._pkgconfig_packages = set()
66
        self._includes = set()
Colin Walters's avatar
Colin Walters committed
67 68
        self._c_includes = set()
        self._c_prefix = None
69
        self._parse_api(tree.getroot())
70 71 72 73

    def get_namespace(self):
        return self._namespace

74
    # Private
75

76 77 78 79 80 81 82 83 84
    def _find_first_child(self, node, name_or_names):
        if isinstance(name_or_names, str):
            for child in node.getchildren():
                if child.tag == name_or_names:
                    return child
        else:
            for child in node.getchildren():
                if child.tag in name_or_names:
                    return child
Colin Walters's avatar
Colin Walters committed
85 86 87 88 89
        return None

    def _find_children(self, node, name):
        return [child for child in node.getchildren() if child.tag == name]

90 91 92 93 94 95 96 97
    def _get_current_file(self):
        if not self._filename_stack:
            return None
        cwd = os.getcwd() + os.sep
        curfile = self._filename_stack[-1]
        if curfile.startswith(cwd):
            return curfile[len(cwd):]
        return curfile
Colin Walters's avatar
Colin Walters committed
98

99
    def _parse_api(self, root):
100
        assert root.tag == _corens('repository')
101 102
        version = root.attrib['version']
        if version != COMPATIBLE_GIR_VERSION:
103 104
            raise SystemExit("%s: Incompatible version %s (supported: %s)" %
                             (self._get_current_file(), version, COMPATIBLE_GIR_VERSION))
105

106 107
        for node in root.getchildren():
            if node.tag == _corens('include'):
108
                self._parse_include(node)
109 110
            elif node.tag == _corens('package'):
                self._parse_pkgconfig_package(node)
Colin Walters's avatar
Colin Walters committed
111 112
            elif node.tag == _cns('include'):
                self._parse_c_include(node)
113

114 115
        ns = root.find(_corens('namespace'))
        assert ns is not None
Colin Walters's avatar
Colin Walters committed
116 117 118 119 120 121 122
        identifier_prefixes = ns.attrib.get(_cns('identifier-prefixes'))
        if identifier_prefixes:
            identifier_prefixes = identifier_prefixes.split(',')
        symbol_prefixes = ns.attrib.get(_cns('symbol-prefixes'))
        if symbol_prefixes:
            symbol_prefixes = symbol_prefixes.split(',')
        self._namespace = ast.Namespace(ns.attrib['name'],
123 124 125
                                        ns.attrib['version'],
                                        identifier_prefixes=identifier_prefixes,
                                        symbol_prefixes=symbol_prefixes)
126
        if 'shared-library' in ns.attrib:
127
            self._namespace.shared_libraries = ns.attrib['shared-library'].split(',')
128
        self._namespace.includes = self._includes
129
        self._namespace.c_includes = self._c_includes
130
        self._namespace.exported_packages = self._pkgconfig_packages
131 132 133 134 135 136 137 138 139 140

        parser_methods = {
            _corens('alias'): self._parse_alias,
            _corens('bitfield'): self._parse_enumeration_bitfield,
            _corens('callback'): self._parse_callback,
            _corens('class'): self._parse_object_interface,
            _corens('enumeration'): self._parse_enumeration_bitfield,
            _corens('interface'): self._parse_object_interface,
            _corens('record'): self._parse_record,
            _corens('union'): self._parse_union,
141
            _glibns('boxed'): self._parse_boxed}
142

143 144 145 146
        if not self._types_only:
            parser_methods[_corens('constant')] = self._parse_constant
            parser_methods[_corens('function')] = self._parse_function

147 148 149 150 151 152
        for node in ns.getchildren():
            method = parser_methods.get(node.tag)
            if method is not None:
                method(node)

    def _parse_include(self, node):
153
        include = ast.Include(node.attrib['name'], node.attrib['version'])
154
        self._includes.add(include)
155

156 157 158
    def _parse_pkgconfig_package(self, node):
        self._pkgconfig_packages.add(node.attrib['name'])

Colin Walters's avatar
Colin Walters committed
159 160 161
    def _parse_c_include(self, node):
        self._c_includes.add(node.attrib['name'])

162
    def _parse_alias(self, node):
163
        typeval = self._parse_type(node)
164
        alias = ast.Alias(node.attrib['name'], typeval, node.attrib.get(_cns('type')))
165
        self._parse_generic_attribs(node, alias)
Colin Walters's avatar
Colin Walters committed
166 167 168 169
        self._namespace.append(alias)

    def _parse_generic_attribs(self, node, obj):
        assert isinstance(obj, ast.Annotated)
170 171 172 173 174 175
        skip = node.attrib.get('skip')
        if skip:
            try:
                obj.skip = int(skip) > 0
            except ValueError:
                obj.skip = False
176 177
        introspectable = node.attrib.get('introspectable')
        if introspectable:
178 179 180 181
            try:
                obj.introspectable = int(introspectable) > 0
            except ValueError:
                obj.introspectable = False
182 183
        if self._types_only:
            return
Colin Walters's avatar
Colin Walters committed
184 185
        doc = node.find(_corens('doc'))
        if doc is not None:
186 187
            if doc.text:
                obj.doc = doc.text
188 189
                obj.doc_position = Position(doc.attrib.get('filename', '<unknown>'),
                                            doc.attrib.get('line', None),
190
                                            doc.attrib.get('column', None))
Colin Walters's avatar
Colin Walters committed
191 192 193
        version = node.attrib.get('version')
        if version:
            obj.version = version
194 195 196 197 198
        version_doc = node.find(_corens('doc-version'))
        if version_doc is not None:
            if version_doc.text:
                obj.version_doc = version_doc.text
        deprecated = node.attrib.get('deprecated-version')
Colin Walters's avatar
Colin Walters committed
199 200
        if deprecated:
            obj.deprecated = deprecated
201 202 203 204 205 206 207 208 209 210 211
        deprecated_doc = node.find(_corens('doc-deprecated'))
        if deprecated_doc is not None:
            if deprecated_doc.text:
                obj.deprecated_doc = deprecated_doc.text
        stability = node.attrib.get('stability')
        if stability:
            obj.stability = stability
        stability_doc = node.find(_corens('doc-stability'))
        if stability_doc is not None:
            if stability_doc.text:
                obj.stability_doc = stability_doc.text
212 213 214 215 216 217 218 219
        attributes = node.findall(_corens('attribute'))
        if attributes:
            attributes_ = OrderedDict()
            for attribute in attributes:
                name = attribute.attrib.get('name')
                value = attribute.attrib.get('value')
                attributes_[name] = value
            obj.attributes = attributes_
220

221 222 223 224 225 226 227 228 229 230 231 232 233 234
        if hasattr(obj, 'add_file_position'):
            positions = sorted(node.findall(_corens('source-position')),
                               key=lambda x: (x.attrib['filename'],
                                              int(x.attrib['line'])))
            for position in positions:
                if 'column' in position.attrib:
                    column = int(position.attrib['column'])
                else:
                    column = None

                obj.add_file_position(Position(position.attrib['filename'],
                                               int(position.attrib['line']),
                                               column))

235
    def _parse_object_interface(self, node):
Colin Walters's avatar
Colin Walters committed
236 237 238 239 240 241
        parent = node.attrib.get('parent')
        if parent:
            parent_type = self._namespace.type_from_name(parent)
        else:
            parent_type = None

242
        ctor_kwargs = {'name': node.attrib['name'],
243
                       'parent_type': parent_type,
244
                       'gtype_name': node.attrib[_glibns('type-name')],
Colin Walters's avatar
Colin Walters committed
245 246 247
                       'get_type': node.attrib[_glibns('get-type')],
                       'c_symbol_prefix': node.attrib.get(_cns('symbol-prefix')),
                       'ctype': node.attrib.get(_cns('type'))}
248
        if node.tag == _corens('interface'):
Colin Walters's avatar
Colin Walters committed
249
            klass = ast.Interface
250
        elif node.tag == _corens('class'):
Colin Walters's avatar
Colin Walters committed
251
            klass = ast.Class
252 253
            is_abstract = node.attrib.get('abstract')
            is_abstract = is_abstract and is_abstract != '0'
Colin Walters's avatar
Colin Walters committed
254
            ctor_kwargs['is_abstract'] = is_abstract
255 256 257
        else:
            raise AssertionError(node)

258
        obj = klass(**ctor_kwargs)
Colin Walters's avatar
Colin Walters committed
259 260 261 262
        self._parse_generic_attribs(node, obj)
        type_struct = node.attrib.get(_glibns('type-struct'))
        if type_struct:
            obj.glib_type_struct = self._namespace.type_from_name(type_struct)
263 264 265 266 267 268 269 270
        if klass == ast.Class:
            is_fundamental = node.attrib.get(_glibns('fundamental'))
            if is_fundamental and is_fundamental != '0':
                obj.fundamental = True
            for func_id in ['ref-func', 'unref-func',
                            'set-value-func', 'get-value-func']:
                func_name = node.attrib.get(_glibns(func_id))
                obj.__dict__[func_id.replace('-', '_')] = func_name
271

272
        if self._types_only:
273
            self._namespace.append(obj)
274
            return
275

Colin Walters's avatar
Colin Walters committed
276 277 278 279 280
        for iface in self._find_children(node, _corens('implements')):
            obj.interfaces.append(self._namespace.type_from_name(iface.attrib['name']))
        for iface in self._find_children(node, _corens('prerequisite')):
            obj.prerequisites.append(self._namespace.type_from_name(iface.attrib['name']))
        for func_node in self._find_children(node, _corens('function')):
281
            func = self._parse_function_common(func_node, ast.Function, obj)
Colin Walters's avatar
Colin Walters committed
282 283
            obj.static_methods.append(func)
        for method in self._find_children(node, _corens('method')):
284
            func = self._parse_function_common(method, ast.Function, obj)
285 286
            func.is_method = True
            obj.methods.append(func)
Colin Walters's avatar
Colin Walters committed
287
        for method in self._find_children(node, _corens('virtual-method')):
288
            func = self._parse_function_common(method, ast.VFunction, obj)
Colin Walters's avatar
Colin Walters committed
289 290 291 292 293
            self._parse_generic_attribs(method, func)
            func.is_method = True
            func.invoker = method.get('invoker')
            obj.virtual_methods.append(func)
        for ctor in self._find_children(node, _corens('constructor')):
294
            func = self._parse_function_common(ctor, ast.Function, obj)
Colin Walters's avatar
Colin Walters committed
295 296
            func.is_constructor = True
            obj.constructors.append(func)
297
        obj.fields.extend(self._parse_fields(node, obj))
Colin Walters's avatar
Colin Walters committed
298
        for prop in self._find_children(node, _corens('property')):
299
            obj.properties.append(self._parse_property(prop, obj))
Colin Walters's avatar
Colin Walters committed
300
        for signal in self._find_children(node, _glibns('signal')):
301
            obj.signals.append(self._parse_function_common(signal, ast.Signal, obj))
302

303 304
        self._namespace.append(obj)

305
    def _parse_callback(self, node):
Colin Walters's avatar
Colin Walters committed
306 307
        callback = self._parse_function_common(node, ast.Callback)
        self._namespace.append(callback)
308 309

    def _parse_function(self, node):
Colin Walters's avatar
Colin Walters committed
310 311
        function = self._parse_function_common(node, ast.Function)
        self._namespace.append(function)
312

313 314 315 316 317 318
    def _parse_parameter(self, node):
        typeval = self._parse_type(node)
        param = ast.Parameter(node.attrib.get('name'),
                              typeval,
                              node.attrib.get('direction') or ast.PARAM_DIRECTION_IN,
                              node.attrib.get('transfer-ownership'),
319 320
                              node.attrib.get('nullable') == '1',
                              node.attrib.get('optional') == '1',
321 322 323 324 325 326
                              node.attrib.get('allow-none') == '1',
                              node.attrib.get('scope'),
                              node.attrib.get('caller-allocates') == '1')
        self._parse_generic_attribs(node, param)
        return param

327
    def _parse_function_common(self, node, klass, parent=None):
328
        name = node.attrib['name']
329 330 331
        returnnode = node.find(_corens('return-value'))
        if not returnnode:
            raise ValueError('node %r has no return-value' % (name, ))
332
        transfer = returnnode.attrib.get('transfer-ownership')
333
        nullable = returnnode.attrib.get('nullable') == '1'
334
        retval = ast.Return(self._parse_type(returnnode), nullable, False, transfer)
Colin Walters's avatar
Colin Walters committed
335
        self._parse_generic_attribs(returnnode, retval)
336
        parameters = []
337

Colin Walters's avatar
Colin Walters committed
338 339 340 341
        throws = (node.attrib.get('throws') == '1')

        if klass is ast.Callback:
            func = klass(name, retval, parameters, throws,
342
                         node.attrib.get(_cns('type')))
Colin Walters's avatar
Colin Walters committed
343
        elif klass is ast.Function:
344
            identifier = node.attrib.get(_cns('identifier'))
Colin Walters's avatar
Colin Walters committed
345 346 347
            func = klass(name, retval, parameters, throws, identifier)
        elif klass is ast.VFunction:
            func = klass(name, retval, parameters, throws)
Johan Dahlin's avatar
Johan Dahlin committed
348 349
        elif klass is ast.Signal:
            func = klass(name, retval, parameters,
350
                         when=node.attrib.get('when'),
Johan Dahlin's avatar
Johan Dahlin committed
351 352 353 354
                         no_recurse=node.attrib.get('no-recurse', '0') == '1',
                         detailed=node.attrib.get('detailed', '0') == '1',
                         action=node.attrib.get('action', '0') == '1',
                         no_hooks=node.attrib.get('no-hooks', '0') == '1')
Colin Walters's avatar
Colin Walters committed
355 356
        else:
            assert False
357

358 359
        func.shadows = node.attrib.get('shadows', None)
        func.shadowed_by = node.attrib.get('shadowed-by', None)
360
        func.moved_to = node.attrib.get('moved-to', None)
361
        func.parent = parent
362

363
        parameters_node = node.find(_corens('parameters'))
364
        if (parameters_node is not None):
365 366 367
            paramnode = self._find_first_child(parameters_node, _corens('instance-parameter'))
            if paramnode:
                func.instance_parameter = self._parse_parameter(paramnode)
Colin Walters's avatar
Colin Walters committed
368
            for paramnode in self._find_children(parameters_node, _corens('parameter')):
369
                parameters.append(self._parse_parameter(paramnode))
Colin Walters's avatar
Colin Walters committed
370 371 372
            for i, paramnode in enumerate(self._find_children(parameters_node,
                                                              _corens('parameter'))):
                param = parameters[i]
373
                self._parse_type_array_length(parameters, paramnode, param.type)
Colin Walters's avatar
Colin Walters committed
374 375 376 377 378 379 380 381 382 383 384
                closure = paramnode.attrib.get('closure')
                if closure:
                    idx = int(closure)
                    assert idx < len(parameters), "%d >= %d" % (idx, len(parameters))
                    param.closure_name = parameters[idx].argname
                destroy = paramnode.attrib.get('destroy')
                if destroy:
                    idx = int(destroy)
                    assert idx < len(parameters), "%d >= %d" % (idx, len(parameters))
                    param.destroy_name = parameters[idx].argname

385
        self._parse_type_array_length(parameters, returnnode, retval.type)
Colin Walters's avatar
Colin Walters committed
386

387 388 389
        # Re-set the function's parameters to notify it of changes to the list.
        func.parameters = parameters

Colin Walters's avatar
Colin Walters committed
390
        self._parse_generic_attribs(node, func)
391

392
        self._namespace.track(func)
393
        return func
394

395
    def _parse_fields(self, node, obj):
Colin Walters's avatar
Colin Walters committed
396 397 398 399
        res = []
        names = (_corens('field'), _corens('record'), _corens('union'), _corens('callback'))
        for child in node.getchildren():
            if child.tag in names:
400
                fieldobj = self._parse_field(child, obj)
Colin Walters's avatar
Colin Walters committed
401 402 403
                res.append(fieldobj)
        return res

404 405 406 407 408 409 410
    def _parse_compound(self, cls, node):
        compound = cls(node.attrib.get('name'),
                       ctype=node.attrib.get(_cns('type')),
                       disguised=node.attrib.get('disguised') == '1',
                       gtype_name=node.attrib.get(_glibns('type-name')),
                       get_type=node.attrib.get(_glibns('get-type')),
                       c_symbol_prefix=node.attrib.get(_cns('symbol-prefix')))
Colin Walters's avatar
Colin Walters committed
411
        if node.attrib.get('foreign') == '1':
412 413
            compound.foreign = True
        self._parse_generic_attribs(node, compound)
414
        if not self._types_only:
415
            compound.fields.extend(self._parse_fields(node, compound))
416
            for method in self._find_children(node, _corens('method')):
417 418 419
                func = self._parse_function_common(method, ast.Function, compound)
                func.is_method = True
                compound.methods.append(func)
420 421 422
            for i, fieldnode in enumerate(self._find_children(node, _corens('field'))):
                field = compound.fields[i]
                self._parse_type_array_length(compound.fields, fieldnode, field.type)
423 424
            for func in self._find_children(node, _corens('function')):
                compound.static_methods.append(
425
                    self._parse_function_common(func, ast.Function, compound))
426
            for ctor in self._find_children(node, _corens('constructor')):
427 428 429
                func = self._parse_function_common(ctor, ast.Function, compound)
                func.is_constructor = True
                compound.constructors.append(func)
430 431 432 433 434 435 436 437 438
        return compound

    def _parse_record(self, node, anonymous=False):
        struct = self._parse_compound(ast.Record, node)
        is_gtype_struct_for = node.attrib.get(_glibns('is-gtype-struct-for'))
        if is_gtype_struct_for is not None:
            struct.is_gtype_struct_for = self._namespace.type_from_name(is_gtype_struct_for)
        if not anonymous:
            self._namespace.append(struct)
Colin Walters's avatar
Colin Walters committed
439
        return struct
440

Colin Walters's avatar
Colin Walters committed
441
    def _parse_union(self, node, anonymous=False):
442
        union = self._parse_compound(ast.Union, node)
Colin Walters's avatar
Colin Walters committed
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
        if not anonymous:
            self._namespace.append(union)
        return union

    def _parse_type_simple(self, typenode):
        # ast.Fields can contain inline callbacks
        if typenode.tag == _corens('callback'):
            typeval = self._namespace.type_from_name(typenode.attrib['name'])
            typeval.ctype = typenode.attrib.get(_cns('type'))
            return typeval
        # ast.Arrays have their own toplevel XML
        elif typenode.tag == _corens('array'):
            array_type = typenode.attrib.get('name')
            element_type = self._parse_type(typenode)
            array_ctype = typenode.attrib.get(_cns('type'))
            ret = ast.Array(array_type, element_type, ctype=array_ctype)
            # zero-terminated defaults to true...
            zero = typenode.attrib.get('zero-terminated')
            if zero and zero == '0':
                ret.zeroterminated = False
            fixed_size = typenode.attrib.get('fixed-size')
            if fixed_size:
                ret.size = int(fixed_size)
466

467
            return ret
Colin Walters's avatar
Colin Walters committed
468 469 470 471 472 473 474 475 476 477
        elif typenode.tag == _corens('varargs'):
            return ast.Varargs()
        elif typenode.tag == _corens('type'):
            name = typenode.attrib.get('name')
            ctype = typenode.attrib.get(_cns('type'))
            if name is None:
                if ctype is None:
                    return ast.TypeUnknown()
                return ast.Type(ctype=ctype)
            elif name in ['GLib.List', 'GLib.SList']:
478
                subchild = self._find_first_child(typenode,
479 480
                                                  list(map(_corens, ('callback', 'array',
                                                                '    varargs', 'type'))))
Colin Walters's avatar
Colin Walters committed
481 482 483 484 485 486 487
                if subchild is not None:
                    element_type = self._parse_type(typenode)
                else:
                    element_type = ast.TYPE_ANY
                return ast.List(name, element_type, ctype=ctype)
            elif name == 'GLib.HashTable':
                subchildren = self._find_children(typenode, _corens('type'))
488
                subchildren_types = list(map(self._parse_type_simple, subchildren))
Colin Walters's avatar
Colin Walters committed
489 490
                while len(subchildren_types) < 2:
                    subchildren_types.append(ast.TYPE_ANY)
491
                return ast.Map(subchildren_types[0], subchildren_types[1], ctype=ctype)
Colin Walters's avatar
Colin Walters committed
492 493 494 495
            else:
                return self._namespace.type_from_name(name, ctype)
        else:
            assert False, "Failed to parse inner type"
496

Colin Walters's avatar
Colin Walters committed
497 498 499 500 501 502 503
    def _parse_type(self, node):
        for name in map(_corens, ('callback', 'array', 'varargs', 'type')):
            typenode = node.find(name)
            if typenode is not None:
                return self._parse_type_simple(typenode)
        assert False, "Failed to parse toplevel type"

504 505
    def _parse_type_array_length(self, siblings, node, typeval):
        """A hack necessary to handle the integer parameter/field indexes on
Colin Walters's avatar
Colin Walters committed
506 507 508 509 510 511 512
           array types."""
        typenode = node.find(_corens('array'))
        if typenode is None:
            return
        lenidx = typenode.attrib.get('length')
        if lenidx is not None:
            idx = int(lenidx)
513
            assert idx < len(siblings), "%r %d >= %d" % (siblings, idx, len(siblings))
514 515 516 517
            if isinstance(siblings[idx], ast.Field):
                typeval.length_param_name = siblings[idx].name
            else:
                typeval.length_param_name = siblings[idx].argname
Johan Dahlin's avatar
Johan Dahlin committed
518 519

    def _parse_boxed(self, node):
Colin Walters's avatar
Colin Walters committed
520 521 522 523
        obj = ast.Boxed(node.attrib[_glibns('name')],
                        gtype_name=node.attrib[_glibns('type-name')],
                        get_type=node.attrib[_glibns('get-type')],
                        c_symbol_prefix=node.attrib.get(_cns('symbol-prefix')))
Colin Walters's avatar
Colin Walters committed
524
        self._parse_generic_attribs(node, obj)
525

526
        if self._types_only:
527
            self._namespace.append(obj)
528
            return
529

Colin Walters's avatar
Colin Walters committed
530
        for method in self._find_children(node, _corens('method')):
531
            func = self._parse_function_common(method, ast.Function, obj)
532 533
            func.is_method = True
            obj.methods.append(func)
Colin Walters's avatar
Colin Walters committed
534
        for ctor in self._find_children(node, _corens('constructor')):
535
            obj.constructors.append(
536
                self._parse_function_common(ctor, ast.Function, obj))
Colin Walters's avatar
Colin Walters committed
537
        for callback in self._find_children(node, _corens('callback')):
538
            obj.fields.append(
539
                self._parse_function_common(callback, ast.Callback, obj))
540
        self._namespace.append(obj)
Johan Dahlin's avatar
Johan Dahlin committed
541

542
    def _parse_field(self, node, parent):
Colin Walters's avatar
Colin Walters committed
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
        type_node = None
        anonymous_node = None
        if node.tag in map(_corens, ('record', 'union')):
            anonymous_elt = node
        else:
            anonymous_elt = self._find_first_child(node, _corens('callback'))
        if anonymous_elt is not None:
            if anonymous_elt.tag == _corens('callback'):
                anonymous_node = self._parse_function_common(anonymous_elt, ast.Callback)
            elif anonymous_elt.tag == _corens('record'):
                anonymous_node = self._parse_record(anonymous_elt, anonymous=True)
            elif anonymous_elt.tag == _corens('union'):
                anonymous_node = self._parse_union(anonymous_elt, anonymous=True)
            else:
                assert False, anonymous_elt.tag
        else:
            assert node.tag == _corens('field'), node.tag
            type_node = self._parse_type(node)
        field = ast.Field(node.attrib.get('name'),
562 563 564 565 566
                          type_node,
                          node.attrib.get('readable') != '0',
                          node.attrib.get('writable') == '1',
                          node.attrib.get('bits'),
                          anonymous_node=anonymous_node)
567
        field.private = node.attrib.get('private') == '1'
568
        field.parent = parent
Colin Walters's avatar
Colin Walters committed
569 570
        self._parse_generic_attribs(node, field)
        return field
571

572
    def _parse_property(self, node, parent):
Colin Walters's avatar
Colin Walters committed
573
        prop = ast.Property(node.attrib['name'],
574 575 576 577 578 579
                            self._parse_type(node),
                            node.attrib.get('readable') != '0',
                            node.attrib.get('writable') == '1',
                            node.attrib.get('construct') == '1',
                            node.attrib.get('construct-only') == '1',
                            node.attrib.get('transfer-ownership'))
Colin Walters's avatar
Colin Walters committed
580
        self._parse_generic_attribs(node, prop)
581
        prop.parent = parent
Colin Walters's avatar
Colin Walters committed
582
        return prop
583

584
    def _parse_member(self, node):
Colin Walters's avatar
Colin Walters committed
585 586 587 588
        member = ast.Member(node.attrib['name'],
                            node.attrib['value'],
                            node.attrib.get(_cns('identifier')),
                            node.attrib.get(_glibns('nick')))
Colin Walters's avatar
Colin Walters committed
589 590
        self._parse_generic_attribs(node, member)
        return member
591

592 593
    def _parse_constant(self, node):
        type_node = self._parse_type(node)
Colin Walters's avatar
Colin Walters committed
594
        constant = ast.Constant(node.attrib['name'],
595 596 597
                                type_node,
                                node.attrib['value'],
                                node.attrib.get(_cns('type')))
Colin Walters's avatar
Colin Walters committed
598 599
        self._parse_generic_attribs(node, constant)
        self._namespace.append(constant)
600

601
    def _parse_enumeration_bitfield(self, node):
602 603 604 605
        name = node.attrib.get('name')
        ctype = node.attrib.get(_cns('type'))
        get_type = node.attrib.get(_glibns('get-type'))
        type_name = node.attrib.get(_glibns('type-name'))
606
        glib_error_domain = node.attrib.get(_glibns('error-domain'))
Colin Walters's avatar
Colin Walters committed
607 608
        if node.tag == _corens('bitfield'):
            klass = ast.Bitfield
609
        else:
Colin Walters's avatar
Colin Walters committed
610
            klass = ast.Enum
611
        members = []
Colin Walters's avatar
Colin Walters committed
612 613 614 615
        obj = klass(name, ctype,
                    members=members,
                    gtype_name=type_name,
                    get_type=get_type)
616
        obj.error_domain = glib_error_domain
Colin Walters's avatar
Colin Walters committed
617
        obj.ctype = ctype
Colin Walters's avatar
Colin Walters committed
618
        self._parse_generic_attribs(node, obj)
619

620
        if self._types_only:
621
            self._namespace.append(obj)
622
            return
623

624 625 626 627
        for member_node in self._find_children(node, _corens('member')):
            member = self._parse_member(member_node)
            member.parent = obj
            members.append(member)
628 629
        for func_node in self._find_children(node, _corens('function')):
            func = self._parse_function_common(func_node, ast.Function)
630
            func.parent = obj
631
            obj.static_methods.append(func)
632
        self._namespace.append(obj)