Merge branch 'test-ip_mreq_source-android-only' into 'master'
[glib.git] / gio / gdbus-2.0 / codegen / parser.py
blobf49136d6e5bfbf1ebc2bd08fb92521e151c2952e
1 # -*- Mode: Python -*-
3 # GDBus - GLib D-Bus Library
5 # Copyright (C) 2008-2011 Red Hat, Inc.
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General
18 # Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 # Author: David Zeuthen <davidz@redhat.com>
22 import sys
23 import xml.parsers.expat
25 from . import dbustypes
26 from .utils import print_error
28 class DBusXMLParser:
29 STATE_TOP = 'top'
30 STATE_NODE = 'node'
31 STATE_INTERFACE = 'interface'
32 STATE_METHOD = 'method'
33 STATE_SIGNAL = 'signal'
34 STATE_PROPERTY = 'property'
35 STATE_ARG = 'arg'
36 STATE_ANNOTATION = 'annotation'
37 STATE_IGNORED = 'ignored'
39 def __init__(self, xml_data):
40 self._parser = xml.parsers.expat.ParserCreate()
41 self._parser.CommentHandler = self.handle_comment
42 self._parser.CharacterDataHandler = self.handle_char_data
43 self._parser.StartElementHandler = self.handle_start_element
44 self._parser.EndElementHandler = self.handle_end_element
46 self.parsed_interfaces = []
47 self._cur_object = None
49 self.state = DBusXMLParser.STATE_TOP
50 self.state_stack = []
51 self._cur_object = None
52 self._cur_object_stack = []
54 self.doc_comment_last_symbol = ''
56 self._parser.Parse(xml_data)
58 COMMENT_STATE_BEGIN = 'begin'
59 COMMENT_STATE_PARAMS = 'params'
60 COMMENT_STATE_BODY = 'body'
61 COMMENT_STATE_SKIP = 'skip'
62 def handle_comment(self, data):
63 comment_state = DBusXMLParser.COMMENT_STATE_BEGIN;
64 lines = data.split('\n')
65 symbol = ''
66 body = ''
67 in_para = False
68 params = {}
69 for line in lines:
70 orig_line = line
71 line = line.lstrip()
72 if comment_state == DBusXMLParser.COMMENT_STATE_BEGIN:
73 if len(line) > 0:
74 colon_index = line.find(': ')
75 if colon_index == -1:
76 if line.endswith(':'):
77 symbol = line[0:len(line)-1]
78 comment_state = DBusXMLParser.COMMENT_STATE_PARAMS
79 else:
80 comment_state = DBusXMLParser.COMMENT_STATE_SKIP
81 else:
82 symbol = line[0:colon_index]
83 rest_of_line = line[colon_index+2:].strip()
84 if len(rest_of_line) > 0:
85 body += '<para>' + rest_of_line + '</para>'
86 comment_state = DBusXMLParser.COMMENT_STATE_PARAMS
87 elif comment_state == DBusXMLParser.COMMENT_STATE_PARAMS:
88 if line.startswith('@'):
89 colon_index = line.find(': ')
90 if colon_index == -1:
91 comment_state = DBusXMLParser.COMMENT_STATE_BODY
92 if not in_para:
93 body += '<para>'
94 in_para = True
95 body += orig_line + '\n'
96 else:
97 param = line[1:colon_index]
98 docs = line[colon_index + 2:]
99 params[param] = docs
100 else:
101 comment_state = DBusXMLParser.COMMENT_STATE_BODY
102 if len(line) > 0:
103 if not in_para:
104 body += '<para>'
105 in_para = True
106 body += orig_line + '\n'
107 elif comment_state == DBusXMLParser.COMMENT_STATE_BODY:
108 if len(line) > 0:
109 if not in_para:
110 body += '<para>'
111 in_para = True
112 body += orig_line + '\n'
113 else:
114 if in_para:
115 body += '</para>'
116 in_para = False
117 if in_para:
118 body += '</para>'
120 if symbol != '':
121 self.doc_comment_last_symbol = symbol
122 self.doc_comment_params = params
123 self.doc_comment_body = body
125 def handle_char_data(self, data):
126 #print 'char_data=%s'%data
127 pass
129 def handle_start_element(self, name, attrs):
130 old_state = self.state
131 old_cur_object = self._cur_object
132 if self.state == DBusXMLParser.STATE_IGNORED:
133 self.state = DBusXMLParser.STATE_IGNORED
134 elif self.state == DBusXMLParser.STATE_TOP:
135 if name == DBusXMLParser.STATE_NODE:
136 self.state = DBusXMLParser.STATE_NODE
137 else:
138 self.state = DBusXMLParser.STATE_IGNORED
139 elif self.state == DBusXMLParser.STATE_NODE:
140 if name == DBusXMLParser.STATE_INTERFACE:
141 self.state = DBusXMLParser.STATE_INTERFACE
142 iface = dbustypes.Interface(attrs['name'])
143 self._cur_object = iface
144 self.parsed_interfaces.append(iface)
145 elif name == DBusXMLParser.STATE_ANNOTATION:
146 self.state = DBusXMLParser.STATE_ANNOTATION
147 anno = dbustypes.Annotation(attrs['name'], attrs['value'])
148 self._cur_object.annotations.append(anno)
149 self._cur_object = anno
150 else:
151 self.state = DBusXMLParser.STATE_IGNORED
153 # assign docs, if any
154 if 'name' in attrs and self.doc_comment_last_symbol == attrs['name']:
155 self._cur_object.doc_string = self.doc_comment_body
156 if 'short_description' in self.doc_comment_params:
157 short_description = self.doc_comment_params['short_description']
158 self._cur_object.doc_string_brief = short_description
159 if 'since' in self.doc_comment_params:
160 self._cur_object.since = \
161 self.doc_comment_params['since'].strip()
163 elif self.state == DBusXMLParser.STATE_INTERFACE:
164 if name == DBusXMLParser.STATE_METHOD:
165 self.state = DBusXMLParser.STATE_METHOD
166 method = dbustypes.Method(attrs['name'])
167 self._cur_object.methods.append(method)
168 self._cur_object = method
169 elif name == DBusXMLParser.STATE_SIGNAL:
170 self.state = DBusXMLParser.STATE_SIGNAL
171 signal = dbustypes.Signal(attrs['name'])
172 self._cur_object.signals.append(signal)
173 self._cur_object = signal
174 elif name == DBusXMLParser.STATE_PROPERTY:
175 self.state = DBusXMLParser.STATE_PROPERTY
176 prop = dbustypes.Property(attrs['name'], attrs['type'], attrs['access'])
177 self._cur_object.properties.append(prop)
178 self._cur_object = prop
179 elif name == DBusXMLParser.STATE_ANNOTATION:
180 self.state = DBusXMLParser.STATE_ANNOTATION
181 anno = dbustypes.Annotation(attrs['name'], attrs['value'])
182 self._cur_object.annotations.append(anno)
183 self._cur_object = anno
184 else:
185 self.state = DBusXMLParser.STATE_IGNORED
187 # assign docs, if any
188 if 'name' in attrs and self.doc_comment_last_symbol == attrs['name']:
189 self._cur_object.doc_string = self.doc_comment_body
190 if 'since' in self.doc_comment_params:
191 self._cur_object.since = \
192 self.doc_comment_params['since'].strip()
194 elif self.state == DBusXMLParser.STATE_METHOD:
195 if name == DBusXMLParser.STATE_ARG:
196 self.state = DBusXMLParser.STATE_ARG
197 arg_name = None
198 if 'name' in attrs:
199 arg_name = attrs['name']
200 arg = dbustypes.Arg(arg_name, attrs['type'])
201 direction = attrs.get('direction', 'in')
202 if direction == 'in':
203 self._cur_object.in_args.append(arg)
204 elif direction == 'out':
205 self._cur_object.out_args.append(arg)
206 else:
207 print_error('Invalid direction "{}"'.format(direction))
208 self._cur_object = arg
209 elif name == DBusXMLParser.STATE_ANNOTATION:
210 self.state = DBusXMLParser.STATE_ANNOTATION
211 anno = dbustypes.Annotation(attrs['name'], attrs['value'])
212 self._cur_object.annotations.append(anno)
213 self._cur_object = anno
214 else:
215 self.state = DBusXMLParser.STATE_IGNORED
217 # assign docs, if any
218 if self.doc_comment_last_symbol == old_cur_object.name:
219 if 'name' in attrs and attrs['name'] in self.doc_comment_params:
220 doc_string = self.doc_comment_params[attrs['name']]
221 if doc_string != None:
222 self._cur_object.doc_string = doc_string
223 if 'since' in self.doc_comment_params:
224 self._cur_object.since = \
225 self.doc_comment_params['since'].strip()
227 elif self.state == DBusXMLParser.STATE_SIGNAL:
228 if name == DBusXMLParser.STATE_ARG:
229 self.state = DBusXMLParser.STATE_ARG
230 arg_name = None
231 if 'name' in attrs:
232 arg_name = attrs['name']
233 arg = dbustypes.Arg(arg_name, attrs['type'])
234 self._cur_object.args.append(arg)
235 self._cur_object = arg
236 elif name == DBusXMLParser.STATE_ANNOTATION:
237 self.state = DBusXMLParser.STATE_ANNOTATION
238 anno = dbustypes.Annotation(attrs['name'], attrs['value'])
239 self._cur_object.annotations.append(anno)
240 self._cur_object = anno
241 else:
242 self.state = DBusXMLParser.STATE_IGNORED
244 # assign docs, if any
245 if self.doc_comment_last_symbol == old_cur_object.name:
246 if 'name' in attrs and attrs['name'] in self.doc_comment_params:
247 doc_string = self.doc_comment_params[attrs['name']]
248 if doc_string != None:
249 self._cur_object.doc_string = doc_string
250 if 'since' in self.doc_comment_params:
251 self._cur_object.since = \
252 self.doc_comment_params['since'].strip()
254 elif self.state == DBusXMLParser.STATE_PROPERTY:
255 if name == DBusXMLParser.STATE_ANNOTATION:
256 self.state = DBusXMLParser.STATE_ANNOTATION
257 anno = dbustypes.Annotation(attrs['name'], attrs['value'])
258 self._cur_object.annotations.append(anno)
259 self._cur_object = anno
260 else:
261 self.state = DBusXMLParser.STATE_IGNORED
263 elif self.state == DBusXMLParser.STATE_ARG:
264 if name == DBusXMLParser.STATE_ANNOTATION:
265 self.state = DBusXMLParser.STATE_ANNOTATION
266 anno = dbustypes.Annotation(attrs['name'], attrs['value'])
267 self._cur_object.annotations.append(anno)
268 self._cur_object = anno
269 else:
270 self.state = DBusXMLParser.STATE_IGNORED
272 elif self.state == DBusXMLParser.STATE_ANNOTATION:
273 if name == DBusXMLParser.STATE_ANNOTATION:
274 self.state = DBusXMLParser.STATE_ANNOTATION
275 anno = dbustypes.Annotation(attrs['name'], attrs['value'])
276 self._cur_object.annotations.append(anno)
277 self._cur_object = anno
278 else:
279 self.state = DBusXMLParser.STATE_IGNORED
281 else:
282 print_error('Unhandled state "{}" while entering element with name "{}"'.format(self.state, name))
284 self.state_stack.append(old_state)
285 self._cur_object_stack.append(old_cur_object)
287 def handle_end_element(self, name):
288 self.state = self.state_stack.pop()
289 self._cur_object = self._cur_object_stack.pop()
291 def parse_dbus_xml(xml_data):
292 parser = DBusXMLParser(xml_data)
293 return parser.parsed_interfaces