640eaef8c41b576d8be3fa039f93905237a5fab6
[gnome.gobject-introspection] / giscanner / girparser.py
1 # -*- Mode: Python -*-
2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008  Johan Dahlin
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 # 02110-1301, USA.
19 #
20
21 from xml.etree.cElementTree import parse
22
23 from .ast import (Alias, Array, Callback, Enum, Function, Field, Namespace,
24                   Parameter, Property, Return, Union, Struct, Type, Varargs)
25 from .glibast import (GLibEnum, GLibEnumMember, GLibFlags,
26                       GLibInterface, GLibObject, GLibBoxedStruct,
27                       GLibBoxedUnion, GLibBoxedOther)
28
29 CORE_NS = "http://www.gtk.org/introspection/core/1.0"
30 C_NS = "http://www.gtk.org/introspection/c/1.0"
31 GLIB_NS = "http://www.gtk.org/introspection/glib/1.0"
32
33
34 def _corens(tag):
35     return '{%s}%s' % (CORE_NS, tag)
36
37
38 def _glibns(tag):
39     return '{%s}%s' % (GLIB_NS, tag)
40
41
42 def _cns(tag):
43     return '{%s}%s' % (C_NS, tag)
44
45
46 class GIRParser(object):
47
48     def __init__(self, filename, initial_parse=True):
49         self._includes = set()
50         self._namespace = None
51         self._shared_libraries = []
52         self._tree = parse(filename)
53
54         if (initial_parse):
55             self.parse()
56
57     # Public API
58
59     def parse(self):
60         self._includes.clear()
61         del self._namespace
62         del self._shared_libraries[:]
63
64         self._parse_api(self._tree.getroot())
65
66     def get_namespace(self):
67         return self._namespace
68
69     def get_shared_libraries(self):
70         return self._shared_libraries
71
72     def get_includes(self):
73         return self._includes
74
75     def get_doc(self):
76         return self._tree
77
78     # Private
79
80     def _add_node(self, node):
81         self._namespace.nodes.append(node)
82
83     def _parse_api(self, root):
84         assert root.tag == _corens('repository')
85         for node in root.getchildren():
86             if node.tag == _corens('include'):
87                 self._includes.add((node.attrib['name']))
88         ns = root.find(_corens('namespace'))
89         assert ns is not None
90         self._namespace = Namespace(ns.attrib['name'], ns.attrib['version'])
91         self._shared_libraries.extend(ns.attrib['shared-library'].split(','))
92         for child in ns.getchildren():
93             self._parse_node(child)
94
95     def _parse_node(self, node):
96         if node.tag == _corens('alias'):
97             self._add_node(self._parse_alias(node))
98         elif node.tag in [_corens('callback')]:
99             self._add_node(self._parse_function(node, Callback))
100         elif node.tag in [_corens('function')]:
101             self._add_node(self._parse_function(node, Function))
102         elif node.tag in [_corens('class'),
103                           _corens('interface')]:
104             self._parse_object_interface(node)
105         elif node.tag == _corens('record'):
106             self._parse_struct(node)
107         elif node.tag == _corens('union'):
108             self._parse_union(node)
109         elif node.tag == _glibns('boxed'):
110             self._parse_boxed(node)
111         elif node.tag in [_corens('enumeration'),
112                           _corens('bitfield')]:
113             self._parse_enumeration_bitfield(node)
114
115     def _parse_alias(self, node):
116         return Alias(node.attrib['name'],
117                      node.attrib['target'],
118                      node.attrib.get(_cns('type')))
119
120     def _parse_object_interface(self, node):
121         if node.tag == _corens('interface'):
122             klass = GLibInterface
123         elif node.tag == _corens('class'):
124             klass = GLibObject
125         else:
126             raise AssertionError(node)
127
128         obj = klass(node.attrib['name'],
129                     node.attrib.get('parent'),
130                     node.attrib[_glibns('type-name')],
131                     node.attrib[_glibns('get-type')],
132                     node.attrib.get(_cns('type')))
133         for iface in node.findall(_corens('implements')):
134             obj.interfaces.append(iface.attrib['name'])
135         for method in node.findall(_corens('method')):
136             obj.methods.append(self._parse_function(method, Function))
137         for ctor in node.findall(_corens('constructor')):
138             obj.constructors.append(self._parse_function(ctor, Function))
139         for callback in node.findall(_corens('callback')):
140             obj.fields.append(self._parse_function(callback, Callback))
141         for field in node.findall(_corens('field')):
142             obj.fields.append(self._parse_field(field))
143         for property in node.findall(_corens('property')):
144             obj.properties.append(self._parse_property(property))
145         for signal in node.findall(_glibns('signal')):
146             obj.signals.append(self._parse_function(signal, Function))
147         self._add_node(obj)
148
149     def _parse_function(self, node, klass):
150         name = node.attrib['name']
151         returnnode = node.find(_corens('return-value'))
152         if not returnnode:
153             raise ValueError('node %r has no return-value' % (name, ))
154         transfer = returnnode.attrib.get('transfer-ownership')
155         retval = Return(self._parse_type(returnnode), transfer)
156         parameters_node = node.find(_corens('parameters'))
157         parameters = []
158         if (parameters_node is not None):
159             for paramnode in parameters_node.findall(_corens('parameter')):
160                 parameters.append(Parameter(paramnode.attrib.get('name'),
161                                   self._parse_type(paramnode)))
162         if klass is Callback:
163             return klass(name, retval, parameters,
164                          node.attrib.get(_cns('type')))
165         else:
166             identifier = node.attrib.get(_cns('identifier'))
167             return klass(name, retval, parameters, identifier)
168
169     def _parse_struct(self, node):
170         if _glibns('type-name') in node.attrib:
171             struct = GLibBoxedStruct(node.attrib['name'],
172                                      node.attrib[_glibns('type-name')],
173                                      node.attrib[_glibns('get-type')],
174                                      node.attrib.get(_cns('type')))
175         else:
176             struct = Struct(node.attrib['name'],
177                             node.attrib.get(_cns('type')))
178         for field in node.findall(_corens('field')):
179             struct.fields.append(self._parse_field(field))
180         for callback in node.findall(_corens('callback')):
181             struct.fields.append(self._parse_function(callback, Callback))
182         for method in node.findall(_corens('method')):
183             struct.fields.append(self._parse_function(method, Function))
184         for ctor in node.findall(_corens('constructor')):
185             struct.constructors.append(self._parse_function(ctor, Function))
186         self._add_node(struct)
187
188     def _parse_union(self, node):
189         if _glibns('type-name') in node.attrib:
190             struct = GLibBoxedUnion(node.attrib['name'],
191                                     node.attrib[_glibns('type-name')],
192                                     node.attrib[_glibns('get-type')],
193                                     node.attrib.get(_cns('type')))
194         else:
195             struct = Union(node.attrib['name'],
196                            node.attrib.get(_cns('type')))
197         for callback in node.findall(_corens('callback')):
198             struct.fields.append(self._parse_function(callback, Callback))
199         for field in node.findall(_corens('field')):
200             struct.fields.append(self._parse_field(field))
201         for method in node.findall(_corens('method')):
202             struct.fields.append(self._parse_function(method, Function))
203         for ctor in node.findall(_corens('constructor')):
204             struct.constructors.append(self._parse_function(ctor, Function))
205         self._add_node(struct)
206
207     def _parse_type(self, node):
208         typenode = node.find(_corens('type'))
209         if typenode is not None:
210             return Type(typenode.attrib['name'],
211                         typenode.attrib.get(_cns('type')))
212         typenode = node.find(_corens('array'))
213         if typenode is not None:
214             return Array(typenode.attrib.get(_cns('type')),
215                          self._parse_type(typenode))
216         typenode = node.find(_corens('varargs'))
217         if typenode is not None:
218             return Varargs()
219         raise ValueError("Couldn't parse type of node %r; children=%r",
220                          node, list(node))
221
222     def _parse_boxed(self, node):
223         obj = GLibBoxedOther(node.attrib[_glibns('name')],
224                              node.attrib[_glibns('type-name')],
225                              node.attrib[_glibns('get-type')])
226         for method in node.findall(_corens('method')):
227             obj.methods.append(self._parse_function(method, Function))
228         for ctor in node.findall(_corens('constructor')):
229             obj.constructors.append(self._parse_function(ctor, Function))
230         for callback in node.findall(_corens('callback')):
231             obj.fields.append(self._parse_function(callback, Callback))
232         self._add_node(obj)
233
234     def _parse_field(self, node):
235         type_node = self._parse_type(node)
236         return Field(node.attrib['name'],
237                      type_node,
238                      type_node.ctype)
239
240     def _parse_property(self, node):
241         type_node = self._parse_type(node)
242         return Property(node.attrib['name'],
243                         type_node.name,
244                         node.attrib.get('readable') != '0',
245                         node.attrib.get('writable') == '1',
246                         node.attrib.get('construct') == '1',
247                         node.attrib.get('construct-only') == '1',
248                         type_node.ctype)
249
250     def _parse_member(self, node):
251         return GLibEnumMember(node.attrib['name'],
252                               node.attrib['value'],
253                               node.attrib.get(_cns('identifier')),
254                               node.attrib.get(_glibns('nick')))
255
256     def _parse_enumeration_bitfield(self, node):
257         name = node.attrib.get('name')
258         ctype = node.attrib.get(_cns('type'))
259         get_type = node.attrib.get(_glibns('get-type'))
260         type_name = node.attrib.get(_glibns('type-name'))
261         if get_type:
262             if node.tag == _corens('bitfield'):
263                 klass = GLibFlags
264             else:
265                 klass = GLibEnum
266         else:
267             klass = Enum
268             type_name = ctype
269         members = []
270         for member in node.findall(_corens('member')):
271             members.append(self._parse_member(member))
272
273         if klass is Enum:
274             obj = klass(name, type_name, members)
275         else:
276             obj = klass(name, type_name, members, get_type)
277             obj.ctype = ctype
278         self._add_node(obj)