Rename most c:identifier to c:type. Add new ones to
[gnome.gobject-introspection] / giscanner / girwriter.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 __future__ import with_statement
22
23 from .ast import (Callback, Class, Enum, Function, Interface, Sequence)
24 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember,
25                       GLibFlags, GLibObject, GLibInterface)
26 from .xmlwriter import XMLWriter
27
28
29 class GIRWriter(XMLWriter):
30     def __init__(self, namespace, nodes):
31         super(GIRWriter, self).__init__()
32         self._write_repository(namespace, nodes)
33
34     def _write_repository(self, namespace, nodes):
35         attrs = [
36             ('version', '1.0'),
37             ('xmlns', 'http://www.gtk.org/introspection/core/1.0'),
38             ('xmlns:c', 'http://www.gtk.org/introspection/c/1.0'),
39             ('xmlns:glib', 'http://www.gtk.org/introspection/glib/1.0'),
40             ]
41         with self.tagcontext('repository', attrs):
42             self._write_namespace(namespace, nodes)
43
44     def _write_namespace(self, namespace, nodes):
45         with self.tagcontext('namespace', [('name', namespace)]):
46             for node in nodes:
47                 self._write_node(node)
48
49     def _write_node(self, node):
50         if isinstance(node, Function):
51             self._write_function(node)
52         elif isinstance(node, Enum):
53             self._write_enum(node)
54         elif isinstance(node, (Class, Interface)):
55             self._write_class(node)
56         elif isinstance(node, GLibBoxed):
57             self._write_boxed(node)
58         elif isinstance(node, Callback):
59             self._write_callback(node)
60         else:
61             print 'WRITER: Unhandled node', node
62
63     def _write_function(self, func, tag_name='function'):
64         attrs = [('name', func.name),
65                  ('c:identifier', func.symbol)]
66         with self.tagcontext(tag_name, attrs):
67             self._write_return_type(func.retval)
68             self._write_parameters(func.parameters)
69
70     def _write_method(self, method):
71         self._write_function(method, tag_name='method')
72
73     def _write_constructor(self, method):
74         self._write_function(method, tag_name='constructor')
75
76     def _write_return_type(self, return_):
77         if not return_:
78             return
79         with self.tagcontext('return-value'):
80             if isinstance(return_.type, Sequence):
81                 self._write_sequence(return_.type)
82             else:
83                 self._write_type(return_.type)
84
85     def _write_parameters(self, parameters):
86         if not parameters:
87             return
88         with self.tagcontext('parameters'):
89             for parameter in parameters:
90                 self._write_parameter(parameter)
91
92     def _write_parameter(self, parameter):
93         attrs = [('name', parameter.name)]
94         if parameter.direction != 'in':
95             attrs.append(('direction', parameter.direction))
96         if parameter.transfer != 'none':
97             attrs.append(('transfer', parameter.transfer))
98         with self.tagcontext('parameter', attrs):
99             self._write_type(parameter.type)
100
101     def _write_type(self, type):
102         attrs = [('name', type.name)]
103         # FIXME: figure out if type references a basic type
104         #        or a boxed/class/interface etc. and skip
105         #        writing the ctype if the latter.
106         if 1:
107             attrs.append(('c:type', type.ctype))
108         self.write_tag('type', attrs)
109
110     def _write_sequence(self, sequence):
111         attrs = [('c:owner', sequence.cowner)]
112         with self.tagcontext('sequence', attrs):
113             attrs = [('c:identifier', sequence.element_type)]
114             self.write_tag('element-type', attrs)
115
116     def _write_enum(self, enum):
117         attrs = [('name', enum.name),
118                  ('c:type', enum.ctype)]
119         tag_name = 'enumeration'
120         if isinstance(enum, GLibEnum):
121             attrs.extend([('glib:type-name', enum.type_name),
122                           ('glib:get-type', enum.get_type)])
123             if isinstance(enum, GLibFlags):
124                 tag_name = 'bitfield'
125
126         with self.tagcontext(tag_name, attrs):
127             for member in enum.members:
128                 self._write_member(member)
129
130     def _write_member(self, member):
131         attrs = [('name', member.name),
132                  ('value', str(member.value))]
133         if isinstance(member, GLibEnumMember):
134             attrs.append(('glib:nick', member.nick))
135         self.write_tag('member', attrs)
136
137     def _write_class(self, node):
138         attrs = [('name', node.name),
139                  ('c:type', node.ctype)]
140         if isinstance(node, Class):
141             tag_name = 'class'
142             if node.parent is not None:
143                 attrs.append(('parent', node.parent))
144         else:
145             tag_name = 'interface'
146         if isinstance(node, (GLibObject, GLibInterface)):
147             attrs.append(('glib:type-name', node.type_name))
148             attrs.append(('glib:get-type', node.get_type))
149         with self.tagcontext(tag_name, attrs):
150             if isinstance(node, Class):
151                 for method in node.constructors:
152                     self._write_constructor(method)
153             for method in node.methods:
154                 self._write_method(method)
155             for prop in node.properties:
156                 self._write_property(prop)
157
158     def _write_boxed(self, boxed):
159         attrs = [('c:type', boxed.ctype),
160                  ('glib:name', boxed.name),
161                  ('glib:type-name', boxed.type_name),
162                  ('glib:get-type', boxed.get_type)]
163
164         with self.tagcontext('glib:boxed', attrs):
165             for method in boxed.constructors:
166                 self._write_constructor(method)
167             for method in boxed.methods:
168                 self._write_method(method)
169
170     def _write_property(self, prop):
171         attrs = [('name', prop.name)]
172         with self.tagcontext('property', attrs):
173             self._write_type(prop.type)
174
175     def _write_callback(self, callback):
176         attrs = [('name', callback.name)]
177         with self.tagcontext('callback', attrs):
178             self._write_return_type(callback.retval)
179             self._write_parameters(callback.parameters)