2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008 Johan Dahlin
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2 of the License, or (at your option) any later version.
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 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the
17 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA.
21 from xml.etree.cElementTree import parse
23 from .ast import (Alias, Array, Callback, Constant, Enum, Function, Field,
24 Namespace, Parameter, Property, Return, Union, Struct, Type,
26 from .glibast import (GLibEnum, GLibEnumMember, GLibFlags,
27 GLibInterface, GLibObject, GLibBoxedStruct,
28 GLibBoxedUnion, GLibBoxedOther)
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"
36 return '{%s}%s' % (CORE_NS, tag)
40 return '{%s}%s' % (GLIB_NS, tag)
44 return '{%s}%s' % (C_NS, tag)
47 class GIRParser(object):
50 self._include_parsing = False
51 self._shared_libraries = []
52 self._includes = set()
53 self._pkgconfig_packages = set()
54 self._namespace = None
58 def parse(self, filename):
59 tree = parse(filename)
62 def parse_tree(self, tree):
63 self._includes.clear()
64 self._namespace = None
65 self._shared_libraries = []
66 self._pkgconfig_packages = set()
67 self._parse_api(tree.getroot())
69 def get_namespace(self):
70 return self._namespace
72 def get_shared_libraries(self):
73 return self._shared_libraries
75 def get_includes(self):
78 def get_pkgconfig_packages(self):
79 if not hasattr(self, '_pkgconfig_packages'):
80 self._pkgconfig_packages = []
81 return self._pkgconfig_packages
84 return parse(self._filename)
86 def set_include_parsing(self, include_parsing):
87 self._include_parsing = include_parsing
91 def _add_node(self, node):
92 self._namespace.nodes.append(node)
94 def _parse_api(self, root):
95 assert root.tag == _corens('repository')
96 for node in root.getchildren():
97 if node.tag == _corens('include'):
98 self._parse_include(node)
99 elif node.tag == _corens('package'):
100 self._parse_pkgconfig_package(node)
102 ns = root.find(_corens('namespace'))
103 assert ns is not None
104 self._namespace = Namespace(ns.attrib['name'],
105 ns.attrib['version'])
106 if 'shared-library' in ns.attrib:
107 self._shared_libraries.extend(
108 ns.attrib['shared-library'].split(','))
111 _corens('alias'): self._parse_alias,
112 _corens('bitfield'): self._parse_enumeration_bitfield,
113 _corens('callback'): self._parse_callback,
114 _corens('class'): self._parse_object_interface,
115 _corens('constant'): self._parse_constant,
116 _corens('function'): self._parse_function,
117 _corens('enumeration'): self._parse_enumeration_bitfield,
118 _corens('interface'): self._parse_object_interface,
119 _corens('record'): self._parse_record,
120 _corens('union'): self._parse_union,
121 _corens('boxed'): self._parse_boxed,
124 for node in ns.getchildren():
125 method = parser_methods.get(node.tag)
126 if method is not None:
129 def _parse_include(self, node):
130 include = Include(node.attrib['name'],
131 node.attrib['version'])
132 self._includes.add(include)
134 def _parse_pkgconfig_package(self, node):
135 if not hasattr(self, '_pkgconfig_packages'):
136 self._pkgconfig_packages = []
137 self._pkgconfig_packages.add(node.attrib['name'])
139 def _parse_alias(self, node):
140 alias = Alias(node.attrib['name'],
141 node.attrib['target'],
142 node.attrib.get(_cns('type')))
143 self._add_node(alias)
145 def _parse_object_interface(self, node):
146 ctor_args = [node.attrib['name'],
147 node.attrib.get('parent'),
148 node.attrib[_glibns('type-name')],
149 node.attrib[_glibns('get-type')]]
150 if node.tag == _corens('interface'):
151 klass = GLibInterface
152 elif node.tag == _corens('class'):
154 is_abstract = node.attrib.get('abstract')
155 is_abstract = is_abstract and is_abstract != '0'
156 ctor_args.append(is_abstract)
158 raise AssertionError(node)
160 obj = klass(*ctor_args)
163 if self._include_parsing:
165 ctor_args.append(node.attrib.get(_cns('type')))
166 for iface in node.findall(_corens('implements')):
167 obj.interfaces.append(iface.attrib['name'])
168 for iface in node.findall(_corens('prerequisites')):
169 obj.prerequisities.append(iface.attrib['name'])
170 for method in node.findall(_corens('method')):
171 func = self._parse_function_common(method, Function)
172 func.is_method = True
173 obj.methods.append(func)
174 for ctor in node.findall(_corens('constructor')):
175 obj.constructors.append(
176 self._parse_function_common(ctor, Function))
177 for callback in node.findall(_corens('callback')):
178 obj.fields.append(self._parse_function_common(callback, Callback))
179 for field in node.findall(_corens('field')):
180 obj.fields.append(self._parse_field(field))
181 for prop in node.findall(_corens('property')):
182 obj.properties.append(self._parse_property(prop))
183 for signal in node.findall(_glibns('signal')):
184 obj.signals.append(self._parse_function_common(signal, Function))
186 def _parse_callback(self, node):
187 callback = self._parse_function_common(node, Callback)
188 self._add_node(callback)
190 def _parse_function(self, node):
191 function = self._parse_function_common(node, Function)
192 self._add_node(function)
194 def _parse_function_common(self, node, klass):
195 name = node.attrib['name']
196 returnnode = node.find(_corens('return-value'))
198 raise ValueError('node %r has no return-value' % (name, ))
199 transfer = returnnode.attrib.get('transfer-ownership')
200 retval = Return(self._parse_type(returnnode), transfer)
203 if klass is Callback:
204 func = klass(name, retval, parameters,
205 node.attrib.get(_cns('type')))
207 identifier = node.attrib.get(_cns('identifier'))
208 throws = (node.attrib.get('throws') == '1')
209 func = klass(name, retval, parameters, identifier, throws)
211 if self._include_parsing:
214 parameters_node = node.find(_corens('parameters'))
215 if (parameters_node is not None):
216 for paramnode in parameters_node.findall(_corens('parameter')):
217 param = Parameter(paramnode.attrib.get('name'),
218 self._parse_type(paramnode),
219 paramnode.attrib.get('direction'),
220 paramnode.attrib.get('transfer-ownership'),
221 paramnode.attrib.get('allow-none') == '1')
222 parameters.append(param)
226 def _parse_record(self, node):
227 if _glibns('type-name') in node.attrib:
228 struct = GLibBoxedStruct(node.attrib['name'],
229 node.attrib[_glibns('type-name')],
230 node.attrib[_glibns('get-type')],
231 node.attrib.get(_cns('type')))
233 disguised = node.attrib.get('disguised') == '1'
234 struct = Struct(node.attrib['name'],
235 node.attrib.get(_cns('type')),
237 self._add_node(struct)
239 if self._include_parsing:
241 for field in node.findall(_corens('field')):
242 struct.fields.append(self._parse_field(field))
243 for callback in node.findall(_corens('callback')):
244 struct.fields.append(
245 self._parse_function_common(callback, Callback))
246 for method in node.findall(_corens('method')):
247 struct.fields.append(
248 self._parse_function_common(method, Function))
249 for ctor in node.findall(_corens('constructor')):
250 struct.constructors.append(
251 self._parse_function_common(ctor, Function))
253 def _parse_union(self, node):
254 if _glibns('type-name') in node.attrib:
255 union = GLibBoxedUnion(node.attrib['name'],
256 node.attrib[_glibns('type-name')],
257 node.attrib[_glibns('get-type')],
258 node.attrib.get(_cns('type')))
260 union = Union(node.attrib['name'],
261 node.attrib.get(_cns('type')))
262 self._add_node(union)
264 if self._include_parsing:
266 for callback in node.findall(_corens('callback')):
268 self._parse_function_common(callback, Callback))
269 for field in node.findall(_corens('field')):
270 union.fields.append(self._parse_field(field))
271 for method in node.findall(_corens('method')):
273 self._parse_function_common(method, Function))
274 for ctor in node.findall(_corens('constructor')):
275 union.constructors.append(
276 self._parse_function_common(ctor, Function))
278 def _parse_type(self, node):
279 typenode = node.find(_corens('type'))
280 if typenode is not None:
281 return Type(typenode.attrib['name'],
282 typenode.attrib.get(_cns('type')))
283 typenode = node.find(_corens('array'))
284 if typenode is not None:
285 ret = Array(typenode.attrib.get(_cns('type')),
286 self._parse_type(typenode))
287 lenidx = typenode.attrib.get('length')
289 ret.length_param_index = int(lenidx)
291 typenode = node.find(_corens('varargs'))
292 if typenode is not None:
294 raise ValueError("Couldn't parse type of node %r; children=%r",
297 def _parse_boxed(self, node):
298 obj = GLibBoxedOther(node.attrib[_glibns('name')],
299 node.attrib[_glibns('type-name')],
300 node.attrib[_glibns('get-type')])
302 if self._include_parsing:
304 for method in node.findall(_corens('method')):
305 func = self._parse_function_common(method, Function)
306 func.is_method = True
307 obj.methods.append(func)
308 for ctor in node.findall(_corens('constructor')):
309 obj.constructors.append(
310 self._parse_function_common(ctor, Function))
311 for callback in node.findall(_corens('callback')):
313 self._parse_function_common(callback, Callback))
315 def _parse_field(self, node):
316 type_node = self._parse_type(node)
317 return Field(node.attrib['name'],
320 node.attrib.get('readable') != '0',
321 node.attrib.get('writable') == '1',
322 node.attrib.get('bits'))
324 def _parse_property(self, node):
325 type_node = self._parse_type(node)
326 return Property(node.attrib['name'],
328 node.attrib.get('readable') != '0',
329 node.attrib.get('writable') == '1',
330 node.attrib.get('construct') == '1',
331 node.attrib.get('construct-only') == '1',
334 def _parse_member(self, node):
335 return GLibEnumMember(node.attrib['name'],
336 node.attrib['value'],
337 node.attrib.get(_cns('identifier')),
338 node.attrib.get(_glibns('nick')))
340 def _parse_constant(self, node):
341 type_node = self._parse_type(node)
342 constant = Constant(node.attrib['name'],
344 node.attrib['value'])
345 self._add_node(constant)
347 def _parse_enumeration_bitfield(self, node):
348 name = node.attrib.get('name')
349 ctype = node.attrib.get(_cns('type'))
350 get_type = node.attrib.get(_glibns('get-type'))
351 type_name = node.attrib.get(_glibns('type-name'))
353 if node.tag == _corens('bitfield'):
362 obj = klass(name, type_name, members)
364 obj = klass(name, type_name, members, get_type)
368 if self._include_parsing:
370 for member in node.findall(_corens('member')):
371 members.append(self._parse_member(member))