2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008 Johan Dahlin
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.
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.
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
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):
49 def __init__(self, filename, initial_parse=True):
50 self._includes = set()
51 self._namespace = None
52 self._shared_libraries = []
53 self._tree = parse(filename)
61 self._includes.clear()
63 del self._shared_libraries[:]
65 self._parse_api(self._tree.getroot())
67 def get_namespace(self):
68 return self._namespace
70 def get_shared_libraries(self):
71 return self._shared_libraries
73 def get_includes(self):
81 def _add_node(self, node):
82 self._namespace.nodes.append(node)
84 def _parse_api(self, root):
85 assert root.tag == _corens('repository')
86 for node in root.getchildren():
87 if node.tag == _corens('include'):
88 include = Include(node.attrib['name'],
89 node.attrib['version'])
90 self._includes.add(include)
91 ns = root.find(_corens('namespace'))
93 self._namespace = Namespace(ns.attrib['name'], ns.attrib['version'])
94 self._shared_libraries.extend(ns.attrib['shared-library'].split(','))
95 for child in ns.getchildren():
96 self._parse_node(child)
98 def _parse_node(self, node):
99 if node.tag == _corens('alias'):
100 self._add_node(self._parse_alias(node))
101 elif node.tag in [_corens('callback')]:
102 self._add_node(self._parse_function(node, Callback))
103 elif node.tag in [_corens('function')]:
104 self._add_node(self._parse_function(node, Function))
105 elif node.tag in [_corens('class'),
106 _corens('interface')]:
107 self._parse_object_interface(node)
108 elif node.tag == _corens('record'):
109 self._parse_struct(node)
110 elif node.tag == _corens('union'):
111 self._parse_union(node)
112 elif node.tag == _glibns('boxed'):
113 self._parse_boxed(node)
114 elif node.tag in [_corens('enumeration'),
115 _corens('bitfield')]:
116 self._parse_enumeration_bitfield(node)
117 elif node.tag in _corens('constant'):
118 self._add_node(self._parse_constant(node))
120 def _parse_alias(self, node):
121 return Alias(node.attrib['name'],
122 node.attrib['target'],
123 node.attrib.get(_cns('type')))
125 def _parse_object_interface(self, node):
126 if node.tag == _corens('interface'):
127 klass = GLibInterface
128 elif node.tag == _corens('class'):
131 raise AssertionError(node)
133 obj = klass(node.attrib['name'],
134 node.attrib.get('parent'),
135 node.attrib[_glibns('type-name')],
136 node.attrib[_glibns('get-type')],
137 node.attrib.get(_cns('type')))
138 for iface in node.findall(_corens('implements')):
139 obj.interfaces.append(iface.attrib['name'])
140 for method in node.findall(_corens('method')):
141 obj.methods.append(self._parse_function(method, Function))
142 for ctor in node.findall(_corens('constructor')):
143 obj.constructors.append(self._parse_function(ctor, Function))
144 for callback in node.findall(_corens('callback')):
145 obj.fields.append(self._parse_function(callback, Callback))
146 for field in node.findall(_corens('field')):
147 obj.fields.append(self._parse_field(field))
148 for property in node.findall(_corens('property')):
149 obj.properties.append(self._parse_property(property))
150 for signal in node.findall(_glibns('signal')):
151 obj.signals.append(self._parse_function(signal, Function))
154 def _parse_function(self, node, klass):
155 name = node.attrib['name']
156 returnnode = node.find(_corens('return-value'))
158 raise ValueError('node %r has no return-value' % (name, ))
159 transfer = returnnode.attrib.get('transfer-ownership')
160 retval = Return(self._parse_type(returnnode), transfer)
161 parameters_node = node.find(_corens('parameters'))
163 if (parameters_node is not None):
164 for paramnode in parameters_node.findall(_corens('parameter')):
165 parameters.append(Parameter(paramnode.attrib.get('name'),
166 self._parse_type(paramnode)))
167 if klass is Callback:
168 return klass(name, retval, parameters,
169 node.attrib.get(_cns('type')))
171 identifier = node.attrib.get(_cns('identifier'))
172 return klass(name, retval, parameters, identifier)
174 def _parse_struct(self, node):
175 if _glibns('type-name') in node.attrib:
176 struct = GLibBoxedStruct(node.attrib['name'],
177 node.attrib[_glibns('type-name')],
178 node.attrib[_glibns('get-type')],
179 node.attrib.get(_cns('type')))
181 struct = Struct(node.attrib['name'],
182 node.attrib.get(_cns('type')))
183 for field in node.findall(_corens('field')):
184 struct.fields.append(self._parse_field(field))
185 for callback in node.findall(_corens('callback')):
186 struct.fields.append(self._parse_function(callback, Callback))
187 for method in node.findall(_corens('method')):
188 struct.fields.append(self._parse_function(method, Function))
189 for ctor in node.findall(_corens('constructor')):
190 struct.constructors.append(self._parse_function(ctor, Function))
191 self._add_node(struct)
193 def _parse_union(self, node):
194 if _glibns('type-name') in node.attrib:
195 struct = GLibBoxedUnion(node.attrib['name'],
196 node.attrib[_glibns('type-name')],
197 node.attrib[_glibns('get-type')],
198 node.attrib.get(_cns('type')))
200 struct = Union(node.attrib['name'],
201 node.attrib.get(_cns('type')))
202 for callback in node.findall(_corens('callback')):
203 struct.fields.append(self._parse_function(callback, Callback))
204 for field in node.findall(_corens('field')):
205 struct.fields.append(self._parse_field(field))
206 for method in node.findall(_corens('method')):
207 struct.fields.append(self._parse_function(method, Function))
208 for ctor in node.findall(_corens('constructor')):
209 struct.constructors.append(self._parse_function(ctor, Function))
210 self._add_node(struct)
212 def _parse_type(self, node):
213 typenode = node.find(_corens('type'))
214 if typenode is not None:
215 return Type(typenode.attrib['name'],
216 typenode.attrib.get(_cns('type')))
217 typenode = node.find(_corens('array'))
218 if typenode is not None:
219 return Array(typenode.attrib.get(_cns('type')),
220 self._parse_type(typenode))
221 typenode = node.find(_corens('varargs'))
222 if typenode is not None:
224 raise ValueError("Couldn't parse type of node %r; children=%r",
227 def _parse_boxed(self, node):
228 obj = GLibBoxedOther(node.attrib[_glibns('name')],
229 node.attrib[_glibns('type-name')],
230 node.attrib[_glibns('get-type')])
231 for method in node.findall(_corens('method')):
232 obj.methods.append(self._parse_function(method, Function))
233 for ctor in node.findall(_corens('constructor')):
234 obj.constructors.append(self._parse_function(ctor, Function))
235 for callback in node.findall(_corens('callback')):
236 obj.fields.append(self._parse_function(callback, Callback))
239 def _parse_field(self, node):
240 type_node = self._parse_type(node)
241 return Field(node.attrib['name'],
244 node.attrib.get('bits'))
246 def _parse_property(self, node):
247 type_node = self._parse_type(node)
248 return Property(node.attrib['name'],
250 node.attrib.get('readable') != '0',
251 node.attrib.get('writable') == '1',
252 node.attrib.get('construct') == '1',
253 node.attrib.get('construct-only') == '1',
256 def _parse_member(self, node):
257 return GLibEnumMember(node.attrib['name'],
258 node.attrib['value'],
259 node.attrib.get(_cns('identifier')),
260 node.attrib.get(_glibns('nick')))
262 def _parse_constant(self, node):
263 type_node = self._parse_type(node)
264 return Constant(node.attrib['name'],
266 node.attrib['value'])
268 def _parse_enumeration_bitfield(self, node):
269 name = node.attrib.get('name')
270 ctype = node.attrib.get(_cns('type'))
271 get_type = node.attrib.get(_glibns('get-type'))
272 type_name = node.attrib.get(_glibns('type-name'))
274 if node.tag == _corens('bitfield'):
282 for member in node.findall(_corens('member')):
283 members.append(self._parse_member(member))
286 obj = klass(name, type_name, members)
288 obj = klass(name, type_name, members, get_type)