blob: c1e0bed08788b3f4d33428012fd42586d0692663 [file] [log] [blame]
Michael Roth0f923be2011-07-19 14:50:39 -05001#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
Eric Blakee4083112016-01-29 06:48:41 -07005# Copyright (c) 2013-2016 Red Hat Inc.
Michael Roth0f923be2011-07-19 14:50:39 -05006#
7# Authors:
8# Anthony Liguori <aliguori@us.ibm.com>
Markus Armbrusterc7a3f252013-07-27 17:41:55 +02009# Markus Armbruster <armbru@redhat.com>
Michael Roth0f923be2011-07-19 14:50:39 -050010#
Markus Armbruster678e48a2014-03-01 08:40:34 +010011# This work is licensed under the terms of the GNU GPL, version 2.
12# See the COPYING file in the top-level directory.
Michael Roth0f923be2011-07-19 14:50:39 -050013
Lluís Vilanovaa719a272014-05-07 20:46:15 +020014import re
Michael Roth0f923be2011-07-19 14:50:39 -050015from ordereddict import OrderedDict
Markus Armbruster12f8e1b2015-04-02 14:46:39 +020016import errno
Markus Armbruster2114f5a2015-04-02 13:12:21 +020017import getopt
Lluís Vilanova33aaad52014-05-02 15:52:35 +020018import os
Markus Armbruster2caba362013-07-27 17:41:56 +020019import sys
Markus Armbruster47299262015-05-14 06:50:47 -060020import string
Michael Roth0f923be2011-07-19 14:50:39 -050021
Eric Blakeb52c4b92015-05-04 09:05:00 -060022builtin_types = {
Kevin Wolf69dd62d2013-07-08 16:14:21 +020023 'str': 'QTYPE_QSTRING',
24 'int': 'QTYPE_QINT',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
27 'int8': 'QTYPE_QINT',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
Eric Blakecb17f792015-05-04 09:05:01 -060035 'size': 'QTYPE_QINT',
Eric Blake1310a3d2015-12-01 22:20:46 -070036 'any': None, # any QType possible, actually
Eric Blake7264f5c2015-12-01 22:20:47 -070037 'QType': 'QTYPE_QSTRING',
Kevin Wolf69dd62d2013-07-08 16:14:21 +020038}
39
Markus Armbrusterbc52d032017-03-15 13:56:51 +010040# Are documentation comments required?
41doc_required = False
42
Eric Blake10d4d992015-05-04 09:05:23 -060043# Whitelist of commands allowed to return a non-dictionary
Markus Armbruster1554a8f2017-03-15 13:56:54 +010044returns_whitelist = []
Eric Blake10d4d992015-05-04 09:05:23 -060045
Eric Blake893e1f22015-12-01 22:20:57 -070046# Whitelist of entities allowed to violate case conventions
Markus Armbruster2cfbae32017-03-15 13:56:55 +010047name_case_whitelist = []
Eric Blake893e1f22015-12-01 22:20:57 -070048
Eric Blake4dc2e692015-05-04 09:05:17 -060049enum_types = []
50struct_types = []
51union_types = []
52events = []
53all_names = {}
54
Markus Armbruster00e4b282015-06-10 10:04:36 +020055#
56# Parsing the schema into expressions
57#
58
Eric Blake437db252015-09-29 16:21:02 -060059
Lluís Vilanovaa719a272014-05-07 20:46:15 +020060def error_path(parent):
61 res = ""
62 while parent:
63 res = ("In file included from %s:%d:\n" % (parent['file'],
64 parent['line'])) + res
65 parent = parent['parent']
66 return res
67
Eric Blake437db252015-09-29 16:21:02 -060068
Marc-André Lureau4148c292017-01-13 15:41:25 +010069class QAPIError(Exception):
70 def __init__(self, fname, line, col, incl_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -060071 Exception.__init__(self)
Marc-André Lureau4148c292017-01-13 15:41:25 +010072 self.fname = fname
73 self.line = line
74 self.col = col
75 self.info = incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +020076 self.msg = msg
Marc-André Lureau4148c292017-01-13 15:41:25 +010077
78 def __str__(self):
79 loc = "%s:%d" % (self.fname, self.line)
80 if self.col is not None:
81 loc += ":%s" % self.col
82 return error_path(self.info) + "%s: %s" % (loc, self.msg)
83
84
85class QAPIParseError(QAPIError):
86 def __init__(self, parser, msg):
87 col = 1
88 for ch in parser.src[parser.line_pos:parser.pos]:
Wenchao Xia515b9432014-03-04 18:44:33 -080089 if ch == '\t':
Marc-André Lureau4148c292017-01-13 15:41:25 +010090 col = (col + 7) % 8 + 1
Markus Armbruster2caba362013-07-27 17:41:56 +020091 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +010092 col += 1
93 QAPIError.__init__(self, parser.fname, parser.line, col,
94 parser.incl_info, msg)
Markus Armbruster2caba362013-07-27 17:41:56 +020095
Eric Blake437db252015-09-29 16:21:02 -060096
Marc-André Lureau4148c292017-01-13 15:41:25 +010097class QAPISemError(QAPIError):
98 def __init__(self, info, msg):
99 QAPIError.__init__(self, info['file'], info['line'], None,
100 info['parent'], msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800101
Eric Blake437db252015-09-29 16:21:02 -0600102
Marc-André Lureau3313b612017-01-13 15:41:29 +0100103class QAPIDoc(object):
104 class Section(object):
105 def __init__(self, name=None):
106 # optional section name (argument/member or section name)
107 self.name = name
108 # the list of lines for this section
109 self.content = []
Markus Armbrusterb116fd82017-03-15 13:57:00 +0100110 self.optional = False
Marc-André Lureau3313b612017-01-13 15:41:29 +0100111
112 def append(self, line):
113 self.content.append(line)
114
115 def __repr__(self):
116 return "\n".join(self.content).strip()
117
118 class ArgSection(Section):
Markus Armbruster069fb5b2017-03-15 13:57:03 +0100119 def __init__(self, name):
120 QAPIDoc.Section.__init__(self, name)
121 self.member = None
122
123 def connect(self, member):
124 self.member = member
Marc-André Lureau3313b612017-01-13 15:41:29 +0100125
126 def __init__(self, parser, info):
127 # self.parser is used to report errors with QAPIParseError. The
128 # resulting error position depends on the state of the parser.
129 # It happens to be the beginning of the comment. More or less
130 # servicable, but action at a distance.
131 self.parser = parser
132 self.info = info
133 self.symbol = None
134 self.body = QAPIDoc.Section()
135 # dict mapping parameter name to ArgSection
136 self.args = OrderedDict()
137 # a list of Section
138 self.sections = []
139 # the current section
140 self.section = self.body
141 # associated expression (to be set by expression parser)
142 self.expr = None
143
144 def has_section(self, name):
145 """Return True if we have a section with this name."""
146 for i in self.sections:
147 if i.name == name:
148 return True
149 return False
150
151 def append(self, line):
152 """Parse a comment line and add it to the documentation."""
153 line = line[1:]
154 if not line:
155 self._append_freeform(line)
156 return
157
158 if line[0] != ' ':
159 raise QAPIParseError(self.parser, "Missing space after #")
160 line = line[1:]
161
162 # FIXME not nice: things like '# @foo:' and '# @foo: ' aren't
163 # recognized, and get silently treated as ordinary text
164 if self.symbol:
165 self._append_symbol_line(line)
166 elif not self.body.content and line.startswith("@"):
167 if not line.endswith(":"):
168 raise QAPIParseError(self.parser, "Line should end with :")
169 self.symbol = line[1:-1]
170 # FIXME invalid names other than the empty string aren't flagged
171 if not self.symbol:
172 raise QAPIParseError(self.parser, "Invalid name")
173 else:
174 self._append_freeform(line)
175
176 def _append_symbol_line(self, line):
177 name = line.split(' ', 1)[0]
178
179 if name.startswith("@") and name.endswith(":"):
180 line = line[len(name)+1:]
181 self._start_args_section(name[1:-1])
182 elif name in ("Returns:", "Since:",
183 # those are often singular or plural
184 "Note:", "Notes:",
185 "Example:", "Examples:",
186 "TODO:"):
187 line = line[len(name)+1:]
188 self._start_section(name[:-1])
189
190 self._append_freeform(line)
191
192 def _start_args_section(self, name):
193 # FIXME invalid names other than the empty string aren't flagged
194 if not name:
195 raise QAPIParseError(self.parser, "Invalid parameter name")
196 if name in self.args:
197 raise QAPIParseError(self.parser,
198 "'%s' parameter name duplicated" % name)
199 if self.sections:
200 raise QAPIParseError(self.parser,
201 "'@%s:' can't follow '%s' section"
202 % (name, self.sections[0].name))
203 self.section = QAPIDoc.ArgSection(name)
204 self.args[name] = self.section
205
206 def _start_section(self, name=""):
207 if name in ("Returns", "Since") and self.has_section(name):
208 raise QAPIParseError(self.parser,
209 "Duplicated '%s' section" % name)
210 self.section = QAPIDoc.Section(name)
211 self.sections.append(self.section)
212
213 def _append_freeform(self, line):
214 in_arg = isinstance(self.section, QAPIDoc.ArgSection)
215 if (in_arg and self.section.content
216 and not self.section.content[-1]
217 and line and not line[0].isspace()):
218 self._start_section()
219 if (in_arg or not self.section.name
220 or not self.section.name.startswith("Example")):
221 line = line.strip()
222 self.section.append(line)
223
Markus Armbruster069fb5b2017-03-15 13:57:03 +0100224 def connect_member(self, member):
225 if member.name not in self.args:
226 # Undocumented TODO outlaw
227 pass
228 else:
229 self.args[member.name].connect(member)
230
Marc-André Lureau3313b612017-01-13 15:41:29 +0100231
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200232class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500233
Eric Blake437db252015-09-29 16:21:02 -0600234 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200235 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200236 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200237 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200238 previously_included.append(abs_fname)
239 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200240 self.src = fp.read()
241 if self.src == '' or self.src[-1] != '\n':
242 self.src += '\n'
243 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800244 self.line = 1
245 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200246 self.exprs = []
Marc-André Lureau3313b612017-01-13 15:41:29 +0100247 self.docs = []
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200248 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500249
Eric Blake437db252015-09-29 16:21:02 -0600250 while self.tok is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100251 info = {'file': fname, 'line': self.line,
252 'parent': self.incl_info}
Marc-André Lureau3313b612017-01-13 15:41:29 +0100253 if self.tok == '#':
254 doc = self.get_doc(info)
255 self.docs.append(doc)
256 continue
257
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200258 expr = self.get_expr(False)
Markus Armbrustere04dea82017-03-15 13:56:50 +0100259 if 'include' in expr:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200260 if len(expr) != 1:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100261 raise QAPISemError(info, "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200262 include = expr["include"]
263 if not isinstance(include, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100264 raise QAPISemError(info,
265 "Value of 'include' must be a string")
Markus Armbrustere04dea82017-03-15 13:56:50 +0100266 self._include(include, info, os.path.dirname(abs_fname),
267 previously_included)
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100268 elif "pragma" in expr:
269 if len(expr) != 1:
270 raise QAPISemError(info, "Invalid 'pragma' directive")
271 pragma = expr['pragma']
272 if not isinstance(pragma, dict):
273 raise QAPISemError(
274 info, "Value of 'pragma' must be a dictionary")
275 for name, value in pragma.iteritems():
276 self._pragma(name, value, info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200277 else:
278 expr_elem = {'expr': expr,
Marc-André Lureau4148c292017-01-13 15:41:25 +0100279 'info': info}
Marc-André Lureau3313b612017-01-13 15:41:29 +0100280 if (self.docs
281 and self.docs[-1].info['file'] == fname
282 and not self.docs[-1].expr):
283 self.docs[-1].expr = expr
284 expr_elem['doc'] = self.docs[-1]
285
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200286 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500287
Markus Armbrustere04dea82017-03-15 13:56:50 +0100288 def _include(self, include, info, base_dir, previously_included):
289 incl_abs_fname = os.path.join(base_dir, include)
290 # catch inclusion cycle
291 inf = info
292 while inf:
293 if incl_abs_fname == os.path.abspath(inf['file']):
294 raise QAPISemError(info, "Inclusion loop for %s" % include)
295 inf = inf['parent']
296
297 # skip multiple include of the same file
298 if incl_abs_fname in previously_included:
299 return
300 try:
301 fobj = open(incl_abs_fname, 'r')
302 except IOError as e:
303 raise QAPISemError(info, '%s: %s' % (e.strerror, include))
304 exprs_include = QAPISchemaParser(fobj, previously_included, info)
305 self.exprs.extend(exprs_include.exprs)
306 self.docs.extend(exprs_include.docs)
307
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100308 def _pragma(self, name, value, info):
Markus Armbruster2cfbae32017-03-15 13:56:55 +0100309 global doc_required, returns_whitelist, name_case_whitelist
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100310 if name == 'doc-required':
311 if not isinstance(value, bool):
312 raise QAPISemError(info,
313 "Pragma 'doc-required' must be boolean")
314 doc_required = value
Markus Armbruster1554a8f2017-03-15 13:56:54 +0100315 elif name == 'returns-whitelist':
316 if (not isinstance(value, list)
317 or any([not isinstance(elt, str) for elt in value])):
318 raise QAPISemError(info,
319 "Pragma returns-whitelist must be"
320 " a list of strings")
321 returns_whitelist = value
Markus Armbruster2cfbae32017-03-15 13:56:55 +0100322 elif name == 'name-case-whitelist':
323 if (not isinstance(value, list)
324 or any([not isinstance(elt, str) for elt in value])):
325 raise QAPISemError(info,
326 "Pragma name-case-whitelist must be"
327 " a list of strings")
328 name_case_whitelist = value
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100329 else:
330 raise QAPISemError(info, "Unknown pragma '%s'" % name)
331
Marc-André Lureau3313b612017-01-13 15:41:29 +0100332 def accept(self, skip_comment=True):
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200333 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200334 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200335 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200336 self.cursor += 1
337 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500338
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200339 if self.tok == '#':
Marc-André Lureau3313b612017-01-13 15:41:29 +0100340 if self.src[self.cursor] == '#':
341 # Start of doc comment
342 skip_comment = False
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200343 self.cursor = self.src.find('\n', self.cursor)
Marc-André Lureau3313b612017-01-13 15:41:29 +0100344 if not skip_comment:
345 self.val = self.src[self.pos:self.cursor]
346 return
Eric Blake8712fa52015-10-26 16:34:41 -0600347 elif self.tok in "{}:,[]":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200348 return
349 elif self.tok == "'":
350 string = ''
351 esc = False
352 while True:
353 ch = self.src[self.cursor]
354 self.cursor += 1
355 if ch == '\n':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100356 raise QAPIParseError(self, 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200357 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600358 if ch == 'b':
359 string += '\b'
360 elif ch == 'f':
361 string += '\f'
362 elif ch == 'n':
363 string += '\n'
364 elif ch == 'r':
365 string += '\r'
366 elif ch == 't':
367 string += '\t'
368 elif ch == 'u':
369 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600370 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600371 ch = self.src[self.cursor]
372 self.cursor += 1
373 if ch not in "0123456789abcdefABCDEF":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100374 raise QAPIParseError(self,
375 '\\u escape needs 4 '
376 'hex digits')
Eric Blakea7f59662015-05-04 09:05:36 -0600377 value = (value << 4) + int(ch, 16)
378 # If Python 2 and 3 didn't disagree so much on
379 # how to handle Unicode, then we could allow
380 # Unicode string defaults. But most of QAPI is
381 # ASCII-only, so we aren't losing much for now.
382 if not value or value > 0x7f:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100383 raise QAPIParseError(self,
384 'For now, \\u escape '
385 'only supports non-zero '
386 'values up to \\u007f')
Eric Blakea7f59662015-05-04 09:05:36 -0600387 string += chr(value)
388 elif ch in "\\/'\"":
389 string += ch
390 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100391 raise QAPIParseError(self,
392 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200393 esc = False
394 elif ch == "\\":
395 esc = True
396 elif ch == "'":
397 self.val = string
398 return
399 else:
400 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200401 elif self.src.startswith("true", self.pos):
402 self.val = True
403 self.cursor += 3
404 return
405 elif self.src.startswith("false", self.pos):
406 self.val = False
407 self.cursor += 4
408 return
409 elif self.src.startswith("null", self.pos):
410 self.val = None
411 self.cursor += 3
412 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200413 elif self.tok == '\n':
414 if self.cursor == len(self.src):
415 self.tok = None
416 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800417 self.line += 1
418 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200419 elif not self.tok.isspace():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100420 raise QAPIParseError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500421
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200422 def get_members(self):
423 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200424 if self.tok == '}':
425 self.accept()
426 return expr
427 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100428 raise QAPIParseError(self, 'Expected string or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200429 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200430 key = self.val
431 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200432 if self.tok != ':':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100433 raise QAPIParseError(self, 'Expected ":"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200434 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800435 if key in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100436 raise QAPIParseError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200437 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200438 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200439 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200440 return expr
441 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100442 raise QAPIParseError(self, 'Expected "," or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200443 self.accept()
444 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100445 raise QAPIParseError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500446
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200447 def get_values(self):
448 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200449 if self.tok == ']':
450 self.accept()
451 return expr
Eric Blake437db252015-09-29 16:21:02 -0600452 if self.tok not in "{['tfn":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100453 raise QAPIParseError(self, 'Expected "{", "[", "]", string, '
454 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200455 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200456 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200457 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200458 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200459 return expr
460 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100461 raise QAPIParseError(self, 'Expected "," or "]"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200462 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500463
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200464 def get_expr(self, nested):
465 if self.tok != '{' and not nested:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100466 raise QAPIParseError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200467 if self.tok == '{':
468 self.accept()
469 expr = self.get_members()
470 elif self.tok == '[':
471 self.accept()
472 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600473 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200474 expr = self.val
475 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200476 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100477 raise QAPIParseError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200478 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200479
Marc-André Lureau3313b612017-01-13 15:41:29 +0100480 def get_doc(self, info):
481 if self.val != '##':
482 raise QAPIParseError(self, "Junk after '##' at start of "
483 "documentation comment")
484
485 doc = QAPIDoc(self, info)
486 self.accept(False)
487 while self.tok == '#':
488 if self.val.startswith('##'):
489 # End of doc comment
490 if self.val != '##':
491 raise QAPIParseError(self, "Junk after '##' at end of "
492 "documentation comment")
493 self.accept()
494 return doc
495 else:
496 doc.append(self.val)
497 self.accept(False)
498
499 raise QAPIParseError(self, "Documentation comment must end with '##'")
500
501
Markus Armbruster00e4b282015-06-10 10:04:36 +0200502#
503# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200504# TODO fold into QAPISchema
505# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200506#
507
Eric Blake437db252015-09-29 16:21:02 -0600508
Eric Blake14f00c62016-03-03 09:16:43 -0700509def find_base_members(base):
Eric Blakeac4338f2016-03-17 16:48:39 -0600510 if isinstance(base, dict):
511 return base
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800512 base_struct_define = find_struct(base)
513 if not base_struct_define:
514 return None
515 return base_struct_define['data']
516
Eric Blake437db252015-09-29 16:21:02 -0600517
Eric Blake811d04f2015-05-04 09:05:10 -0600518# Return the qtype of an alternate branch, or None on error.
519def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600520 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600521 return builtin_types[qapi_type]
522 elif find_struct(qapi_type):
523 return "QTYPE_QDICT"
524 elif find_enum(qapi_type):
525 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600526 elif find_union(qapi_type):
527 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600528 return None
529
Eric Blake437db252015-09-29 16:21:02 -0600530
Wenchao Xiabceae762014-03-06 17:08:56 -0800531# Return the discriminator enum define if discriminator is specified as an
532# enum type, otherwise return None.
533def discriminator_find_enum_define(expr):
534 base = expr.get('base')
535 discriminator = expr.get('discriminator')
536
537 if not (discriminator and base):
538 return None
539
Eric Blake14f00c62016-03-03 09:16:43 -0700540 base_members = find_base_members(base)
541 if not base_members:
Wenchao Xiabceae762014-03-06 17:08:56 -0800542 return None
543
Eric Blake14f00c62016-03-03 09:16:43 -0700544 discriminator_type = base_members.get(discriminator)
Wenchao Xiabceae762014-03-06 17:08:56 -0800545 if not discriminator_type:
546 return None
547
548 return find_enum(discriminator_type)
549
Eric Blake437db252015-09-29 16:21:02 -0600550
Eric Blake59a92fe2015-11-18 01:52:56 -0700551# Names must be letters, numbers, -, and _. They must start with letter,
552# except for downstream extensions which must start with __RFQDN_.
553# Dots are only valid in the downstream extension prefix.
554valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
555 '[a-zA-Z][a-zA-Z0-9_-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600556
557
Marc-André Lureau4148c292017-01-13 15:41:25 +0100558def check_name(info, source, name, allow_optional=False,
Eric Blake437db252015-09-29 16:21:02 -0600559 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600560 global valid_name
561 membername = name
562
563 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100564 raise QAPISemError(info, "%s requires a string name" % source)
Eric Blakec9e0a792015-05-04 09:05:22 -0600565 if name.startswith('*'):
566 membername = name[1:]
567 if not allow_optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100568 raise QAPISemError(info, "%s does not allow optional name '%s'"
569 % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600570 # Enum members can start with a digit, because the generated C
571 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700572 if enum_member and membername[0].isdigit():
573 membername = 'D' + membername
Eric Blake75996972016-03-17 16:48:29 -0600574 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
575 # and 'q_obj_*' implicit type names.
Eric Blake9fb081e2015-10-26 16:34:44 -0600576 if not valid_name.match(membername) or \
577 c_name(membername, False).startswith('q_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100578 raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600579
Eric Blake437db252015-09-29 16:21:02 -0600580
581def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200582 global all_names
583 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200584 # FIXME should reject names that differ only in '_' vs. '.'
585 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200586 if name in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100587 raise QAPISemError(info, "%s '%s' is already defined"
588 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600589 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100590 raise QAPISemError(info, "%s '%s' should not end in '%s'"
591 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200592 all_names[name] = meta
593
Eric Blake437db252015-09-29 16:21:02 -0600594
Markus Armbruster00e4b282015-06-10 10:04:36 +0200595def add_struct(definition, info):
596 global struct_types
597 name = definition['struct']
598 add_name(name, info, 'struct')
599 struct_types.append(definition)
600
Eric Blake437db252015-09-29 16:21:02 -0600601
Markus Armbruster00e4b282015-06-10 10:04:36 +0200602def find_struct(name):
603 global struct_types
604 for struct in struct_types:
605 if struct['struct'] == name:
606 return struct
607 return None
608
Eric Blake437db252015-09-29 16:21:02 -0600609
Markus Armbruster00e4b282015-06-10 10:04:36 +0200610def add_union(definition, info):
611 global union_types
612 name = definition['union']
613 add_name(name, info, 'union')
614 union_types.append(definition)
615
Eric Blake437db252015-09-29 16:21:02 -0600616
Markus Armbruster00e4b282015-06-10 10:04:36 +0200617def find_union(name):
618 global union_types
619 for union in union_types:
620 if union['union'] == name:
621 return union
622 return None
623
Eric Blake437db252015-09-29 16:21:02 -0600624
625def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200626 global enum_types
627 add_name(name, info, 'enum', implicit)
628 enum_types.append({"enum_name": name, "enum_values": enum_values})
629
Eric Blake437db252015-09-29 16:21:02 -0600630
Markus Armbruster00e4b282015-06-10 10:04:36 +0200631def find_enum(name):
632 global enum_types
633 for enum in enum_types:
634 if enum['enum_name'] == name:
635 return enum
636 return None
637
Markus Armbruster00e4b282015-06-10 10:04:36 +0200638
Eric Blake437db252015-09-29 16:21:02 -0600639def is_enum(name):
640 return find_enum(name) is not None
641
642
Marc-André Lureau4148c292017-01-13 15:41:25 +0100643def check_type(info, source, value, allow_array=False,
Eric Blake437db252015-09-29 16:21:02 -0600644 allow_dict=False, allow_optional=False,
645 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600646 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600647
648 if value is None:
649 return
650
Eric Blakedd883c62015-05-04 09:05:21 -0600651 # Check if array type for value is okay
652 if isinstance(value, list):
653 if not allow_array:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100654 raise QAPISemError(info, "%s cannot be an array" % source)
Eric Blakedd883c62015-05-04 09:05:21 -0600655 if len(value) != 1 or not isinstance(value[0], str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100656 raise QAPISemError(info,
657 "%s: array type must contain single type name" %
658 source)
Eric Blakedd883c62015-05-04 09:05:21 -0600659 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600660
661 # Check if type name for value is okay
662 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600663 if value not in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100664 raise QAPISemError(info, "%s uses unknown type '%s'"
665 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600666 if not all_names[value] in allow_metas:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100667 raise QAPISemError(info, "%s cannot use %s type '%s'" %
668 (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600669 return
670
Eric Blakedd883c62015-05-04 09:05:21 -0600671 if not allow_dict:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100672 raise QAPISemError(info, "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200673
674 if not isinstance(value, OrderedDict):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100675 raise QAPISemError(info,
676 "%s should be a dictionary or type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200677
678 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600679 for (key, arg) in value.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100680 check_name(info, "Member of %s" % source, key,
Eric Blakec9e0a792015-05-04 09:05:22 -0600681 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600682 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100683 raise QAPISemError(info, "Member of %s uses reserved name '%s'"
684 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600685 # Todo: allow dictionaries to represent default values of
686 # an optional argument.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100687 check_type(info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200688 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600689 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600690 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600691
Eric Blake437db252015-09-29 16:21:02 -0600692
Marc-André Lureau4148c292017-01-13 15:41:25 +0100693def check_command(expr, info):
Eric Blakedd883c62015-05-04 09:05:21 -0600694 name = expr['command']
Eric Blakec8184082016-07-13 21:50:20 -0600695 boxed = expr.get('boxed', False)
Eric Blake2cbf0992015-05-04 09:05:24 -0600696
Eric Blakec8184082016-07-13 21:50:20 -0600697 args_meta = ['struct']
698 if boxed:
699 args_meta += ['union', 'alternate']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100700 check_type(info, "'data' for command '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600701 expr.get('data'), allow_dict=not boxed, allow_optional=True,
702 allow_metas=args_meta)
Eric Blake10d4d992015-05-04 09:05:23 -0600703 returns_meta = ['union', 'struct']
704 if name in returns_whitelist:
705 returns_meta += ['built-in', 'alternate', 'enum']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100706 check_type(info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200707 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200708 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600709
Eric Blake437db252015-09-29 16:21:02 -0600710
Marc-André Lureau4148c292017-01-13 15:41:25 +0100711def check_event(expr, info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600712 global events
713 name = expr['event']
Eric Blakec8184082016-07-13 21:50:20 -0600714 boxed = expr.get('boxed', False)
Eric Blake4dc2e692015-05-04 09:05:17 -0600715
Eric Blakec8184082016-07-13 21:50:20 -0600716 meta = ['struct']
717 if boxed:
718 meta += ['union', 'alternate']
Eric Blake4dc2e692015-05-04 09:05:17 -0600719 events.append(name)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100720 check_type(info, "'data' for event '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600721 expr.get('data'), allow_dict=not boxed, allow_optional=True,
722 allow_metas=meta)
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200723
Eric Blake437db252015-09-29 16:21:02 -0600724
Marc-André Lureau4148c292017-01-13 15:41:25 +0100725def check_union(expr, info):
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800726 name = expr['union']
727 base = expr.get('base')
728 discriminator = expr.get('discriminator')
729 members = expr['data']
730
Eric Blake811d04f2015-05-04 09:05:10 -0600731 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600732
733 # With no discriminator it is a simple union.
734 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600735 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600736 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600737 if base is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100738 raise QAPISemError(info, "Simple union '%s' must not have a base" %
739 name)
Eric Blake44bd1272015-05-04 09:05:08 -0600740
741 # Else, it's a flat union.
742 else:
Eric Blakeac4338f2016-03-17 16:48:39 -0600743 # The object must have a string or dictionary 'base'.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100744 check_type(info, "'base' for union '%s'" % name,
Eric Blakeac4338f2016-03-17 16:48:39 -0600745 base, allow_dict=True, allow_optional=True,
746 allow_metas=['struct'])
Eric Blake376863e2015-09-29 16:21:07 -0600747 if not base:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100748 raise QAPISemError(info, "Flat union '%s' must have a base"
749 % name)
Eric Blake14f00c62016-03-03 09:16:43 -0700750 base_members = find_base_members(base)
Markus Armbruster48153742017-03-15 13:56:58 +0100751 assert base_members is not None
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800752
Eric Blakec9e0a792015-05-04 09:05:22 -0600753 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600754 # member of the base struct.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100755 check_name(info, "Discriminator of flat union '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600756 discriminator)
Eric Blake14f00c62016-03-03 09:16:43 -0700757 discriminator_type = base_members.get(discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800758 if not discriminator_type:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100759 raise QAPISemError(info,
760 "Discriminator '%s' is not a member of base "
761 "struct '%s'"
762 % (discriminator, base))
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800763 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600764 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800765 # Do not allow string discriminator
766 if not enum_define:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100767 raise QAPISemError(info,
768 "Discriminator '%s' must be of enumeration "
769 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800770
Eric Blake02a57ae2016-02-17 23:48:16 -0700771 # Check every branch; don't allow an empty union
772 if len(members) == 0:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100773 raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800774 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100775 check_name(info, "Member of union '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600776
Eric Blake01cfbaa2015-12-01 22:20:58 -0700777 # Each value must name a known type
Marc-André Lureau4148c292017-01-13 15:41:25 +0100778 check_type(info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200779 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600780
Eric Blake44bd1272015-05-04 09:05:08 -0600781 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700782 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600783 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600784 if key not in enum_define['enum_values']:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100785 raise QAPISemError(info,
786 "Discriminator value '%s' is not found in "
787 "enum '%s'"
788 % (key, enum_define["enum_name"]))
Eric Blake44bd1272015-05-04 09:05:08 -0600789
Eric Blaked0b18232016-07-13 21:50:13 -0600790 # If discriminator is user-defined, ensure all values are covered
791 if enum_define:
792 for value in enum_define['enum_values']:
793 if value not in members.keys():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100794 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
795 % (name, value))
Eric Blaked0b18232016-07-13 21:50:13 -0600796
Eric Blake437db252015-09-29 16:21:02 -0600797
Marc-André Lureau4148c292017-01-13 15:41:25 +0100798def check_alternate(expr, info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600799 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600800 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600801 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600802
Eric Blake02a57ae2016-02-17 23:48:16 -0700803 # Check every branch; require at least two branches
804 if len(members) < 2:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100805 raise QAPISemError(info,
806 "Alternate '%s' should have at least two branches "
807 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600808 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100809 check_name(info, "Member of alternate '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600810
Eric Blake811d04f2015-05-04 09:05:10 -0600811 # Ensure alternates have no type conflicts.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100812 check_type(info, "Member '%s' of alternate '%s'" % (key, name),
Eric Blakedd883c62015-05-04 09:05:21 -0600813 value,
814 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600815 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700816 if not qtype:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100817 raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
818 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600819 if qtype in types_seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100820 raise QAPISemError(info, "Alternate '%s' member '%s' can't "
821 "be distinguished from member '%s'"
822 % (name, key, types_seen[qtype]))
Eric Blake811d04f2015-05-04 09:05:10 -0600823 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800824
Eric Blake437db252015-09-29 16:21:02 -0600825
Marc-André Lureau4148c292017-01-13 15:41:25 +0100826def check_enum(expr, info):
Eric Blakecf393592015-05-04 09:05:04 -0600827 name = expr['enum']
828 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100829 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600830
831 if not isinstance(members, list):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100832 raise QAPISemError(info,
833 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100834 if prefix is not None and not isinstance(prefix, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100835 raise QAPISemError(info,
836 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600837 for member in members:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100838 check_name(info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600839 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600840
Eric Blake437db252015-09-29 16:21:02 -0600841
Marc-André Lureau4148c292017-01-13 15:41:25 +0100842def check_struct(expr, info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600843 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600844 members = expr['data']
845
Marc-André Lureau4148c292017-01-13 15:41:25 +0100846 check_type(info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600847 allow_dict=True, allow_optional=True)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100848 check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600849 allow_metas=['struct'])
850
Eric Blake437db252015-09-29 16:21:02 -0600851
Eric Blake0545f6b2015-05-04 09:05:15 -0600852def check_keys(expr_elem, meta, required, optional=[]):
853 expr = expr_elem['expr']
854 info = expr_elem['info']
855 name = expr[meta]
856 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100857 raise QAPISemError(info, "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600858 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600859 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600860 if key not in required and key not in optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100861 raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
862 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600863 if (key == 'gen' or key == 'success-response') and value is not False:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100864 raise QAPISemError(info,
865 "'%s' of %s '%s' should only use false value"
866 % (key, meta, name))
Eric Blakec8184082016-07-13 21:50:20 -0600867 if key == 'boxed' and value is not True:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100868 raise QAPISemError(info,
869 "'%s' of %s '%s' should only use true value"
870 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600871 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600872 if key not in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100873 raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
874 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600875
Eric Blake437db252015-09-29 16:21:02 -0600876
Markus Armbruster4d076d62015-06-10 08:55:21 +0200877def check_exprs(exprs):
878 global all_names
879
880 # Learn the types and check for valid expression keys
881 for builtin in builtin_types.keys():
882 all_names[builtin] = 'built-in'
883 for expr_elem in exprs:
884 expr = expr_elem['expr']
885 info = expr_elem['info']
Marc-André Lureau3313b612017-01-13 15:41:29 +0100886
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100887 if 'doc' not in expr_elem and doc_required:
Marc-André Lureau3313b612017-01-13 15:41:29 +0100888 raise QAPISemError(info,
889 "Expression missing documentation comment")
890
Eric Blake437db252015-09-29 16:21:02 -0600891 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100892 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200893 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600894 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200895 check_keys(expr_elem, 'union', ['data'],
896 ['base', 'discriminator'])
897 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600898 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200899 check_keys(expr_elem, 'alternate', ['data'])
900 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600901 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200902 check_keys(expr_elem, 'struct', ['data'], ['base'])
903 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600904 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200905 check_keys(expr_elem, 'command', [],
Eric Blakec8184082016-07-13 21:50:20 -0600906 ['data', 'returns', 'gen', 'success-response', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200907 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600908 elif 'event' in expr:
Eric Blakec8184082016-07-13 21:50:20 -0600909 check_keys(expr_elem, 'event', [], ['data', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200910 add_name(expr['event'], info, 'event')
911 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100912 raise QAPISemError(expr_elem['info'],
913 "Expression is missing metatype")
Markus Armbruster4d076d62015-06-10 08:55:21 +0200914
915 # Try again for hidden UnionKind enum
916 for expr_elem in exprs:
917 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600918 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200919 if not discriminator_find_enum_define(expr):
920 add_enum('%sKind' % expr['union'], expr_elem['info'],
921 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600922 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200923 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
924 implicit=True)
925
926 # Validate that exprs make sense
927 for expr_elem in exprs:
928 expr = expr_elem['expr']
929 info = expr_elem['info']
930
Eric Blake437db252015-09-29 16:21:02 -0600931 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200932 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600933 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200934 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600935 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200936 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600937 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200938 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600939 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200940 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600941 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200942 check_event(expr, info)
943 else:
944 assert False, 'unexpected meta type'
945
Markus Armbrusterac882192015-09-16 13:06:05 +0200946 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600947
Markus Armbrusterac882192015-09-16 13:06:05 +0200948
Marc-André Lureau3313b612017-01-13 15:41:29 +0100949def check_freeform_doc(doc):
950 if doc.symbol:
951 raise QAPISemError(doc.info,
952 "Documention for '%s' is not followed"
953 " by the definition" % doc.symbol)
954
955 body = str(doc.body)
956 if re.search(r'@\S+:', body, re.MULTILINE):
957 raise QAPISemError(doc.info,
958 "Free-form documentation block must not contain"
959 " @NAME: sections")
960
961
962def check_definition_doc(doc, expr, info):
963 for i in ('enum', 'union', 'alternate', 'struct', 'command', 'event'):
964 if i in expr:
965 meta = i
966 break
967
968 name = expr[meta]
969 if doc.symbol != name:
970 raise QAPISemError(info, "Definition of '%s' follows documentation"
971 " for '%s'" % (name, doc.symbol))
972 if doc.has_section('Returns') and 'command' not in expr:
973 raise QAPISemError(info, "'Returns:' is only valid for commands")
974
975 if meta == 'union':
976 args = expr.get('base', [])
977 else:
978 args = expr.get('data', [])
979 if isinstance(args, str):
980 return
981 if isinstance(args, dict):
982 args = args.keys()
983 assert isinstance(args, list)
984
985 if (meta == 'alternate'
986 or (meta == 'union' and not expr.get('discriminator'))):
987 args.append('type')
988
989 for arg in args:
990 if arg[0] == '*':
991 opt = True
992 desc = doc.args.get(arg[1:])
993 else:
994 opt = False
995 desc = doc.args.get(arg)
996 if not desc:
997 continue
Markus Armbrusterb116fd82017-03-15 13:57:00 +0100998 desc.optional = opt
Marc-André Lureau3313b612017-01-13 15:41:29 +0100999 desc_opt = "#optional" in str(desc)
1000 if desc_opt and not opt:
1001 raise QAPISemError(info, "Description has #optional, "
1002 "but the declaration doesn't")
1003 if not desc_opt and opt:
Marc-André Lureau3313b612017-01-13 15:41:29 +01001004 # TODO either fix the schema and make this an error,
1005 # or drop #optional entirely
Markus Armbrusterb116fd82017-03-15 13:57:00 +01001006 pass
Marc-André Lureau3313b612017-01-13 15:41:29 +01001007
1008 doc_args = set(doc.args.keys())
1009 args = set([name.strip('*') for name in args])
1010 if not doc_args.issubset(args):
1011 raise QAPISemError(info, "The following documented members are not in "
1012 "the declaration: %s" % ", ".join(doc_args - args))
1013
1014
1015def check_docs(docs):
1016 for doc in docs:
1017 for section in doc.args.values() + doc.sections:
1018 content = str(section)
1019 if not content or content.isspace():
1020 raise QAPISemError(doc.info,
1021 "Empty doc section '%s'" % section.name)
1022
1023 if not doc.expr:
1024 check_freeform_doc(doc)
1025 else:
1026 check_definition_doc(doc, doc.expr, doc.info)
1027
1028 return docs
1029
1030
Markus Armbrusterac882192015-09-16 13:06:05 +02001031#
1032# Schema compiler frontend
1033#
1034
1035class QAPISchemaEntity(object):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001036 def __init__(self, name, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001037 assert isinstance(name, str)
1038 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -06001039 # For explicitly defined entities, info points to the (explicit)
1040 # definition. For builtins (and their arrays), info is None.
1041 # For implicitly defined entities, info points to a place that
1042 # triggered the implicit definition (there may be more than one
1043 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +02001044 self.info = info
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001045 self.doc = doc
Markus Armbrusterac882192015-09-16 13:06:05 +02001046
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001047 def c_name(self):
1048 return c_name(self.name)
1049
Markus Armbrusterac882192015-09-16 13:06:05 +02001050 def check(self, schema):
1051 pass
1052
Eric Blake49823c42015-10-12 22:22:27 -06001053 def is_implicit(self):
1054 return not self.info
1055
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001056 def visit(self, visitor):
1057 pass
1058
1059
1060class QAPISchemaVisitor(object):
1061 def visit_begin(self, schema):
1062 pass
1063
1064 def visit_end(self):
1065 pass
1066
Eric Blake25a0d9c2015-10-12 22:22:21 -06001067 def visit_needed(self, entity):
1068 # Default to visiting everything
1069 return True
1070
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001071 def visit_builtin_type(self, name, info, json_type):
1072 pass
1073
1074 def visit_enum_type(self, name, info, values, prefix):
1075 pass
1076
1077 def visit_array_type(self, name, info, element_type):
1078 pass
1079
1080 def visit_object_type(self, name, info, base, members, variants):
1081 pass
1082
Markus Armbruster39a18152015-09-16 13:06:28 +02001083 def visit_object_type_flat(self, name, info, members, variants):
1084 pass
1085
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001086 def visit_alternate_type(self, name, info, variants):
1087 pass
1088
1089 def visit_command(self, name, info, arg_type, ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001090 gen, success_response, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001091 pass
1092
Eric Blake48825ca2016-07-13 21:50:19 -06001093 def visit_event(self, name, info, arg_type, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001094 pass
1095
Markus Armbrusterac882192015-09-16 13:06:05 +02001096
1097class QAPISchemaType(QAPISchemaEntity):
Eric Blake4040d992016-03-17 16:48:28 -06001098 # Return the C type for common use.
1099 # For the types we commonly box, this is a pointer type.
1100 def c_type(self):
1101 pass
1102
1103 # Return the C type to be used in a parameter list.
1104 def c_param_type(self):
1105 return self.c_type()
1106
1107 # Return the C type to be used where we suppress boxing.
1108 def c_unboxed_type(self):
1109 return self.c_type()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001110
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001111 def json_type(self):
1112 pass
1113
1114 def alternate_qtype(self):
1115 json2qtype = {
1116 'string': 'QTYPE_QSTRING',
1117 'number': 'QTYPE_QFLOAT',
1118 'int': 'QTYPE_QINT',
1119 'boolean': 'QTYPE_QBOOL',
1120 'object': 'QTYPE_QDICT'
1121 }
1122 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +02001123
1124
1125class QAPISchemaBuiltinType(QAPISchemaType):
Eric Blake861877a2016-03-17 16:48:36 -06001126 def __init__(self, name, json_type, c_type):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001127 QAPISchemaType.__init__(self, name, None, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001128 assert not c_type or isinstance(c_type, str)
1129 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
1130 'value')
1131 self._json_type_name = json_type
1132 self._c_type_name = c_type
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001133
1134 def c_name(self):
1135 return self.name
1136
Eric Blake4040d992016-03-17 16:48:28 -06001137 def c_type(self):
1138 return self._c_type_name
1139
1140 def c_param_type(self):
1141 if self.name == 'str':
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001142 return 'const ' + self._c_type_name
1143 return self._c_type_name
1144
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001145 def json_type(self):
1146 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +02001147
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001148 def visit(self, visitor):
1149 visitor.visit_builtin_type(self.name, self.info, self.json_type())
1150
Markus Armbrusterac882192015-09-16 13:06:05 +02001151
1152class QAPISchemaEnumType(QAPISchemaType):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001153 def __init__(self, name, info, doc, values, prefix):
1154 QAPISchemaType.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001155 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -07001156 assert isinstance(v, QAPISchemaMember)
1157 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001158 assert prefix is None or isinstance(prefix, str)
1159 self.values = values
1160 self.prefix = prefix
1161
1162 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -07001163 seen = {}
1164 for v in self.values:
1165 v.check_clash(self.info, seen)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001166 if self.doc:
1167 self.doc.connect_member(v)
Markus Armbrusterac882192015-09-16 13:06:05 +02001168
Eric Blake99df5282015-10-12 22:22:32 -06001169 def is_implicit(self):
Markus Armbruster46362112017-03-15 13:57:02 +01001170 # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
1171 return self.name.endswith('Kind') or self.name == 'QType'
Eric Blake99df5282015-10-12 22:22:32 -06001172
Eric Blake4040d992016-03-17 16:48:28 -06001173 def c_type(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001174 return c_name(self.name)
1175
Eric Blake93bda4d2015-12-01 22:20:55 -07001176 def member_names(self):
1177 return [v.name for v in self.values]
1178
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001179 def json_type(self):
1180 return 'string'
1181
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001182 def visit(self, visitor):
1183 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -07001184 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001185
Markus Armbrusterac882192015-09-16 13:06:05 +02001186
1187class QAPISchemaArrayType(QAPISchemaType):
1188 def __init__(self, name, info, element_type):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001189 QAPISchemaType.__init__(self, name, info, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001190 assert isinstance(element_type, str)
1191 self._element_type_name = element_type
1192 self.element_type = None
1193
1194 def check(self, schema):
1195 self.element_type = schema.lookup_type(self._element_type_name)
1196 assert self.element_type
1197
Eric Blake99df5282015-10-12 22:22:32 -06001198 def is_implicit(self):
1199 return True
1200
Eric Blake4040d992016-03-17 16:48:28 -06001201 def c_type(self):
1202 return c_name(self.name) + pointer_suffix
1203
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001204 def json_type(self):
1205 return 'array'
1206
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001207 def visit(self, visitor):
1208 visitor.visit_array_type(self.name, self.info, self.element_type)
1209
Markus Armbrusterac882192015-09-16 13:06:05 +02001210
1211class QAPISchemaObjectType(QAPISchemaType):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001212 def __init__(self, name, info, doc, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -07001213 # struct has local_members, optional base, and no variants
1214 # flat union has base, variants, and no local_members
1215 # simple union has local_members, variants, and no base
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001216 QAPISchemaType.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001217 assert base is None or isinstance(base, str)
1218 for m in local_members:
1219 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -07001220 m.set_owner(name)
1221 if variants is not None:
1222 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1223 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001224 self._base_name = base
1225 self.base = None
1226 self.local_members = local_members
1227 self.variants = variants
1228 self.members = None
1229
1230 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -07001231 if self.members is False: # check for cycles
Marc-André Lureau4148c292017-01-13 15:41:25 +01001232 raise QAPISemError(self.info,
1233 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001234 if self.members:
1235 return
1236 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -07001237 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +02001238 if self._base_name:
1239 self.base = schema.lookup_type(self._base_name)
1240 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +02001241 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001242 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001243 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001244 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001245 m.check_clash(self.info, seen)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001246 if self.doc:
1247 self.doc.connect_member(m)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001248 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +02001249 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001250 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001251 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -07001252 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001253
Eric Blake14f00c62016-03-03 09:16:43 -07001254 # Check that the members of this type do not cause duplicate JSON members,
Eric Blake27b60ab2015-11-18 01:52:51 -07001255 # and update seen to track the members seen so far. Report any errors
1256 # on behalf of info, which is not necessarily self.info
1257 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -07001258 assert not self.variants # not implemented
1259 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -07001260 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -07001261
Eric Blake99df5282015-10-12 22:22:32 -06001262 def is_implicit(self):
Eric Blake75996972016-03-17 16:48:29 -06001263 # See QAPISchema._make_implicit_object_type(), as well as
1264 # _def_predefineds()
1265 return self.name.startswith('q_')
Eric Blake99df5282015-10-12 22:22:32 -06001266
Eric Blakeb6167702016-07-13 21:50:16 -06001267 def is_empty(self):
1268 assert self.members is not None
1269 return not self.members and not self.variants
1270
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001271 def c_name(self):
Eric Blakecd50a252016-07-13 21:50:14 -06001272 assert self.name != 'q_empty'
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001273 return QAPISchemaType.c_name(self)
1274
Eric Blake4040d992016-03-17 16:48:28 -06001275 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001276 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -07001277 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001278
Eric Blake4040d992016-03-17 16:48:28 -06001279 def c_unboxed_type(self):
Eric Blake4040d992016-03-17 16:48:28 -06001280 return c_name(self.name)
1281
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001282 def json_type(self):
1283 return 'object'
1284
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001285 def visit(self, visitor):
1286 visitor.visit_object_type(self.name, self.info,
1287 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001288 visitor.visit_object_type_flat(self.name, self.info,
1289 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001290
Markus Armbrusterac882192015-09-16 13:06:05 +02001291
Eric Blaked44f9ac2015-12-01 22:20:54 -07001292class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001293 role = 'member'
1294
Eric Blaked44f9ac2015-12-01 22:20:54 -07001295 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001296 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001297 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001298 self.owner = None
1299
1300 def set_owner(self, name):
1301 assert not self.owner
1302 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001303
Eric Blake27b60ab2015-11-18 01:52:51 -07001304 def check_clash(self, info, seen):
1305 cname = c_name(self.name)
Markus Armbruster2cfbae32017-03-15 13:56:55 +01001306 if cname.lower() != cname and self.owner not in name_case_whitelist:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001307 raise QAPISemError(info,
1308 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001309 if cname in seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001310 raise QAPISemError(info, "%s collides with %s" %
1311 (self.describe(), seen[cname].describe()))
Eric Blake27b60ab2015-11-18 01:52:51 -07001312 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001313
Eric Blake88d4ef82015-11-18 01:52:50 -07001314 def _pretty_owner(self):
1315 owner = self.owner
Eric Blake75996972016-03-17 16:48:29 -06001316 if owner.startswith('q_obj_'):
Eric Blake88d4ef82015-11-18 01:52:50 -07001317 # See QAPISchema._make_implicit_object_type() - reverse the
1318 # mapping there to create a nice human-readable description
Eric Blake75996972016-03-17 16:48:29 -06001319 owner = owner[6:]
Eric Blake88d4ef82015-11-18 01:52:50 -07001320 if owner.endswith('-arg'):
1321 return '(parameter of %s)' % owner[:-4]
Eric Blakeac4338f2016-03-17 16:48:39 -06001322 elif owner.endswith('-base'):
1323 return '(base of %s)' % owner[:-5]
Eric Blake88d4ef82015-11-18 01:52:50 -07001324 else:
1325 assert owner.endswith('-wrapper')
1326 # Unreachable and not implemented
1327 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001328 if owner.endswith('Kind'):
1329 # See QAPISchema._make_implicit_enum_type()
1330 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001331 return '(%s of %s)' % (self.role, owner)
1332
1333 def describe(self):
1334 return "'%s' %s" % (self.name, self._pretty_owner())
1335
Markus Armbrusterac882192015-09-16 13:06:05 +02001336
Eric Blaked44f9ac2015-12-01 22:20:54 -07001337class QAPISchemaObjectTypeMember(QAPISchemaMember):
1338 def __init__(self, name, typ, optional):
1339 QAPISchemaMember.__init__(self, name)
1340 assert isinstance(typ, str)
1341 assert isinstance(optional, bool)
1342 self._type_name = typ
1343 self.type = None
1344 self.optional = optional
1345
1346 def check(self, schema):
1347 assert self.owner
1348 self.type = schema.lookup_type(self._type_name)
1349 assert self.type
1350
1351
Markus Armbrusterac882192015-09-16 13:06:05 +02001352class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001353 def __init__(self, tag_name, tag_member, variants):
1354 # Flat unions pass tag_name but not tag_member.
1355 # Simple unions and alternates pass tag_member but not tag_name.
1356 # After check(), tag_member is always set, and tag_name remains
1357 # a reliable witness of being used by a flat union.
1358 assert bool(tag_member) != bool(tag_name)
1359 assert (isinstance(tag_name, str) or
1360 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001361 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001362 for v in variants:
1363 assert isinstance(v, QAPISchemaObjectTypeVariant)
Eric Blakeda9cb192016-07-13 21:50:15 -06001364 self._tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001365 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001366 self.variants = variants
1367
Eric Blake88d4ef82015-11-18 01:52:50 -07001368 def set_owner(self, name):
1369 for v in self.variants:
1370 v.set_owner(name)
1371
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001372 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001373 if not self.tag_member: # flat union
Eric Blakeda9cb192016-07-13 21:50:15 -06001374 self.tag_member = seen[c_name(self._tag_name)]
1375 assert self._tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001376 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1377 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001378 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001379 # Union names must match enum values; alternate names are
1380 # checked separately. Use 'seen' to tell the two apart.
1381 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001382 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001383 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001384 v.type.check(schema)
1385
Eric Blake27b60ab2015-11-18 01:52:51 -07001386 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001387 for v in self.variants:
1388 # Reset seen map for each variant, since qapi names from one
1389 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001390 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001391 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001392
Eric Blake437db252015-09-29 16:21:02 -06001393
Markus Armbrusterac882192015-09-16 13:06:05 +02001394class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001395 role = 'branch'
1396
Markus Armbrusterac882192015-09-16 13:06:05 +02001397 def __init__(self, name, typ):
1398 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1399
Markus Armbrusterac882192015-09-16 13:06:05 +02001400
1401class QAPISchemaAlternateType(QAPISchemaType):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001402 def __init__(self, name, info, doc, variants):
1403 QAPISchemaType.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001404 assert isinstance(variants, QAPISchemaObjectTypeVariants)
Eric Blakeda9cb192016-07-13 21:50:15 -06001405 assert variants.tag_member
Eric Blake88d4ef82015-11-18 01:52:50 -07001406 variants.set_owner(name)
1407 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001408 self.variants = variants
1409
1410 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001411 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001412 # Not calling self.variants.check_clash(), because there's nothing
1413 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001414 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001415 # Alternate branch names have no relation to the tag enum values;
1416 # so we have to check for potential name collisions ourselves.
1417 seen = {}
1418 for v in self.variants.variants:
1419 v.check_clash(self.info, seen)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001420 if self.doc:
1421 self.doc.connect_member(v)
Markus Armbrusterac882192015-09-16 13:06:05 +02001422
Eric Blake4040d992016-03-17 16:48:28 -06001423 def c_type(self):
1424 return c_name(self.name) + pointer_suffix
1425
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001426 def json_type(self):
1427 return 'value'
1428
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001429 def visit(self, visitor):
1430 visitor.visit_alternate_type(self.name, self.info, self.variants)
1431
Eric Blakec8184082016-07-13 21:50:20 -06001432 def is_empty(self):
1433 return False
1434
Markus Armbrusterac882192015-09-16 13:06:05 +02001435
1436class QAPISchemaCommand(QAPISchemaEntity):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001437 def __init__(self, name, info, doc, arg_type, ret_type,
1438 gen, success_response, boxed):
1439 QAPISchemaEntity.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001440 assert not arg_type or isinstance(arg_type, str)
1441 assert not ret_type or isinstance(ret_type, str)
1442 self._arg_type_name = arg_type
1443 self.arg_type = None
1444 self._ret_type_name = ret_type
1445 self.ret_type = None
1446 self.gen = gen
1447 self.success_response = success_response
Eric Blake48825ca2016-07-13 21:50:19 -06001448 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001449
1450 def check(self, schema):
1451 if self._arg_type_name:
1452 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001453 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1454 isinstance(self.arg_type, QAPISchemaAlternateType))
1455 self.arg_type.check(schema)
1456 if self.boxed:
1457 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001458 raise QAPISemError(self.info,
1459 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001460 else:
1461 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1462 assert not self.arg_type.variants
1463 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001464 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001465 if self._ret_type_name:
1466 self.ret_type = schema.lookup_type(self._ret_type_name)
1467 assert isinstance(self.ret_type, QAPISchemaType)
1468
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001469 def visit(self, visitor):
1470 visitor.visit_command(self.name, self.info,
1471 self.arg_type, self.ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001472 self.gen, self.success_response, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001473
Markus Armbrusterac882192015-09-16 13:06:05 +02001474
1475class QAPISchemaEvent(QAPISchemaEntity):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001476 def __init__(self, name, info, doc, arg_type, boxed):
1477 QAPISchemaEntity.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001478 assert not arg_type or isinstance(arg_type, str)
1479 self._arg_type_name = arg_type
1480 self.arg_type = None
Eric Blake48825ca2016-07-13 21:50:19 -06001481 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001482
1483 def check(self, schema):
1484 if self._arg_type_name:
1485 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001486 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1487 isinstance(self.arg_type, QAPISchemaAlternateType))
1488 self.arg_type.check(schema)
1489 if self.boxed:
1490 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001491 raise QAPISemError(self.info,
1492 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001493 else:
1494 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1495 assert not self.arg_type.variants
1496 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001497 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001498
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001499 def visit(self, visitor):
Eric Blake48825ca2016-07-13 21:50:19 -06001500 visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001501
Markus Armbrusterac882192015-09-16 13:06:05 +02001502
1503class QAPISchema(object):
1504 def __init__(self, fname):
1505 try:
Marc-André Lureau3313b612017-01-13 15:41:29 +01001506 parser = QAPISchemaParser(open(fname, "r"))
1507 self.exprs = check_exprs(parser.exprs)
1508 self.docs = check_docs(parser.docs)
Eric Blake7618b912015-10-12 22:22:22 -06001509 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001510 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001511 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001512 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001513 self._def_exprs()
1514 self.check()
Marc-André Lureau4148c292017-01-13 15:41:25 +01001515 except QAPIError as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001516 print >>sys.stderr, err
1517 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001518
Markus Armbrusterac882192015-09-16 13:06:05 +02001519 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001520 # Only the predefined types are allowed to not have info
1521 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001522 assert ent.name not in self._entity_dict
1523 self._entity_dict[ent.name] = ent
1524
1525 def lookup_entity(self, name, typ=None):
1526 ent = self._entity_dict.get(name)
1527 if typ and not isinstance(ent, typ):
1528 return None
1529 return ent
1530
1531 def lookup_type(self, name):
1532 return self.lookup_entity(name, QAPISchemaType)
1533
Eric Blake861877a2016-03-17 16:48:36 -06001534 def _def_builtin_type(self, name, json_type, c_type):
1535 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001536 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1537 # qapi-types.h from a single .c, all arrays of builtins must be
1538 # declared in the first file whether or not they are used. Nicer
1539 # would be to use lazy instantiation, while figuring out how to
1540 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001541 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001542
1543 def _def_predefineds(self):
Eric Blake861877a2016-03-17 16:48:36 -06001544 for t in [('str', 'string', 'char' + pointer_suffix),
1545 ('number', 'number', 'double'),
1546 ('int', 'int', 'int64_t'),
1547 ('int8', 'int', 'int8_t'),
1548 ('int16', 'int', 'int16_t'),
1549 ('int32', 'int', 'int32_t'),
1550 ('int64', 'int', 'int64_t'),
1551 ('uint8', 'int', 'uint8_t'),
1552 ('uint16', 'int', 'uint16_t'),
1553 ('uint32', 'int', 'uint32_t'),
1554 ('uint64', 'int', 'uint64_t'),
1555 ('size', 'int', 'uint64_t'),
1556 ('bool', 'boolean', 'bool'),
1557 ('any', 'value', 'QObject' + pointer_suffix)]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001558 self._def_builtin_type(*t)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001559 self.the_empty_object_type = QAPISchemaObjectType(
1560 'q_empty', None, None, None, [], None)
Markus Armbruster39a18152015-09-16 13:06:28 +02001561 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001562 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1563 'qstring', 'qdict', 'qlist',
1564 'qfloat', 'qbool'])
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001565 self._def_entity(QAPISchemaEnumType('QType', None, None,
1566 qtype_values, 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001567
Eric Blake93bda4d2015-12-01 22:20:55 -07001568 def _make_enum_members(self, values):
1569 return [QAPISchemaMember(v) for v in values]
1570
Eric Blake99df5282015-10-12 22:22:32 -06001571 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001572 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001573 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001574 self._def_entity(QAPISchemaEnumType(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001575 name, info, None, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001576 return name
1577
Eric Blake99df5282015-10-12 22:22:32 -06001578 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001579 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001580 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001581 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001582 return name
1583
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001584 def _make_implicit_object_type(self, name, info, doc, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001585 if not members:
1586 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001587 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake75996972016-03-17 16:48:29 -06001588 name = 'q_obj_%s-%s' % (name, role)
Markus Armbrusterac882192015-09-16 13:06:05 +02001589 if not self.lookup_entity(name, QAPISchemaObjectType):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001590 self._def_entity(QAPISchemaObjectType(name, info, doc, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001591 members, None))
1592 return name
1593
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001594 def _def_enum_type(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001595 name = expr['enum']
1596 data = expr['data']
1597 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001598 self._def_entity(QAPISchemaEnumType(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001599 name, info, doc, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001600
Eric Blake99df5282015-10-12 22:22:32 -06001601 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001602 optional = False
1603 if name.startswith('*'):
1604 name = name[1:]
1605 optional = True
1606 if isinstance(typ, list):
1607 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001608 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001609 return QAPISchemaObjectTypeMember(name, typ, optional)
1610
Eric Blake99df5282015-10-12 22:22:32 -06001611 def _make_members(self, data, info):
1612 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001613 for (key, value) in data.iteritems()]
1614
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001615 def _def_struct_type(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001616 name = expr['struct']
1617 base = expr.get('base')
1618 data = expr['data']
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001619 self._def_entity(QAPISchemaObjectType(name, info, doc, base,
Eric Blake99df5282015-10-12 22:22:32 -06001620 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001621 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001622
1623 def _make_variant(self, case, typ):
1624 return QAPISchemaObjectTypeVariant(case, typ)
1625
Eric Blake99df5282015-10-12 22:22:32 -06001626 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001627 if isinstance(typ, list):
1628 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001629 typ = self._make_array_type(typ[0], info)
1630 typ = self._make_implicit_object_type(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001631 typ, info, None, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001632 return QAPISchemaObjectTypeVariant(case, typ)
1633
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001634 def _def_union_type(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001635 name = expr['union']
1636 data = expr['data']
1637 base = expr.get('base')
1638 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001639 tag_member = None
Eric Blakeac4338f2016-03-17 16:48:39 -06001640 if isinstance(base, dict):
1641 base = (self._make_implicit_object_type(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001642 name, info, doc, 'base', self._make_members(base, info)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001643 if tag_name:
1644 variants = [self._make_variant(key, value)
1645 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001646 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001647 else:
Eric Blake99df5282015-10-12 22:22:32 -06001648 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001649 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001650 typ = self._make_implicit_enum_type(name, info,
1651 [v.name for v in variants])
1652 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001653 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001654 self._def_entity(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001655 QAPISchemaObjectType(name, info, doc, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001656 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001657 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001658 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001659
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001660 def _def_alternate_type(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001661 name = expr['alternate']
1662 data = expr['data']
1663 variants = [self._make_variant(key, value)
1664 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001665 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001666 self._def_entity(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001667 QAPISchemaAlternateType(name, info, doc,
Markus Armbrusterac882192015-09-16 13:06:05 +02001668 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001669 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001670 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001671
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001672 def _def_command(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001673 name = expr['command']
1674 data = expr.get('data')
1675 rets = expr.get('returns')
1676 gen = expr.get('gen', True)
1677 success_response = expr.get('success-response', True)
Eric Blake48825ca2016-07-13 21:50:19 -06001678 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001679 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001680 data = self._make_implicit_object_type(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001681 name, info, doc, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001682 if isinstance(rets, list):
1683 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001684 rets = self._make_array_type(rets[0], info)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001685 self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
1686 gen, success_response, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001687
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001688 def _def_event(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001689 name = expr['event']
1690 data = expr.get('data')
Eric Blake48825ca2016-07-13 21:50:19 -06001691 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001692 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001693 data = self._make_implicit_object_type(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001694 name, info, doc, 'arg', self._make_members(data, info))
1695 self._def_entity(QAPISchemaEvent(name, info, doc, data, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001696
1697 def _def_exprs(self):
1698 for expr_elem in self.exprs:
1699 expr = expr_elem['expr']
1700 info = expr_elem['info']
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001701 doc = expr_elem.get('doc')
Markus Armbrusterac882192015-09-16 13:06:05 +02001702 if 'enum' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001703 self._def_enum_type(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001704 elif 'struct' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001705 self._def_struct_type(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001706 elif 'union' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001707 self._def_union_type(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001708 elif 'alternate' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001709 self._def_alternate_type(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001710 elif 'command' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001711 self._def_command(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001712 elif 'event' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001713 self._def_event(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001714 else:
1715 assert False
1716
1717 def check(self):
1718 for ent in self._entity_dict.values():
1719 ent.check(self)
1720
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001721 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001722 visitor.visit_begin(self)
1723 for (name, entity) in sorted(self._entity_dict.items()):
1724 if visitor.visit_needed(entity):
1725 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001726 visitor.visit_end()
1727
Markus Armbruster2caba362013-07-27 17:41:56 +02001728
Markus Armbruster00e4b282015-06-10 10:04:36 +02001729#
1730# Code generation helpers
1731#
1732
Michael Roth0f923be2011-07-19 14:50:39 -05001733def camel_case(name):
1734 new_name = ''
1735 first = True
1736 for ch in name:
1737 if ch in ['_', '-']:
1738 first = True
1739 elif first:
1740 new_name += ch.upper()
1741 first = False
1742 else:
1743 new_name += ch.lower()
1744 return new_name
1745
Eric Blake437db252015-09-29 16:21:02 -06001746
Markus Armbruster849bc532015-05-14 06:50:53 -06001747# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1748# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1749# ENUM24_Name -> ENUM24_NAME
1750def camel_to_upper(value):
1751 c_fun_str = c_name(value, False)
1752 if value.isupper():
1753 return c_fun_str
1754
1755 new_name = ''
1756 l = len(c_fun_str)
1757 for i in range(l):
1758 c = c_fun_str[i]
1759 # When c is upper and no "_" appears before, do more checks
1760 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001761 if i < l - 1 and c_fun_str[i + 1].islower():
1762 new_name += '_'
1763 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001764 new_name += '_'
1765 new_name += c
1766 return new_name.lstrip('_').upper()
1767
Eric Blake437db252015-09-29 16:21:02 -06001768
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001769def c_enum_const(type_name, const_name, prefix=None):
1770 if prefix is not None:
1771 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001772 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001773
Eric Blake18df5152015-05-14 06:50:48 -06001774c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001775
Eric Blake437db252015-09-29 16:21:02 -06001776
Eric Blakec6405b52015-05-14 06:50:55 -06001777# Map @name to a valid C identifier.
1778# If @protect, avoid returning certain ticklish identifiers (like
1779# C keywords) by prepending "q_".
1780#
1781# Used for converting 'name' from a 'name':'type' qapi definition
1782# into a generated struct member, as well as converting type names
1783# into substrings of a generated C function name.
1784# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1785# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001786def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001787 # ANSI X3J11/88-090, 3.1.1
1788 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001789 'default', 'do', 'double', 'else', 'enum', 'extern',
1790 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1791 'return', 'short', 'signed', 'sizeof', 'static',
1792 'struct', 'switch', 'typedef', 'union', 'unsigned',
1793 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001794 # ISO/IEC 9899:1999, 6.4.1
1795 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1796 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001797 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1798 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001799 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1800 # excluding _.*
1801 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001802 # C++ ISO/IEC 14882:2003 2.11
1803 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1804 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1805 'namespace', 'new', 'operator', 'private', 'protected',
1806 'public', 'reinterpret_cast', 'static_cast', 'template',
1807 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1808 'using', 'virtual', 'wchar_t',
1809 # alternative representations
1810 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1811 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001812 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001813 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001814 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001815 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1816 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001817 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001818 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001819
Amos Kong05dfb262014-06-10 19:25:53 +08001820eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001821pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001822
Eric Blake437db252015-09-29 16:21:02 -06001823
Michael Roth0f923be2011-07-19 14:50:39 -05001824def genindent(count):
1825 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001826 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001827 ret += " "
1828 return ret
1829
1830indent_level = 0
1831
Eric Blake437db252015-09-29 16:21:02 -06001832
Michael Roth0f923be2011-07-19 14:50:39 -05001833def push_indent(indent_amount=4):
1834 global indent_level
1835 indent_level += indent_amount
1836
Eric Blake437db252015-09-29 16:21:02 -06001837
Michael Roth0f923be2011-07-19 14:50:39 -05001838def pop_indent(indent_amount=4):
1839 global indent_level
1840 indent_level -= indent_amount
1841
Eric Blake437db252015-09-29 16:21:02 -06001842
Markus Armbruster77e703b2015-06-24 19:27:32 +02001843# Generate @code with @kwds interpolated.
1844# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001845def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001846 raw = code % kwds
1847 if indent_level:
1848 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001849 # re.subn() lacks flags support before Python 2.7, use re.compile()
1850 raw = re.subn(re.compile("^.", re.MULTILINE),
1851 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001852 raw = raw[0]
1853 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001854
Eric Blake437db252015-09-29 16:21:02 -06001855
Michael Roth0f923be2011-07-19 14:50:39 -05001856def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001857 if code[0] == '\n':
1858 code = code[1:]
1859 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001860
Michael Roth0f923be2011-07-19 14:50:39 -05001861
1862def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001863 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001864
Eric Blake437db252015-09-29 16:21:02 -06001865
Michael Rothc0afa9c2013-05-10 17:46:00 -05001866def guardstart(name):
1867 return mcgen('''
1868
1869#ifndef %(name)s
1870#define %(name)s
1871
1872''',
1873 name=guardname(name))
1874
Eric Blake437db252015-09-29 16:21:02 -06001875
Michael Rothc0afa9c2013-05-10 17:46:00 -05001876def guardend(name):
1877 return mcgen('''
1878
1879#endif /* %(name)s */
1880
1881''',
1882 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001883
Eric Blake437db252015-09-29 16:21:02 -06001884
Markus Armbrustere98859a2015-09-16 13:06:16 +02001885def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001886 ret = mcgen('''
1887
Markus Armbrustere98859a2015-09-16 13:06:16 +02001888const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001889''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001890 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001891 for value in values:
1892 index = c_enum_const(name, value, prefix)
1893 ret += mcgen('''
1894 [%(index)s] = "%(value)s",
1895''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001896 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001897
Eric Blake7fb1cf12015-11-18 01:52:57 -07001898 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001899 ret += mcgen('''
1900 [%(max_index)s] = NULL,
1901};
1902''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001903 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001904 return ret
1905
Eric Blake437db252015-09-29 16:21:02 -06001906
Markus Armbrustere98859a2015-09-16 13:06:16 +02001907def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001908 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001909 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001910
1911 ret = mcgen('''
1912
1913typedef enum %(c_name)s {
1914''',
1915 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001916
1917 i = 0
1918 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001919 ret += mcgen('''
1920 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001921''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001922 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001923 i=i)
1924 i += 1
1925
Markus Armbrustere98859a2015-09-16 13:06:16 +02001926 ret += mcgen('''
1927} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001928''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001929 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001930
Markus Armbrustere98859a2015-09-16 13:06:16 +02001931 ret += mcgen('''
1932
1933extern const char *const %(c_name)s_lookup[];
1934''',
1935 c_name=c_name(name))
1936 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001937
Eric Blake437db252015-09-29 16:21:02 -06001938
Eric Blake48825ca2016-07-13 21:50:19 -06001939def gen_params(arg_type, boxed, extra):
Markus Armbruster03b43672015-09-16 13:06:20 +02001940 if not arg_type:
Eric Blakec8184082016-07-13 21:50:20 -06001941 assert not boxed
Markus Armbruster03b43672015-09-16 13:06:20 +02001942 return extra
Markus Armbruster03b43672015-09-16 13:06:20 +02001943 ret = ''
1944 sep = ''
Eric Blake48825ca2016-07-13 21:50:19 -06001945 if boxed:
Eric Blakec8184082016-07-13 21:50:20 -06001946 ret += '%s arg' % arg_type.c_param_type()
1947 sep = ', '
Eric Blake48825ca2016-07-13 21:50:19 -06001948 else:
1949 assert not arg_type.variants
1950 for memb in arg_type.members:
1951 ret += sep
1952 sep = ', '
1953 if memb.optional:
1954 ret += 'bool has_%s, ' % c_name(memb.name)
1955 ret += '%s %s' % (memb.type.c_param_type(),
1956 c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001957 if extra:
1958 ret += sep + extra
1959 return ret
1960
Eric Blake1f353342015-09-29 16:21:13 -06001961
Markus Armbruster00e4b282015-06-10 10:04:36 +02001962#
1963# Common command line parsing
1964#
1965
Eric Blake437db252015-09-29 16:21:02 -06001966
1967def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001968
1969 try:
1970 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001971 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001972 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001973 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001974 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001975 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001976 sys.exit(1)
1977
1978 output_dir = ""
1979 prefix = ""
1980 do_c = False
1981 do_h = False
1982 extra_opts = []
1983
1984 for oa in opts:
1985 o, a = oa
1986 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001987 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1988 if match.end() != len(a):
1989 print >>sys.stderr, \
1990 "%s: 'funny character '%s' in argument of --prefix" \
1991 % (sys.argv[0], a[match.end()])
1992 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001993 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001994 elif o in ("-o", "--output-dir"):
1995 output_dir = a + "/"
1996 elif o in ("-c", "--source"):
1997 do_c = True
1998 elif o in ("-h", "--header"):
1999 do_h = True
2000 else:
2001 extra_opts.append(oa)
2002
2003 if not do_c and not do_h:
2004 do_c = True
2005 do_h = True
2006
Markus Armbruster16d80f62015-04-02 13:32:16 +02002007 if len(args) != 1:
2008 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02002009 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02002010 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02002011
Markus Armbruster54414042015-06-09 16:22:45 +02002012 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002013
Markus Armbruster00e4b282015-06-10 10:04:36 +02002014#
2015# Generate output files with boilerplate
2016#
2017
Eric Blake437db252015-09-29 16:21:02 -06002018
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002019def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
2020 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02002021 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002022 c_file = output_dir + prefix + c_file
2023 h_file = output_dir + prefix + h_file
2024
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02002025 if output_dir:
2026 try:
2027 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01002028 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02002029 if e.errno != errno.EEXIST:
2030 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002031
2032 def maybe_open(really, name, opt):
2033 if really:
2034 return open(name, opt)
2035 else:
2036 import StringIO
2037 return StringIO.StringIO()
2038
2039 fdef = maybe_open(do_c, c_file, 'w')
2040 fdecl = maybe_open(do_h, h_file, 'w')
2041
2042 fdef.write(mcgen('''
2043/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2044%(comment)s
2045''',
Eric Blake437db252015-09-29 16:21:02 -06002046 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002047
2048 fdecl.write(mcgen('''
2049/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2050%(comment)s
2051#ifndef %(guard)s
2052#define %(guard)s
2053
2054''',
Eric Blake437db252015-09-29 16:21:02 -06002055 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002056
2057 return (fdef, fdecl)
2058
Eric Blake437db252015-09-29 16:21:02 -06002059
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002060def close_output(fdef, fdecl):
2061 fdecl.write('''
2062#endif
2063''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002064 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002065 fdef.close()