Imported Upstream version 2.50.2
[platform/upstream/glib.git] / gio / gdbus-2.0 / codegen / parser.py
1 # -*- Mode: Python -*-
2
3 # GDBus - GLib D-Bus Library
4 #
5 # Copyright (C) 2008-2011 Red Hat, Inc.
6 #
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 of the License, or (at your option) any later version.
11 #
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.
16 #
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/>.
19 #
20 # Author: David Zeuthen <davidz@redhat.com>
21
22 import sys
23 import xml.parsers.expat
24
25 from . import dbustypes
26
27 class DBusXMLParser:
28     STATE_TOP = 'top'
29     STATE_NODE = 'node'
30     STATE_INTERFACE = 'interface'
31     STATE_METHOD = 'method'
32     STATE_SIGNAL = 'signal'
33     STATE_PROPERTY = 'property'
34     STATE_ARG = 'arg'
35     STATE_ANNOTATION = 'annotation'
36     STATE_IGNORED = 'ignored'
37
38     def __init__(self, xml_data):
39         self._parser = xml.parsers.expat.ParserCreate()
40         self._parser.CommentHandler = self.handle_comment
41         self._parser.CharacterDataHandler = self.handle_char_data
42         self._parser.StartElementHandler = self.handle_start_element
43         self._parser.EndElementHandler = self.handle_end_element
44
45         self.parsed_interfaces = []
46         self._cur_object = None
47
48         self.state = DBusXMLParser.STATE_TOP
49         self.state_stack = []
50         self._cur_object = None
51         self._cur_object_stack = []
52
53         self.doc_comment_last_symbol = ''
54
55         self._parser.Parse(xml_data)
56
57     COMMENT_STATE_BEGIN = 'begin'
58     COMMENT_STATE_PARAMS = 'params'
59     COMMENT_STATE_BODY = 'body'
60     COMMENT_STATE_SKIP = 'skip'
61     def handle_comment(self, data):
62         comment_state = DBusXMLParser.COMMENT_STATE_BEGIN;
63         lines = data.split('\n')
64         symbol = ''
65         body = ''
66         in_para = False
67         params = {}
68         for line in lines:
69             orig_line = line
70             line = line.lstrip()
71             if comment_state == DBusXMLParser.COMMENT_STATE_BEGIN:
72                 if len(line) > 0:
73                     colon_index = line.find(': ')
74                     if colon_index == -1:
75                         if line.endswith(':'):
76                             symbol = line[0:len(line)-1]
77                             comment_state = DBusXMLParser.COMMENT_STATE_PARAMS
78                         else:
79                             comment_state = DBusXMLParser.COMMENT_STATE_SKIP
80                     else:
81                         symbol = line[0:colon_index]
82                         rest_of_line = line[colon_index+2:].strip()
83                         if len(rest_of_line) > 0:
84                             body += '<para>' + rest_of_line + '</para>'
85                         comment_state = DBusXMLParser.COMMENT_STATE_PARAMS
86             elif comment_state == DBusXMLParser.COMMENT_STATE_PARAMS:
87                 if line.startswith('@'):
88                     colon_index = line.find(': ')
89                     if colon_index == -1:
90                         comment_state = DBusXMLParser.COMMENT_STATE_BODY
91                         if not in_para:
92                             body += '<para>'
93                             in_para = True
94                         body += orig_line + '\n'
95                     else:
96                         param = line[1:colon_index]
97                         docs = line[colon_index + 2:]
98                         params[param] = docs
99                 else:
100                     comment_state = DBusXMLParser.COMMENT_STATE_BODY
101                     if len(line) > 0:
102                         if not in_para:
103                             body += '<para>'
104                             in_para = True
105                         body += orig_line + '\n'
106             elif comment_state == DBusXMLParser.COMMENT_STATE_BODY:
107                 if len(line) > 0:
108                     if not in_para:
109                         body += '<para>'
110                         in_para = True
111                     body += orig_line + '\n'
112                 else:
113                     if in_para:
114                         body += '</para>'
115                         in_para = False
116         if in_para:
117             body += '</para>'
118
119         if symbol != '':
120             self.doc_comment_last_symbol = symbol
121             self.doc_comment_params = params
122             self.doc_comment_body = body
123
124     def handle_char_data(self, data):
125         #print 'char_data=%s'%data
126         pass
127
128     def handle_start_element(self, name, attrs):
129         old_state = self.state
130         old_cur_object = self._cur_object
131         if self.state == DBusXMLParser.STATE_IGNORED:
132             self.state = DBusXMLParser.STATE_IGNORED
133         elif self.state == DBusXMLParser.STATE_TOP:
134             if name == DBusXMLParser.STATE_NODE:
135                 self.state = DBusXMLParser.STATE_NODE
136             else:
137                 self.state = DBusXMLParser.STATE_IGNORED
138         elif self.state == DBusXMLParser.STATE_NODE:
139             if name == DBusXMLParser.STATE_INTERFACE:
140                 self.state = DBusXMLParser.STATE_INTERFACE
141                 iface = dbustypes.Interface(attrs['name'])
142                 self._cur_object = iface
143                 self.parsed_interfaces.append(iface)
144             elif name == DBusXMLParser.STATE_ANNOTATION:
145                 self.state = DBusXMLParser.STATE_ANNOTATION
146                 anno = dbustypes.Annotation(attrs['name'], attrs['value'])
147                 self._cur_object.annotations.append(anno)
148                 self._cur_object = anno
149             else:
150                 self.state = DBusXMLParser.STATE_IGNORED
151
152             # assign docs, if any
153             if 'name' in attrs and self.doc_comment_last_symbol == attrs['name']:
154                 self._cur_object.doc_string = self.doc_comment_body
155                 if 'short_description' in self.doc_comment_params:
156                     short_description = self.doc_comment_params['short_description']
157                     self._cur_object.doc_string_brief = short_description
158                 if 'since' in self.doc_comment_params:
159                     self._cur_object.since = \
160                         self.doc_comment_params['since'].strip()
161
162         elif self.state == DBusXMLParser.STATE_INTERFACE:
163             if name == DBusXMLParser.STATE_METHOD:
164                 self.state = DBusXMLParser.STATE_METHOD
165                 method = dbustypes.Method(attrs['name'])
166                 self._cur_object.methods.append(method)
167                 self._cur_object = method
168             elif name == DBusXMLParser.STATE_SIGNAL:
169                 self.state = DBusXMLParser.STATE_SIGNAL
170                 signal = dbustypes.Signal(attrs['name'])
171                 self._cur_object.signals.append(signal)
172                 self._cur_object = signal
173             elif name == DBusXMLParser.STATE_PROPERTY:
174                 self.state = DBusXMLParser.STATE_PROPERTY
175                 prop = dbustypes.Property(attrs['name'], attrs['type'], attrs['access'])
176                 self._cur_object.properties.append(prop)
177                 self._cur_object = prop
178             elif name == DBusXMLParser.STATE_ANNOTATION:
179                 self.state = DBusXMLParser.STATE_ANNOTATION
180                 anno = dbustypes.Annotation(attrs['name'], attrs['value'])
181                 self._cur_object.annotations.append(anno)
182                 self._cur_object = anno
183             else:
184                 self.state = DBusXMLParser.STATE_IGNORED
185
186             # assign docs, if any
187             if 'name' in attrs and self.doc_comment_last_symbol == attrs['name']:
188                 self._cur_object.doc_string = self.doc_comment_body
189                 if 'since' in self.doc_comment_params:
190                     self._cur_object.since = \
191                         self.doc_comment_params['since'].strip()
192
193         elif self.state == DBusXMLParser.STATE_METHOD:
194             if name == DBusXMLParser.STATE_ARG:
195                 self.state = DBusXMLParser.STATE_ARG
196                 arg_name = None
197                 if 'name' in attrs:
198                     arg_name = attrs['name']
199                 arg = dbustypes.Arg(arg_name, attrs['type'])
200                 direction = attrs.get('direction', 'in')
201                 if direction == 'in':
202                     self._cur_object.in_args.append(arg)
203                 elif direction == 'out':
204                     self._cur_object.out_args.append(arg)
205                 else:
206                     raise RuntimeError('Invalid direction "%s"'%(direction))
207                 self._cur_object = arg
208             elif name == DBusXMLParser.STATE_ANNOTATION:
209                 self.state = DBusXMLParser.STATE_ANNOTATION
210                 anno = dbustypes.Annotation(attrs['name'], attrs['value'])
211                 self._cur_object.annotations.append(anno)
212                 self._cur_object = anno
213             else:
214                 self.state = DBusXMLParser.STATE_IGNORED
215
216             # assign docs, if any
217             if self.doc_comment_last_symbol == old_cur_object.name:
218                 if 'name' in attrs and attrs['name'] in self.doc_comment_params:
219                     doc_string = self.doc_comment_params[attrs['name']]
220                     if doc_string != None:
221                         self._cur_object.doc_string = doc_string
222                     if 'since' in self.doc_comment_params:
223                         self._cur_object.since = \
224                             self.doc_comment_params['since'].strip()
225
226         elif self.state == DBusXMLParser.STATE_SIGNAL:
227             if name == DBusXMLParser.STATE_ARG:
228                 self.state = DBusXMLParser.STATE_ARG
229                 arg_name = None
230                 if 'name' in attrs:
231                     arg_name = attrs['name']
232                 arg = dbustypes.Arg(arg_name, attrs['type'])
233                 self._cur_object.args.append(arg)
234                 self._cur_object = arg
235             elif name == DBusXMLParser.STATE_ANNOTATION:
236                 self.state = DBusXMLParser.STATE_ANNOTATION
237                 anno = dbustypes.Annotation(attrs['name'], attrs['value'])
238                 self._cur_object.annotations.append(anno)
239                 self._cur_object = anno
240             else:
241                 self.state = DBusXMLParser.STATE_IGNORED
242
243             # assign docs, if any
244             if self.doc_comment_last_symbol == old_cur_object.name:
245                 if 'name' in attrs and attrs['name'] in self.doc_comment_params:
246                     doc_string = self.doc_comment_params[attrs['name']]
247                     if doc_string != None:
248                         self._cur_object.doc_string = doc_string
249                     if 'since' in self.doc_comment_params:
250                         self._cur_object.since = \
251                             self.doc_comment_params['since'].strip()
252
253         elif self.state == DBusXMLParser.STATE_PROPERTY:
254             if name == DBusXMLParser.STATE_ANNOTATION:
255                 self.state = DBusXMLParser.STATE_ANNOTATION
256                 anno = dbustypes.Annotation(attrs['name'], attrs['value'])
257                 self._cur_object.annotations.append(anno)
258                 self._cur_object = anno
259             else:
260                 self.state = DBusXMLParser.STATE_IGNORED
261
262         elif self.state == DBusXMLParser.STATE_ARG:
263             if name == DBusXMLParser.STATE_ANNOTATION:
264                 self.state = DBusXMLParser.STATE_ANNOTATION
265                 anno = dbustypes.Annotation(attrs['name'], attrs['value'])
266                 self._cur_object.annotations.append(anno)
267                 self._cur_object = anno
268             else:
269                 self.state = DBusXMLParser.STATE_IGNORED
270
271         elif self.state == DBusXMLParser.STATE_ANNOTATION:
272             if name == DBusXMLParser.STATE_ANNOTATION:
273                 self.state = DBusXMLParser.STATE_ANNOTATION
274                 anno = dbustypes.Annotation(attrs['name'], attrs['value'])
275                 self._cur_object.annotations.append(anno)
276                 self._cur_object = anno
277             else:
278                 self.state = DBusXMLParser.STATE_IGNORED
279
280         else:
281             raise RuntimeError('Unhandled state "%s" while entering element with name "%s"'%(self.state, name))
282
283         self.state_stack.append(old_state)
284         self._cur_object_stack.append(old_cur_object)
285
286     def handle_end_element(self, name):
287         self.state = self.state_stack.pop()
288         self._cur_object = self._cur_object_stack.pop()
289
290 def parse_dbus_xml(xml_data):
291     parser = DBusXMLParser(xml_data)
292     return parser.parsed_interfaces