blob: 78db319831c802fd3610d36faeee656e8905fa08 [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 = []
110
111 def append(self, line):
112 self.content.append(line)
113
114 def __repr__(self):
115 return "\n".join(self.content).strip()
116
117 class ArgSection(Section):
118 pass
119
120 def __init__(self, parser, info):
121 # self.parser is used to report errors with QAPIParseError. The
122 # resulting error position depends on the state of the parser.
123 # It happens to be the beginning of the comment. More or less
124 # servicable, but action at a distance.
125 self.parser = parser
126 self.info = info
127 self.symbol = None
128 self.body = QAPIDoc.Section()
129 # dict mapping parameter name to ArgSection
130 self.args = OrderedDict()
131 # a list of Section
132 self.sections = []
133 # the current section
134 self.section = self.body
135 # associated expression (to be set by expression parser)
136 self.expr = None
137
138 def has_section(self, name):
139 """Return True if we have a section with this name."""
140 for i in self.sections:
141 if i.name == name:
142 return True
143 return False
144
145 def append(self, line):
146 """Parse a comment line and add it to the documentation."""
147 line = line[1:]
148 if not line:
149 self._append_freeform(line)
150 return
151
152 if line[0] != ' ':
153 raise QAPIParseError(self.parser, "Missing space after #")
154 line = line[1:]
155
156 # FIXME not nice: things like '# @foo:' and '# @foo: ' aren't
157 # recognized, and get silently treated as ordinary text
158 if self.symbol:
159 self._append_symbol_line(line)
160 elif not self.body.content and line.startswith("@"):
161 if not line.endswith(":"):
162 raise QAPIParseError(self.parser, "Line should end with :")
163 self.symbol = line[1:-1]
164 # FIXME invalid names other than the empty string aren't flagged
165 if not self.symbol:
166 raise QAPIParseError(self.parser, "Invalid name")
167 else:
168 self._append_freeform(line)
169
170 def _append_symbol_line(self, line):
171 name = line.split(' ', 1)[0]
172
173 if name.startswith("@") and name.endswith(":"):
174 line = line[len(name)+1:]
175 self._start_args_section(name[1:-1])
176 elif name in ("Returns:", "Since:",
177 # those are often singular or plural
178 "Note:", "Notes:",
179 "Example:", "Examples:",
180 "TODO:"):
181 line = line[len(name)+1:]
182 self._start_section(name[:-1])
183
184 self._append_freeform(line)
185
186 def _start_args_section(self, name):
187 # FIXME invalid names other than the empty string aren't flagged
188 if not name:
189 raise QAPIParseError(self.parser, "Invalid parameter name")
190 if name in self.args:
191 raise QAPIParseError(self.parser,
192 "'%s' parameter name duplicated" % name)
193 if self.sections:
194 raise QAPIParseError(self.parser,
195 "'@%s:' can't follow '%s' section"
196 % (name, self.sections[0].name))
197 self.section = QAPIDoc.ArgSection(name)
198 self.args[name] = self.section
199
200 def _start_section(self, name=""):
201 if name in ("Returns", "Since") and self.has_section(name):
202 raise QAPIParseError(self.parser,
203 "Duplicated '%s' section" % name)
204 self.section = QAPIDoc.Section(name)
205 self.sections.append(self.section)
206
207 def _append_freeform(self, line):
208 in_arg = isinstance(self.section, QAPIDoc.ArgSection)
209 if (in_arg and self.section.content
210 and not self.section.content[-1]
211 and line and not line[0].isspace()):
212 self._start_section()
213 if (in_arg or not self.section.name
214 or not self.section.name.startswith("Example")):
215 line = line.strip()
216 self.section.append(line)
217
218
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200219class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500220
Eric Blake437db252015-09-29 16:21:02 -0600221 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200222 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200223 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200224 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200225 previously_included.append(abs_fname)
226 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200227 self.src = fp.read()
228 if self.src == '' or self.src[-1] != '\n':
229 self.src += '\n'
230 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800231 self.line = 1
232 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200233 self.exprs = []
Marc-André Lureau3313b612017-01-13 15:41:29 +0100234 self.docs = []
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200235 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500236
Eric Blake437db252015-09-29 16:21:02 -0600237 while self.tok is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100238 info = {'file': fname, 'line': self.line,
239 'parent': self.incl_info}
Marc-André Lureau3313b612017-01-13 15:41:29 +0100240 if self.tok == '#':
241 doc = self.get_doc(info)
242 self.docs.append(doc)
243 continue
244
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200245 expr = self.get_expr(False)
Markus Armbrustere04dea82017-03-15 13:56:50 +0100246 if 'include' in expr:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200247 if len(expr) != 1:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100248 raise QAPISemError(info, "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200249 include = expr["include"]
250 if not isinstance(include, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100251 raise QAPISemError(info,
252 "Value of 'include' must be a string")
Markus Armbrustere04dea82017-03-15 13:56:50 +0100253 self._include(include, info, os.path.dirname(abs_fname),
254 previously_included)
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100255 elif "pragma" in expr:
256 if len(expr) != 1:
257 raise QAPISemError(info, "Invalid 'pragma' directive")
258 pragma = expr['pragma']
259 if not isinstance(pragma, dict):
260 raise QAPISemError(
261 info, "Value of 'pragma' must be a dictionary")
262 for name, value in pragma.iteritems():
263 self._pragma(name, value, info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200264 else:
265 expr_elem = {'expr': expr,
Marc-André Lureau4148c292017-01-13 15:41:25 +0100266 'info': info}
Marc-André Lureau3313b612017-01-13 15:41:29 +0100267 if (self.docs
268 and self.docs[-1].info['file'] == fname
269 and not self.docs[-1].expr):
270 self.docs[-1].expr = expr
271 expr_elem['doc'] = self.docs[-1]
272
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200273 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500274
Markus Armbrustere04dea82017-03-15 13:56:50 +0100275 def _include(self, include, info, base_dir, previously_included):
276 incl_abs_fname = os.path.join(base_dir, include)
277 # catch inclusion cycle
278 inf = info
279 while inf:
280 if incl_abs_fname == os.path.abspath(inf['file']):
281 raise QAPISemError(info, "Inclusion loop for %s" % include)
282 inf = inf['parent']
283
284 # skip multiple include of the same file
285 if incl_abs_fname in previously_included:
286 return
287 try:
288 fobj = open(incl_abs_fname, 'r')
289 except IOError as e:
290 raise QAPISemError(info, '%s: %s' % (e.strerror, include))
291 exprs_include = QAPISchemaParser(fobj, previously_included, info)
292 self.exprs.extend(exprs_include.exprs)
293 self.docs.extend(exprs_include.docs)
294
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100295 def _pragma(self, name, value, info):
Markus Armbruster2cfbae32017-03-15 13:56:55 +0100296 global doc_required, returns_whitelist, name_case_whitelist
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100297 if name == 'doc-required':
298 if not isinstance(value, bool):
299 raise QAPISemError(info,
300 "Pragma 'doc-required' must be boolean")
301 doc_required = value
Markus Armbruster1554a8f2017-03-15 13:56:54 +0100302 elif name == 'returns-whitelist':
303 if (not isinstance(value, list)
304 or any([not isinstance(elt, str) for elt in value])):
305 raise QAPISemError(info,
306 "Pragma returns-whitelist must be"
307 " a list of strings")
308 returns_whitelist = value
Markus Armbruster2cfbae32017-03-15 13:56:55 +0100309 elif name == 'name-case-whitelist':
310 if (not isinstance(value, list)
311 or any([not isinstance(elt, str) for elt in value])):
312 raise QAPISemError(info,
313 "Pragma name-case-whitelist must be"
314 " a list of strings")
315 name_case_whitelist = value
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100316 else:
317 raise QAPISemError(info, "Unknown pragma '%s'" % name)
318
Marc-André Lureau3313b612017-01-13 15:41:29 +0100319 def accept(self, skip_comment=True):
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200320 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200321 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200322 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200323 self.cursor += 1
324 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500325
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200326 if self.tok == '#':
Marc-André Lureau3313b612017-01-13 15:41:29 +0100327 if self.src[self.cursor] == '#':
328 # Start of doc comment
329 skip_comment = False
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200330 self.cursor = self.src.find('\n', self.cursor)
Marc-André Lureau3313b612017-01-13 15:41:29 +0100331 if not skip_comment:
332 self.val = self.src[self.pos:self.cursor]
333 return
Eric Blake8712fa52015-10-26 16:34:41 -0600334 elif self.tok in "{}:,[]":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200335 return
336 elif self.tok == "'":
337 string = ''
338 esc = False
339 while True:
340 ch = self.src[self.cursor]
341 self.cursor += 1
342 if ch == '\n':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100343 raise QAPIParseError(self, 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200344 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600345 if ch == 'b':
346 string += '\b'
347 elif ch == 'f':
348 string += '\f'
349 elif ch == 'n':
350 string += '\n'
351 elif ch == 'r':
352 string += '\r'
353 elif ch == 't':
354 string += '\t'
355 elif ch == 'u':
356 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600357 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600358 ch = self.src[self.cursor]
359 self.cursor += 1
360 if ch not in "0123456789abcdefABCDEF":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100361 raise QAPIParseError(self,
362 '\\u escape needs 4 '
363 'hex digits')
Eric Blakea7f59662015-05-04 09:05:36 -0600364 value = (value << 4) + int(ch, 16)
365 # If Python 2 and 3 didn't disagree so much on
366 # how to handle Unicode, then we could allow
367 # Unicode string defaults. But most of QAPI is
368 # ASCII-only, so we aren't losing much for now.
369 if not value or value > 0x7f:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100370 raise QAPIParseError(self,
371 'For now, \\u escape '
372 'only supports non-zero '
373 'values up to \\u007f')
Eric Blakea7f59662015-05-04 09:05:36 -0600374 string += chr(value)
375 elif ch in "\\/'\"":
376 string += ch
377 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100378 raise QAPIParseError(self,
379 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200380 esc = False
381 elif ch == "\\":
382 esc = True
383 elif ch == "'":
384 self.val = string
385 return
386 else:
387 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200388 elif self.src.startswith("true", self.pos):
389 self.val = True
390 self.cursor += 3
391 return
392 elif self.src.startswith("false", self.pos):
393 self.val = False
394 self.cursor += 4
395 return
396 elif self.src.startswith("null", self.pos):
397 self.val = None
398 self.cursor += 3
399 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200400 elif self.tok == '\n':
401 if self.cursor == len(self.src):
402 self.tok = None
403 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800404 self.line += 1
405 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200406 elif not self.tok.isspace():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100407 raise QAPIParseError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500408
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200409 def get_members(self):
410 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200411 if self.tok == '}':
412 self.accept()
413 return expr
414 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100415 raise QAPIParseError(self, 'Expected string or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200416 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200417 key = self.val
418 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200419 if self.tok != ':':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100420 raise QAPIParseError(self, 'Expected ":"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200421 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800422 if key in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100423 raise QAPIParseError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200424 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200425 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200426 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200427 return expr
428 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100429 raise QAPIParseError(self, 'Expected "," or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200430 self.accept()
431 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100432 raise QAPIParseError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500433
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200434 def get_values(self):
435 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200436 if self.tok == ']':
437 self.accept()
438 return expr
Eric Blake437db252015-09-29 16:21:02 -0600439 if self.tok not in "{['tfn":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100440 raise QAPIParseError(self, 'Expected "{", "[", "]", string, '
441 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200442 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200443 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200444 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200445 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200446 return expr
447 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100448 raise QAPIParseError(self, 'Expected "," or "]"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200449 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500450
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200451 def get_expr(self, nested):
452 if self.tok != '{' and not nested:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100453 raise QAPIParseError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200454 if self.tok == '{':
455 self.accept()
456 expr = self.get_members()
457 elif self.tok == '[':
458 self.accept()
459 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600460 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200461 expr = self.val
462 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200463 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100464 raise QAPIParseError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200465 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200466
Marc-André Lureau3313b612017-01-13 15:41:29 +0100467 def get_doc(self, info):
468 if self.val != '##':
469 raise QAPIParseError(self, "Junk after '##' at start of "
470 "documentation comment")
471
472 doc = QAPIDoc(self, info)
473 self.accept(False)
474 while self.tok == '#':
475 if self.val.startswith('##'):
476 # End of doc comment
477 if self.val != '##':
478 raise QAPIParseError(self, "Junk after '##' at end of "
479 "documentation comment")
480 self.accept()
481 return doc
482 else:
483 doc.append(self.val)
484 self.accept(False)
485
486 raise QAPIParseError(self, "Documentation comment must end with '##'")
487
488
Markus Armbruster00e4b282015-06-10 10:04:36 +0200489#
490# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200491# TODO fold into QAPISchema
492# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200493#
494
Eric Blake437db252015-09-29 16:21:02 -0600495
Eric Blake14f00c62016-03-03 09:16:43 -0700496def find_base_members(base):
Eric Blakeac4338f2016-03-17 16:48:39 -0600497 if isinstance(base, dict):
498 return base
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800499 base_struct_define = find_struct(base)
500 if not base_struct_define:
501 return None
502 return base_struct_define['data']
503
Eric Blake437db252015-09-29 16:21:02 -0600504
Eric Blake811d04f2015-05-04 09:05:10 -0600505# Return the qtype of an alternate branch, or None on error.
506def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600507 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600508 return builtin_types[qapi_type]
509 elif find_struct(qapi_type):
510 return "QTYPE_QDICT"
511 elif find_enum(qapi_type):
512 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600513 elif find_union(qapi_type):
514 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600515 return None
516
Eric Blake437db252015-09-29 16:21:02 -0600517
Wenchao Xiabceae762014-03-06 17:08:56 -0800518# Return the discriminator enum define if discriminator is specified as an
519# enum type, otherwise return None.
520def discriminator_find_enum_define(expr):
521 base = expr.get('base')
522 discriminator = expr.get('discriminator')
523
524 if not (discriminator and base):
525 return None
526
Eric Blake14f00c62016-03-03 09:16:43 -0700527 base_members = find_base_members(base)
528 if not base_members:
Wenchao Xiabceae762014-03-06 17:08:56 -0800529 return None
530
Eric Blake14f00c62016-03-03 09:16:43 -0700531 discriminator_type = base_members.get(discriminator)
Wenchao Xiabceae762014-03-06 17:08:56 -0800532 if not discriminator_type:
533 return None
534
535 return find_enum(discriminator_type)
536
Eric Blake437db252015-09-29 16:21:02 -0600537
Eric Blake59a92fe2015-11-18 01:52:56 -0700538# Names must be letters, numbers, -, and _. They must start with letter,
539# except for downstream extensions which must start with __RFQDN_.
540# Dots are only valid in the downstream extension prefix.
541valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
542 '[a-zA-Z][a-zA-Z0-9_-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600543
544
Marc-André Lureau4148c292017-01-13 15:41:25 +0100545def check_name(info, source, name, allow_optional=False,
Eric Blake437db252015-09-29 16:21:02 -0600546 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600547 global valid_name
548 membername = name
549
550 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100551 raise QAPISemError(info, "%s requires a string name" % source)
Eric Blakec9e0a792015-05-04 09:05:22 -0600552 if name.startswith('*'):
553 membername = name[1:]
554 if not allow_optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100555 raise QAPISemError(info, "%s does not allow optional name '%s'"
556 % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600557 # Enum members can start with a digit, because the generated C
558 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700559 if enum_member and membername[0].isdigit():
560 membername = 'D' + membername
Eric Blake75996972016-03-17 16:48:29 -0600561 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
562 # and 'q_obj_*' implicit type names.
Eric Blake9fb081e2015-10-26 16:34:44 -0600563 if not valid_name.match(membername) or \
564 c_name(membername, False).startswith('q_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100565 raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600566
Eric Blake437db252015-09-29 16:21:02 -0600567
568def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200569 global all_names
570 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200571 # FIXME should reject names that differ only in '_' vs. '.'
572 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200573 if name in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100574 raise QAPISemError(info, "%s '%s' is already defined"
575 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600576 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100577 raise QAPISemError(info, "%s '%s' should not end in '%s'"
578 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200579 all_names[name] = meta
580
Eric Blake437db252015-09-29 16:21:02 -0600581
Markus Armbruster00e4b282015-06-10 10:04:36 +0200582def add_struct(definition, info):
583 global struct_types
584 name = definition['struct']
585 add_name(name, info, 'struct')
586 struct_types.append(definition)
587
Eric Blake437db252015-09-29 16:21:02 -0600588
Markus Armbruster00e4b282015-06-10 10:04:36 +0200589def find_struct(name):
590 global struct_types
591 for struct in struct_types:
592 if struct['struct'] == name:
593 return struct
594 return None
595
Eric Blake437db252015-09-29 16:21:02 -0600596
Markus Armbruster00e4b282015-06-10 10:04:36 +0200597def add_union(definition, info):
598 global union_types
599 name = definition['union']
600 add_name(name, info, 'union')
601 union_types.append(definition)
602
Eric Blake437db252015-09-29 16:21:02 -0600603
Markus Armbruster00e4b282015-06-10 10:04:36 +0200604def find_union(name):
605 global union_types
606 for union in union_types:
607 if union['union'] == name:
608 return union
609 return None
610
Eric Blake437db252015-09-29 16:21:02 -0600611
612def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200613 global enum_types
614 add_name(name, info, 'enum', implicit)
615 enum_types.append({"enum_name": name, "enum_values": enum_values})
616
Eric Blake437db252015-09-29 16:21:02 -0600617
Markus Armbruster00e4b282015-06-10 10:04:36 +0200618def find_enum(name):
619 global enum_types
620 for enum in enum_types:
621 if enum['enum_name'] == name:
622 return enum
623 return None
624
Markus Armbruster00e4b282015-06-10 10:04:36 +0200625
Eric Blake437db252015-09-29 16:21:02 -0600626def is_enum(name):
627 return find_enum(name) is not None
628
629
Marc-André Lureau4148c292017-01-13 15:41:25 +0100630def check_type(info, source, value, allow_array=False,
Eric Blake437db252015-09-29 16:21:02 -0600631 allow_dict=False, allow_optional=False,
632 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600633 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600634
635 if value is None:
636 return
637
Eric Blakedd883c62015-05-04 09:05:21 -0600638 # Check if array type for value is okay
639 if isinstance(value, list):
640 if not allow_array:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100641 raise QAPISemError(info, "%s cannot be an array" % source)
Eric Blakedd883c62015-05-04 09:05:21 -0600642 if len(value) != 1 or not isinstance(value[0], str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100643 raise QAPISemError(info,
644 "%s: array type must contain single type name" %
645 source)
Eric Blakedd883c62015-05-04 09:05:21 -0600646 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600647
648 # Check if type name for value is okay
649 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600650 if value not in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100651 raise QAPISemError(info, "%s uses unknown type '%s'"
652 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600653 if not all_names[value] in allow_metas:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100654 raise QAPISemError(info, "%s cannot use %s type '%s'" %
655 (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600656 return
657
Eric Blakedd883c62015-05-04 09:05:21 -0600658 if not allow_dict:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100659 raise QAPISemError(info, "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200660
661 if not isinstance(value, OrderedDict):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100662 raise QAPISemError(info,
663 "%s should be a dictionary or type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200664
665 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600666 for (key, arg) in value.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100667 check_name(info, "Member of %s" % source, key,
Eric Blakec9e0a792015-05-04 09:05:22 -0600668 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600669 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100670 raise QAPISemError(info, "Member of %s uses reserved name '%s'"
671 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600672 # Todo: allow dictionaries to represent default values of
673 # an optional argument.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100674 check_type(info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200675 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600676 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600677 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600678
Eric Blake437db252015-09-29 16:21:02 -0600679
Marc-André Lureau4148c292017-01-13 15:41:25 +0100680def check_command(expr, info):
Eric Blakedd883c62015-05-04 09:05:21 -0600681 name = expr['command']
Eric Blakec8184082016-07-13 21:50:20 -0600682 boxed = expr.get('boxed', False)
Eric Blake2cbf0992015-05-04 09:05:24 -0600683
Eric Blakec8184082016-07-13 21:50:20 -0600684 args_meta = ['struct']
685 if boxed:
686 args_meta += ['union', 'alternate']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100687 check_type(info, "'data' for command '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600688 expr.get('data'), allow_dict=not boxed, allow_optional=True,
689 allow_metas=args_meta)
Eric Blake10d4d992015-05-04 09:05:23 -0600690 returns_meta = ['union', 'struct']
691 if name in returns_whitelist:
692 returns_meta += ['built-in', 'alternate', 'enum']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100693 check_type(info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200694 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200695 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600696
Eric Blake437db252015-09-29 16:21:02 -0600697
Marc-André Lureau4148c292017-01-13 15:41:25 +0100698def check_event(expr, info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600699 global events
700 name = expr['event']
Eric Blakec8184082016-07-13 21:50:20 -0600701 boxed = expr.get('boxed', False)
Eric Blake4dc2e692015-05-04 09:05:17 -0600702
Eric Blakec8184082016-07-13 21:50:20 -0600703 meta = ['struct']
704 if boxed:
705 meta += ['union', 'alternate']
Eric Blake4dc2e692015-05-04 09:05:17 -0600706 events.append(name)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100707 check_type(info, "'data' for event '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600708 expr.get('data'), allow_dict=not boxed, allow_optional=True,
709 allow_metas=meta)
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200710
Eric Blake437db252015-09-29 16:21:02 -0600711
Marc-André Lureau4148c292017-01-13 15:41:25 +0100712def check_union(expr, info):
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800713 name = expr['union']
714 base = expr.get('base')
715 discriminator = expr.get('discriminator')
716 members = expr['data']
717
Eric Blake811d04f2015-05-04 09:05:10 -0600718 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600719
720 # With no discriminator it is a simple union.
721 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600722 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600723 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600724 if base is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100725 raise QAPISemError(info, "Simple union '%s' must not have a base" %
726 name)
Eric Blake44bd1272015-05-04 09:05:08 -0600727
728 # Else, it's a flat union.
729 else:
Eric Blakeac4338f2016-03-17 16:48:39 -0600730 # The object must have a string or dictionary 'base'.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100731 check_type(info, "'base' for union '%s'" % name,
Eric Blakeac4338f2016-03-17 16:48:39 -0600732 base, allow_dict=True, allow_optional=True,
733 allow_metas=['struct'])
Eric Blake376863e2015-09-29 16:21:07 -0600734 if not base:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100735 raise QAPISemError(info, "Flat union '%s' must have a base"
736 % name)
Eric Blake14f00c62016-03-03 09:16:43 -0700737 base_members = find_base_members(base)
738 assert base_members
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800739
Eric Blakec9e0a792015-05-04 09:05:22 -0600740 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600741 # member of the base struct.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100742 check_name(info, "Discriminator of flat union '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600743 discriminator)
Eric Blake14f00c62016-03-03 09:16:43 -0700744 discriminator_type = base_members.get(discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800745 if not discriminator_type:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100746 raise QAPISemError(info,
747 "Discriminator '%s' is not a member of base "
748 "struct '%s'"
749 % (discriminator, base))
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800750 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600751 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800752 # Do not allow string discriminator
753 if not enum_define:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100754 raise QAPISemError(info,
755 "Discriminator '%s' must be of enumeration "
756 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800757
Eric Blake02a57ae2016-02-17 23:48:16 -0700758 # Check every branch; don't allow an empty union
759 if len(members) == 0:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100760 raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800761 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100762 check_name(info, "Member of union '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600763
Eric Blake01cfbaa2015-12-01 22:20:58 -0700764 # Each value must name a known type
Marc-André Lureau4148c292017-01-13 15:41:25 +0100765 check_type(info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200766 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600767
Eric Blake44bd1272015-05-04 09:05:08 -0600768 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700769 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600770 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600771 if key not in enum_define['enum_values']:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100772 raise QAPISemError(info,
773 "Discriminator value '%s' is not found in "
774 "enum '%s'"
775 % (key, enum_define["enum_name"]))
Eric Blake44bd1272015-05-04 09:05:08 -0600776
Eric Blaked0b18232016-07-13 21:50:13 -0600777 # If discriminator is user-defined, ensure all values are covered
778 if enum_define:
779 for value in enum_define['enum_values']:
780 if value not in members.keys():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100781 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
782 % (name, value))
Eric Blaked0b18232016-07-13 21:50:13 -0600783
Eric Blake437db252015-09-29 16:21:02 -0600784
Marc-André Lureau4148c292017-01-13 15:41:25 +0100785def check_alternate(expr, info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600786 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600787 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600788 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600789
Eric Blake02a57ae2016-02-17 23:48:16 -0700790 # Check every branch; require at least two branches
791 if len(members) < 2:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100792 raise QAPISemError(info,
793 "Alternate '%s' should have at least two branches "
794 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600795 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100796 check_name(info, "Member of alternate '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600797
Eric Blake811d04f2015-05-04 09:05:10 -0600798 # Ensure alternates have no type conflicts.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100799 check_type(info, "Member '%s' of alternate '%s'" % (key, name),
Eric Blakedd883c62015-05-04 09:05:21 -0600800 value,
801 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600802 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700803 if not qtype:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100804 raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
805 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600806 if qtype in types_seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100807 raise QAPISemError(info, "Alternate '%s' member '%s' can't "
808 "be distinguished from member '%s'"
809 % (name, key, types_seen[qtype]))
Eric Blake811d04f2015-05-04 09:05:10 -0600810 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800811
Eric Blake437db252015-09-29 16:21:02 -0600812
Marc-André Lureau4148c292017-01-13 15:41:25 +0100813def check_enum(expr, info):
Eric Blakecf393592015-05-04 09:05:04 -0600814 name = expr['enum']
815 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100816 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600817
818 if not isinstance(members, list):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100819 raise QAPISemError(info,
820 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100821 if prefix is not None and not isinstance(prefix, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100822 raise QAPISemError(info,
823 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600824 for member in members:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100825 check_name(info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600826 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600827
Eric Blake437db252015-09-29 16:21:02 -0600828
Marc-André Lureau4148c292017-01-13 15:41:25 +0100829def check_struct(expr, info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600830 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600831 members = expr['data']
832
Marc-André Lureau4148c292017-01-13 15:41:25 +0100833 check_type(info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600834 allow_dict=True, allow_optional=True)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100835 check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600836 allow_metas=['struct'])
837
Eric Blake437db252015-09-29 16:21:02 -0600838
Eric Blake0545f6b2015-05-04 09:05:15 -0600839def check_keys(expr_elem, meta, required, optional=[]):
840 expr = expr_elem['expr']
841 info = expr_elem['info']
842 name = expr[meta]
843 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100844 raise QAPISemError(info, "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600845 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600846 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600847 if key not in required and key not in optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100848 raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
849 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600850 if (key == 'gen' or key == 'success-response') and value is not False:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100851 raise QAPISemError(info,
852 "'%s' of %s '%s' should only use false value"
853 % (key, meta, name))
Eric Blakec8184082016-07-13 21:50:20 -0600854 if key == 'boxed' and value is not True:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100855 raise QAPISemError(info,
856 "'%s' of %s '%s' should only use true value"
857 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600858 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600859 if key not in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100860 raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
861 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600862
Eric Blake437db252015-09-29 16:21:02 -0600863
Markus Armbruster4d076d62015-06-10 08:55:21 +0200864def check_exprs(exprs):
865 global all_names
866
867 # Learn the types and check for valid expression keys
868 for builtin in builtin_types.keys():
869 all_names[builtin] = 'built-in'
870 for expr_elem in exprs:
871 expr = expr_elem['expr']
872 info = expr_elem['info']
Marc-André Lureau3313b612017-01-13 15:41:29 +0100873
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100874 if 'doc' not in expr_elem and doc_required:
Marc-André Lureau3313b612017-01-13 15:41:29 +0100875 raise QAPISemError(info,
876 "Expression missing documentation comment")
877
Eric Blake437db252015-09-29 16:21:02 -0600878 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100879 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200880 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600881 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200882 check_keys(expr_elem, 'union', ['data'],
883 ['base', 'discriminator'])
884 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600885 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200886 check_keys(expr_elem, 'alternate', ['data'])
887 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600888 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200889 check_keys(expr_elem, 'struct', ['data'], ['base'])
890 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600891 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200892 check_keys(expr_elem, 'command', [],
Eric Blakec8184082016-07-13 21:50:20 -0600893 ['data', 'returns', 'gen', 'success-response', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200894 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600895 elif 'event' in expr:
Eric Blakec8184082016-07-13 21:50:20 -0600896 check_keys(expr_elem, 'event', [], ['data', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200897 add_name(expr['event'], info, 'event')
898 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100899 raise QAPISemError(expr_elem['info'],
900 "Expression is missing metatype")
Markus Armbruster4d076d62015-06-10 08:55:21 +0200901
902 # Try again for hidden UnionKind enum
903 for expr_elem in exprs:
904 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600905 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200906 if not discriminator_find_enum_define(expr):
907 add_enum('%sKind' % expr['union'], expr_elem['info'],
908 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600909 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200910 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
911 implicit=True)
912
913 # Validate that exprs make sense
914 for expr_elem in exprs:
915 expr = expr_elem['expr']
916 info = expr_elem['info']
917
Eric Blake437db252015-09-29 16:21:02 -0600918 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200919 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600920 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200921 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600922 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200923 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600924 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200925 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600926 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200927 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600928 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200929 check_event(expr, info)
930 else:
931 assert False, 'unexpected meta type'
932
Markus Armbrusterac882192015-09-16 13:06:05 +0200933 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600934
Markus Armbrusterac882192015-09-16 13:06:05 +0200935
Marc-André Lureau3313b612017-01-13 15:41:29 +0100936def check_freeform_doc(doc):
937 if doc.symbol:
938 raise QAPISemError(doc.info,
939 "Documention for '%s' is not followed"
940 " by the definition" % doc.symbol)
941
942 body = str(doc.body)
943 if re.search(r'@\S+:', body, re.MULTILINE):
944 raise QAPISemError(doc.info,
945 "Free-form documentation block must not contain"
946 " @NAME: sections")
947
948
949def check_definition_doc(doc, expr, info):
950 for i in ('enum', 'union', 'alternate', 'struct', 'command', 'event'):
951 if i in expr:
952 meta = i
953 break
954
955 name = expr[meta]
956 if doc.symbol != name:
957 raise QAPISemError(info, "Definition of '%s' follows documentation"
958 " for '%s'" % (name, doc.symbol))
959 if doc.has_section('Returns') and 'command' not in expr:
960 raise QAPISemError(info, "'Returns:' is only valid for commands")
961
962 if meta == 'union':
963 args = expr.get('base', [])
964 else:
965 args = expr.get('data', [])
966 if isinstance(args, str):
967 return
968 if isinstance(args, dict):
969 args = args.keys()
970 assert isinstance(args, list)
971
972 if (meta == 'alternate'
973 or (meta == 'union' and not expr.get('discriminator'))):
974 args.append('type')
975
976 for arg in args:
977 if arg[0] == '*':
978 opt = True
979 desc = doc.args.get(arg[1:])
980 else:
981 opt = False
982 desc = doc.args.get(arg)
983 if not desc:
984 continue
985 desc_opt = "#optional" in str(desc)
986 if desc_opt and not opt:
987 raise QAPISemError(info, "Description has #optional, "
988 "but the declaration doesn't")
989 if not desc_opt and opt:
990 # silently fix the doc
991 # TODO either fix the schema and make this an error,
992 # or drop #optional entirely
993 desc.append("#optional")
994
995 doc_args = set(doc.args.keys())
996 args = set([name.strip('*') for name in args])
997 if not doc_args.issubset(args):
998 raise QAPISemError(info, "The following documented members are not in "
999 "the declaration: %s" % ", ".join(doc_args - args))
1000
1001
1002def check_docs(docs):
1003 for doc in docs:
1004 for section in doc.args.values() + doc.sections:
1005 content = str(section)
1006 if not content or content.isspace():
1007 raise QAPISemError(doc.info,
1008 "Empty doc section '%s'" % section.name)
1009
1010 if not doc.expr:
1011 check_freeform_doc(doc)
1012 else:
1013 check_definition_doc(doc, doc.expr, doc.info)
1014
1015 return docs
1016
1017
Markus Armbrusterac882192015-09-16 13:06:05 +02001018#
1019# Schema compiler frontend
1020#
1021
1022class QAPISchemaEntity(object):
1023 def __init__(self, name, info):
1024 assert isinstance(name, str)
1025 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -06001026 # For explicitly defined entities, info points to the (explicit)
1027 # definition. For builtins (and their arrays), info is None.
1028 # For implicitly defined entities, info points to a place that
1029 # triggered the implicit definition (there may be more than one
1030 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +02001031 self.info = info
1032
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001033 def c_name(self):
1034 return c_name(self.name)
1035
Markus Armbrusterac882192015-09-16 13:06:05 +02001036 def check(self, schema):
1037 pass
1038
Eric Blake49823c42015-10-12 22:22:27 -06001039 def is_implicit(self):
1040 return not self.info
1041
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001042 def visit(self, visitor):
1043 pass
1044
1045
1046class QAPISchemaVisitor(object):
1047 def visit_begin(self, schema):
1048 pass
1049
1050 def visit_end(self):
1051 pass
1052
Eric Blake25a0d9c2015-10-12 22:22:21 -06001053 def visit_needed(self, entity):
1054 # Default to visiting everything
1055 return True
1056
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001057 def visit_builtin_type(self, name, info, json_type):
1058 pass
1059
1060 def visit_enum_type(self, name, info, values, prefix):
1061 pass
1062
1063 def visit_array_type(self, name, info, element_type):
1064 pass
1065
1066 def visit_object_type(self, name, info, base, members, variants):
1067 pass
1068
Markus Armbruster39a18152015-09-16 13:06:28 +02001069 def visit_object_type_flat(self, name, info, members, variants):
1070 pass
1071
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001072 def visit_alternate_type(self, name, info, variants):
1073 pass
1074
1075 def visit_command(self, name, info, arg_type, ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001076 gen, success_response, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001077 pass
1078
Eric Blake48825ca2016-07-13 21:50:19 -06001079 def visit_event(self, name, info, arg_type, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001080 pass
1081
Markus Armbrusterac882192015-09-16 13:06:05 +02001082
1083class QAPISchemaType(QAPISchemaEntity):
Eric Blake4040d992016-03-17 16:48:28 -06001084 # Return the C type for common use.
1085 # For the types we commonly box, this is a pointer type.
1086 def c_type(self):
1087 pass
1088
1089 # Return the C type to be used in a parameter list.
1090 def c_param_type(self):
1091 return self.c_type()
1092
1093 # Return the C type to be used where we suppress boxing.
1094 def c_unboxed_type(self):
1095 return self.c_type()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001096
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001097 def json_type(self):
1098 pass
1099
1100 def alternate_qtype(self):
1101 json2qtype = {
1102 'string': 'QTYPE_QSTRING',
1103 'number': 'QTYPE_QFLOAT',
1104 'int': 'QTYPE_QINT',
1105 'boolean': 'QTYPE_QBOOL',
1106 'object': 'QTYPE_QDICT'
1107 }
1108 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +02001109
1110
1111class QAPISchemaBuiltinType(QAPISchemaType):
Eric Blake861877a2016-03-17 16:48:36 -06001112 def __init__(self, name, json_type, c_type):
Markus Armbrusterac882192015-09-16 13:06:05 +02001113 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001114 assert not c_type or isinstance(c_type, str)
1115 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
1116 'value')
1117 self._json_type_name = json_type
1118 self._c_type_name = c_type
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001119
1120 def c_name(self):
1121 return self.name
1122
Eric Blake4040d992016-03-17 16:48:28 -06001123 def c_type(self):
1124 return self._c_type_name
1125
1126 def c_param_type(self):
1127 if self.name == 'str':
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001128 return 'const ' + self._c_type_name
1129 return self._c_type_name
1130
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001131 def json_type(self):
1132 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +02001133
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001134 def visit(self, visitor):
1135 visitor.visit_builtin_type(self.name, self.info, self.json_type())
1136
Markus Armbrusterac882192015-09-16 13:06:05 +02001137
1138class QAPISchemaEnumType(QAPISchemaType):
1139 def __init__(self, name, info, values, prefix):
1140 QAPISchemaType.__init__(self, name, info)
1141 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -07001142 assert isinstance(v, QAPISchemaMember)
1143 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001144 assert prefix is None or isinstance(prefix, str)
1145 self.values = values
1146 self.prefix = prefix
1147
1148 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -07001149 seen = {}
1150 for v in self.values:
1151 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001152
Eric Blake99df5282015-10-12 22:22:32 -06001153 def is_implicit(self):
1154 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -06001155 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -06001156
Eric Blake4040d992016-03-17 16:48:28 -06001157 def c_type(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001158 return c_name(self.name)
1159
Eric Blake93bda4d2015-12-01 22:20:55 -07001160 def member_names(self):
1161 return [v.name for v in self.values]
1162
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001163 def json_type(self):
1164 return 'string'
1165
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001166 def visit(self, visitor):
1167 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -07001168 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001169
Markus Armbrusterac882192015-09-16 13:06:05 +02001170
1171class QAPISchemaArrayType(QAPISchemaType):
1172 def __init__(self, name, info, element_type):
1173 QAPISchemaType.__init__(self, name, info)
1174 assert isinstance(element_type, str)
1175 self._element_type_name = element_type
1176 self.element_type = None
1177
1178 def check(self, schema):
1179 self.element_type = schema.lookup_type(self._element_type_name)
1180 assert self.element_type
1181
Eric Blake99df5282015-10-12 22:22:32 -06001182 def is_implicit(self):
1183 return True
1184
Eric Blake4040d992016-03-17 16:48:28 -06001185 def c_type(self):
1186 return c_name(self.name) + pointer_suffix
1187
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001188 def json_type(self):
1189 return 'array'
1190
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001191 def visit(self, visitor):
1192 visitor.visit_array_type(self.name, self.info, self.element_type)
1193
Markus Armbrusterac882192015-09-16 13:06:05 +02001194
1195class QAPISchemaObjectType(QAPISchemaType):
1196 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -07001197 # struct has local_members, optional base, and no variants
1198 # flat union has base, variants, and no local_members
1199 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +02001200 QAPISchemaType.__init__(self, name, info)
1201 assert base is None or isinstance(base, str)
1202 for m in local_members:
1203 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -07001204 m.set_owner(name)
1205 if variants is not None:
1206 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1207 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001208 self._base_name = base
1209 self.base = None
1210 self.local_members = local_members
1211 self.variants = variants
1212 self.members = None
1213
1214 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -07001215 if self.members is False: # check for cycles
Marc-André Lureau4148c292017-01-13 15:41:25 +01001216 raise QAPISemError(self.info,
1217 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001218 if self.members:
1219 return
1220 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -07001221 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +02001222 if self._base_name:
1223 self.base = schema.lookup_type(self._base_name)
1224 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +02001225 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001226 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001227 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001228 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001229 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001230 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +02001231 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001232 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001233 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -07001234 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001235
Eric Blake14f00c62016-03-03 09:16:43 -07001236 # Check that the members of this type do not cause duplicate JSON members,
Eric Blake27b60ab2015-11-18 01:52:51 -07001237 # and update seen to track the members seen so far. Report any errors
1238 # on behalf of info, which is not necessarily self.info
1239 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -07001240 assert not self.variants # not implemented
1241 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -07001242 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -07001243
Eric Blake99df5282015-10-12 22:22:32 -06001244 def is_implicit(self):
Eric Blake75996972016-03-17 16:48:29 -06001245 # See QAPISchema._make_implicit_object_type(), as well as
1246 # _def_predefineds()
1247 return self.name.startswith('q_')
Eric Blake99df5282015-10-12 22:22:32 -06001248
Eric Blakeb6167702016-07-13 21:50:16 -06001249 def is_empty(self):
1250 assert self.members is not None
1251 return not self.members and not self.variants
1252
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001253 def c_name(self):
Eric Blakecd50a252016-07-13 21:50:14 -06001254 assert self.name != 'q_empty'
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001255 return QAPISchemaType.c_name(self)
1256
Eric Blake4040d992016-03-17 16:48:28 -06001257 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001258 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -07001259 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001260
Eric Blake4040d992016-03-17 16:48:28 -06001261 def c_unboxed_type(self):
Eric Blake4040d992016-03-17 16:48:28 -06001262 return c_name(self.name)
1263
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001264 def json_type(self):
1265 return 'object'
1266
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001267 def visit(self, visitor):
1268 visitor.visit_object_type(self.name, self.info,
1269 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001270 visitor.visit_object_type_flat(self.name, self.info,
1271 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001272
Markus Armbrusterac882192015-09-16 13:06:05 +02001273
Eric Blaked44f9ac2015-12-01 22:20:54 -07001274class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001275 role = 'member'
1276
Eric Blaked44f9ac2015-12-01 22:20:54 -07001277 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001278 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001279 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001280 self.owner = None
1281
1282 def set_owner(self, name):
1283 assert not self.owner
1284 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001285
Eric Blake27b60ab2015-11-18 01:52:51 -07001286 def check_clash(self, info, seen):
1287 cname = c_name(self.name)
Markus Armbruster2cfbae32017-03-15 13:56:55 +01001288 if cname.lower() != cname and self.owner not in name_case_whitelist:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001289 raise QAPISemError(info,
1290 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001291 if cname in seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001292 raise QAPISemError(info, "%s collides with %s" %
1293 (self.describe(), seen[cname].describe()))
Eric Blake27b60ab2015-11-18 01:52:51 -07001294 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001295
Eric Blake88d4ef82015-11-18 01:52:50 -07001296 def _pretty_owner(self):
1297 owner = self.owner
Eric Blake75996972016-03-17 16:48:29 -06001298 if owner.startswith('q_obj_'):
Eric Blake88d4ef82015-11-18 01:52:50 -07001299 # See QAPISchema._make_implicit_object_type() - reverse the
1300 # mapping there to create a nice human-readable description
Eric Blake75996972016-03-17 16:48:29 -06001301 owner = owner[6:]
Eric Blake88d4ef82015-11-18 01:52:50 -07001302 if owner.endswith('-arg'):
1303 return '(parameter of %s)' % owner[:-4]
Eric Blakeac4338f2016-03-17 16:48:39 -06001304 elif owner.endswith('-base'):
1305 return '(base of %s)' % owner[:-5]
Eric Blake88d4ef82015-11-18 01:52:50 -07001306 else:
1307 assert owner.endswith('-wrapper')
1308 # Unreachable and not implemented
1309 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001310 if owner.endswith('Kind'):
1311 # See QAPISchema._make_implicit_enum_type()
1312 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001313 return '(%s of %s)' % (self.role, owner)
1314
1315 def describe(self):
1316 return "'%s' %s" % (self.name, self._pretty_owner())
1317
Markus Armbrusterac882192015-09-16 13:06:05 +02001318
Eric Blaked44f9ac2015-12-01 22:20:54 -07001319class QAPISchemaObjectTypeMember(QAPISchemaMember):
1320 def __init__(self, name, typ, optional):
1321 QAPISchemaMember.__init__(self, name)
1322 assert isinstance(typ, str)
1323 assert isinstance(optional, bool)
1324 self._type_name = typ
1325 self.type = None
1326 self.optional = optional
1327
1328 def check(self, schema):
1329 assert self.owner
1330 self.type = schema.lookup_type(self._type_name)
1331 assert self.type
1332
1333
Markus Armbrusterac882192015-09-16 13:06:05 +02001334class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001335 def __init__(self, tag_name, tag_member, variants):
1336 # Flat unions pass tag_name but not tag_member.
1337 # Simple unions and alternates pass tag_member but not tag_name.
1338 # After check(), tag_member is always set, and tag_name remains
1339 # a reliable witness of being used by a flat union.
1340 assert bool(tag_member) != bool(tag_name)
1341 assert (isinstance(tag_name, str) or
1342 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001343 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001344 for v in variants:
1345 assert isinstance(v, QAPISchemaObjectTypeVariant)
Eric Blakeda9cb192016-07-13 21:50:15 -06001346 self._tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001347 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001348 self.variants = variants
1349
Eric Blake88d4ef82015-11-18 01:52:50 -07001350 def set_owner(self, name):
1351 for v in self.variants:
1352 v.set_owner(name)
1353
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001354 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001355 if not self.tag_member: # flat union
Eric Blakeda9cb192016-07-13 21:50:15 -06001356 self.tag_member = seen[c_name(self._tag_name)]
1357 assert self._tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001358 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1359 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001360 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001361 # Union names must match enum values; alternate names are
1362 # checked separately. Use 'seen' to tell the two apart.
1363 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001364 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001365 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001366 v.type.check(schema)
1367
Eric Blake27b60ab2015-11-18 01:52:51 -07001368 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001369 for v in self.variants:
1370 # Reset seen map for each variant, since qapi names from one
1371 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001372 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001373 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001374
Eric Blake437db252015-09-29 16:21:02 -06001375
Markus Armbrusterac882192015-09-16 13:06:05 +02001376class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001377 role = 'branch'
1378
Markus Armbrusterac882192015-09-16 13:06:05 +02001379 def __init__(self, name, typ):
1380 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1381
Markus Armbrusterac882192015-09-16 13:06:05 +02001382
1383class QAPISchemaAlternateType(QAPISchemaType):
1384 def __init__(self, name, info, variants):
1385 QAPISchemaType.__init__(self, name, info)
1386 assert isinstance(variants, QAPISchemaObjectTypeVariants)
Eric Blakeda9cb192016-07-13 21:50:15 -06001387 assert variants.tag_member
Eric Blake88d4ef82015-11-18 01:52:50 -07001388 variants.set_owner(name)
1389 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001390 self.variants = variants
1391
1392 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001393 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001394 # Not calling self.variants.check_clash(), because there's nothing
1395 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001396 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001397 # Alternate branch names have no relation to the tag enum values;
1398 # so we have to check for potential name collisions ourselves.
1399 seen = {}
1400 for v in self.variants.variants:
1401 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001402
Eric Blake4040d992016-03-17 16:48:28 -06001403 def c_type(self):
1404 return c_name(self.name) + pointer_suffix
1405
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001406 def json_type(self):
1407 return 'value'
1408
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001409 def visit(self, visitor):
1410 visitor.visit_alternate_type(self.name, self.info, self.variants)
1411
Eric Blakec8184082016-07-13 21:50:20 -06001412 def is_empty(self):
1413 return False
1414
Markus Armbrusterac882192015-09-16 13:06:05 +02001415
1416class QAPISchemaCommand(QAPISchemaEntity):
Eric Blake48825ca2016-07-13 21:50:19 -06001417 def __init__(self, name, info, arg_type, ret_type, gen, success_response,
1418 boxed):
Markus Armbrusterac882192015-09-16 13:06:05 +02001419 QAPISchemaEntity.__init__(self, name, info)
1420 assert not arg_type or isinstance(arg_type, str)
1421 assert not ret_type or isinstance(ret_type, str)
1422 self._arg_type_name = arg_type
1423 self.arg_type = None
1424 self._ret_type_name = ret_type
1425 self.ret_type = None
1426 self.gen = gen
1427 self.success_response = success_response
Eric Blake48825ca2016-07-13 21:50:19 -06001428 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001429
1430 def check(self, schema):
1431 if self._arg_type_name:
1432 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001433 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1434 isinstance(self.arg_type, QAPISchemaAlternateType))
1435 self.arg_type.check(schema)
1436 if self.boxed:
1437 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001438 raise QAPISemError(self.info,
1439 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001440 else:
1441 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1442 assert not self.arg_type.variants
1443 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001444 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001445 if self._ret_type_name:
1446 self.ret_type = schema.lookup_type(self._ret_type_name)
1447 assert isinstance(self.ret_type, QAPISchemaType)
1448
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001449 def visit(self, visitor):
1450 visitor.visit_command(self.name, self.info,
1451 self.arg_type, self.ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001452 self.gen, self.success_response, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001453
Markus Armbrusterac882192015-09-16 13:06:05 +02001454
1455class QAPISchemaEvent(QAPISchemaEntity):
Eric Blake48825ca2016-07-13 21:50:19 -06001456 def __init__(self, name, info, arg_type, boxed):
Markus Armbrusterac882192015-09-16 13:06:05 +02001457 QAPISchemaEntity.__init__(self, name, info)
1458 assert not arg_type or isinstance(arg_type, str)
1459 self._arg_type_name = arg_type
1460 self.arg_type = None
Eric Blake48825ca2016-07-13 21:50:19 -06001461 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001462
1463 def check(self, schema):
1464 if self._arg_type_name:
1465 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001466 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1467 isinstance(self.arg_type, QAPISchemaAlternateType))
1468 self.arg_type.check(schema)
1469 if self.boxed:
1470 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001471 raise QAPISemError(self.info,
1472 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001473 else:
1474 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1475 assert not self.arg_type.variants
1476 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001477 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001478
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001479 def visit(self, visitor):
Eric Blake48825ca2016-07-13 21:50:19 -06001480 visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001481
Markus Armbrusterac882192015-09-16 13:06:05 +02001482
1483class QAPISchema(object):
1484 def __init__(self, fname):
1485 try:
Marc-André Lureau3313b612017-01-13 15:41:29 +01001486 parser = QAPISchemaParser(open(fname, "r"))
1487 self.exprs = check_exprs(parser.exprs)
1488 self.docs = check_docs(parser.docs)
Eric Blake7618b912015-10-12 22:22:22 -06001489 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001490 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001491 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001492 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001493 self._def_exprs()
1494 self.check()
Marc-André Lureau4148c292017-01-13 15:41:25 +01001495 except QAPIError as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001496 print >>sys.stderr, err
1497 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001498
Markus Armbrusterac882192015-09-16 13:06:05 +02001499 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001500 # Only the predefined types are allowed to not have info
1501 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001502 assert ent.name not in self._entity_dict
1503 self._entity_dict[ent.name] = ent
1504
1505 def lookup_entity(self, name, typ=None):
1506 ent = self._entity_dict.get(name)
1507 if typ and not isinstance(ent, typ):
1508 return None
1509 return ent
1510
1511 def lookup_type(self, name):
1512 return self.lookup_entity(name, QAPISchemaType)
1513
Eric Blake861877a2016-03-17 16:48:36 -06001514 def _def_builtin_type(self, name, json_type, c_type):
1515 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001516 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1517 # qapi-types.h from a single .c, all arrays of builtins must be
1518 # declared in the first file whether or not they are used. Nicer
1519 # would be to use lazy instantiation, while figuring out how to
1520 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001521 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001522
1523 def _def_predefineds(self):
Eric Blake861877a2016-03-17 16:48:36 -06001524 for t in [('str', 'string', 'char' + pointer_suffix),
1525 ('number', 'number', 'double'),
1526 ('int', 'int', 'int64_t'),
1527 ('int8', 'int', 'int8_t'),
1528 ('int16', 'int', 'int16_t'),
1529 ('int32', 'int', 'int32_t'),
1530 ('int64', 'int', 'int64_t'),
1531 ('uint8', 'int', 'uint8_t'),
1532 ('uint16', 'int', 'uint16_t'),
1533 ('uint32', 'int', 'uint32_t'),
1534 ('uint64', 'int', 'uint64_t'),
1535 ('size', 'int', 'uint64_t'),
1536 ('bool', 'boolean', 'bool'),
1537 ('any', 'value', 'QObject' + pointer_suffix)]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001538 self._def_builtin_type(*t)
Eric Blake75996972016-03-17 16:48:29 -06001539 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1540 None, [], None)
Markus Armbruster39a18152015-09-16 13:06:28 +02001541 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001542 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1543 'qstring', 'qdict', 'qlist',
1544 'qfloat', 'qbool'])
1545 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001546 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001547
Eric Blake93bda4d2015-12-01 22:20:55 -07001548 def _make_enum_members(self, values):
1549 return [QAPISchemaMember(v) for v in values]
1550
Eric Blake99df5282015-10-12 22:22:32 -06001551 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001552 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001553 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001554 self._def_entity(QAPISchemaEnumType(
1555 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001556 return name
1557
Eric Blake99df5282015-10-12 22:22:32 -06001558 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001559 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001560 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001561 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001562 return name
1563
Eric Blake99df5282015-10-12 22:22:32 -06001564 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001565 if not members:
1566 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001567 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake75996972016-03-17 16:48:29 -06001568 name = 'q_obj_%s-%s' % (name, role)
Markus Armbrusterac882192015-09-16 13:06:05 +02001569 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001570 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001571 members, None))
1572 return name
1573
1574 def _def_enum_type(self, expr, info):
1575 name = expr['enum']
1576 data = expr['data']
1577 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001578 self._def_entity(QAPISchemaEnumType(
1579 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001580
Eric Blake99df5282015-10-12 22:22:32 -06001581 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001582 optional = False
1583 if name.startswith('*'):
1584 name = name[1:]
1585 optional = True
1586 if isinstance(typ, list):
1587 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001588 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001589 return QAPISchemaObjectTypeMember(name, typ, optional)
1590
Eric Blake99df5282015-10-12 22:22:32 -06001591 def _make_members(self, data, info):
1592 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001593 for (key, value) in data.iteritems()]
1594
1595 def _def_struct_type(self, expr, info):
1596 name = expr['struct']
1597 base = expr.get('base')
1598 data = expr['data']
1599 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001600 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001601 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001602
1603 def _make_variant(self, case, typ):
1604 return QAPISchemaObjectTypeVariant(case, typ)
1605
Eric Blake99df5282015-10-12 22:22:32 -06001606 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001607 if isinstance(typ, list):
1608 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001609 typ = self._make_array_type(typ[0], info)
1610 typ = self._make_implicit_object_type(
1611 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001612 return QAPISchemaObjectTypeVariant(case, typ)
1613
Markus Armbrusterac882192015-09-16 13:06:05 +02001614 def _def_union_type(self, expr, info):
1615 name = expr['union']
1616 data = expr['data']
1617 base = expr.get('base')
1618 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001619 tag_member = None
Eric Blakeac4338f2016-03-17 16:48:39 -06001620 if isinstance(base, dict):
1621 base = (self._make_implicit_object_type(
1622 name, info, 'base', self._make_members(base, info)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001623 if tag_name:
1624 variants = [self._make_variant(key, value)
1625 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001626 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001627 else:
Eric Blake99df5282015-10-12 22:22:32 -06001628 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001629 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001630 typ = self._make_implicit_enum_type(name, info,
1631 [v.name for v in variants])
1632 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001633 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001634 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001635 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001636 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001637 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001638 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001639
1640 def _def_alternate_type(self, expr, info):
1641 name = expr['alternate']
1642 data = expr['data']
1643 variants = [self._make_variant(key, value)
1644 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001645 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001646 self._def_entity(
1647 QAPISchemaAlternateType(name, info,
1648 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001649 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001650 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001651
1652 def _def_command(self, expr, info):
1653 name = expr['command']
1654 data = expr.get('data')
1655 rets = expr.get('returns')
1656 gen = expr.get('gen', True)
1657 success_response = expr.get('success-response', True)
Eric Blake48825ca2016-07-13 21:50:19 -06001658 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001659 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001660 data = self._make_implicit_object_type(
1661 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001662 if isinstance(rets, list):
1663 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001664 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001665 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
Eric Blake48825ca2016-07-13 21:50:19 -06001666 success_response, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001667
1668 def _def_event(self, expr, info):
1669 name = expr['event']
1670 data = expr.get('data')
Eric Blake48825ca2016-07-13 21:50:19 -06001671 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001672 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001673 data = self._make_implicit_object_type(
1674 name, info, 'arg', self._make_members(data, info))
Eric Blake48825ca2016-07-13 21:50:19 -06001675 self._def_entity(QAPISchemaEvent(name, info, data, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001676
1677 def _def_exprs(self):
1678 for expr_elem in self.exprs:
1679 expr = expr_elem['expr']
1680 info = expr_elem['info']
1681 if 'enum' in expr:
1682 self._def_enum_type(expr, info)
1683 elif 'struct' in expr:
1684 self._def_struct_type(expr, info)
1685 elif 'union' in expr:
1686 self._def_union_type(expr, info)
1687 elif 'alternate' in expr:
1688 self._def_alternate_type(expr, info)
1689 elif 'command' in expr:
1690 self._def_command(expr, info)
1691 elif 'event' in expr:
1692 self._def_event(expr, info)
1693 else:
1694 assert False
1695
1696 def check(self):
1697 for ent in self._entity_dict.values():
1698 ent.check(self)
1699
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001700 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001701 visitor.visit_begin(self)
1702 for (name, entity) in sorted(self._entity_dict.items()):
1703 if visitor.visit_needed(entity):
1704 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001705 visitor.visit_end()
1706
Markus Armbruster2caba362013-07-27 17:41:56 +02001707
Markus Armbruster00e4b282015-06-10 10:04:36 +02001708#
1709# Code generation helpers
1710#
1711
Michael Roth0f923be2011-07-19 14:50:39 -05001712def camel_case(name):
1713 new_name = ''
1714 first = True
1715 for ch in name:
1716 if ch in ['_', '-']:
1717 first = True
1718 elif first:
1719 new_name += ch.upper()
1720 first = False
1721 else:
1722 new_name += ch.lower()
1723 return new_name
1724
Eric Blake437db252015-09-29 16:21:02 -06001725
Markus Armbruster849bc532015-05-14 06:50:53 -06001726# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1727# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1728# ENUM24_Name -> ENUM24_NAME
1729def camel_to_upper(value):
1730 c_fun_str = c_name(value, False)
1731 if value.isupper():
1732 return c_fun_str
1733
1734 new_name = ''
1735 l = len(c_fun_str)
1736 for i in range(l):
1737 c = c_fun_str[i]
1738 # When c is upper and no "_" appears before, do more checks
1739 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001740 if i < l - 1 and c_fun_str[i + 1].islower():
1741 new_name += '_'
1742 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001743 new_name += '_'
1744 new_name += c
1745 return new_name.lstrip('_').upper()
1746
Eric Blake437db252015-09-29 16:21:02 -06001747
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001748def c_enum_const(type_name, const_name, prefix=None):
1749 if prefix is not None:
1750 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001751 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001752
Eric Blake18df5152015-05-14 06:50:48 -06001753c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001754
Eric Blake437db252015-09-29 16:21:02 -06001755
Eric Blakec6405b52015-05-14 06:50:55 -06001756# Map @name to a valid C identifier.
1757# If @protect, avoid returning certain ticklish identifiers (like
1758# C keywords) by prepending "q_".
1759#
1760# Used for converting 'name' from a 'name':'type' qapi definition
1761# into a generated struct member, as well as converting type names
1762# into substrings of a generated C function name.
1763# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1764# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001765def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001766 # ANSI X3J11/88-090, 3.1.1
1767 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001768 'default', 'do', 'double', 'else', 'enum', 'extern',
1769 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1770 'return', 'short', 'signed', 'sizeof', 'static',
1771 'struct', 'switch', 'typedef', 'union', 'unsigned',
1772 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001773 # ISO/IEC 9899:1999, 6.4.1
1774 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1775 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001776 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1777 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001778 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1779 # excluding _.*
1780 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001781 # C++ ISO/IEC 14882:2003 2.11
1782 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1783 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1784 'namespace', 'new', 'operator', 'private', 'protected',
1785 'public', 'reinterpret_cast', 'static_cast', 'template',
1786 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1787 'using', 'virtual', 'wchar_t',
1788 # alternative representations
1789 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1790 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001791 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001792 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001793 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001794 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1795 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001796 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001797 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001798
Amos Kong05dfb262014-06-10 19:25:53 +08001799eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001800pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001801
Eric Blake437db252015-09-29 16:21:02 -06001802
Michael Roth0f923be2011-07-19 14:50:39 -05001803def genindent(count):
1804 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001805 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001806 ret += " "
1807 return ret
1808
1809indent_level = 0
1810
Eric Blake437db252015-09-29 16:21:02 -06001811
Michael Roth0f923be2011-07-19 14:50:39 -05001812def push_indent(indent_amount=4):
1813 global indent_level
1814 indent_level += indent_amount
1815
Eric Blake437db252015-09-29 16:21:02 -06001816
Michael Roth0f923be2011-07-19 14:50:39 -05001817def pop_indent(indent_amount=4):
1818 global indent_level
1819 indent_level -= indent_amount
1820
Eric Blake437db252015-09-29 16:21:02 -06001821
Markus Armbruster77e703b2015-06-24 19:27:32 +02001822# Generate @code with @kwds interpolated.
1823# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001824def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001825 raw = code % kwds
1826 if indent_level:
1827 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001828 # re.subn() lacks flags support before Python 2.7, use re.compile()
1829 raw = re.subn(re.compile("^.", re.MULTILINE),
1830 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001831 raw = raw[0]
1832 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001833
Eric Blake437db252015-09-29 16:21:02 -06001834
Michael Roth0f923be2011-07-19 14:50:39 -05001835def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001836 if code[0] == '\n':
1837 code = code[1:]
1838 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001839
Michael Roth0f923be2011-07-19 14:50:39 -05001840
1841def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001842 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001843
Eric Blake437db252015-09-29 16:21:02 -06001844
Michael Rothc0afa9c2013-05-10 17:46:00 -05001845def guardstart(name):
1846 return mcgen('''
1847
1848#ifndef %(name)s
1849#define %(name)s
1850
1851''',
1852 name=guardname(name))
1853
Eric Blake437db252015-09-29 16:21:02 -06001854
Michael Rothc0afa9c2013-05-10 17:46:00 -05001855def guardend(name):
1856 return mcgen('''
1857
1858#endif /* %(name)s */
1859
1860''',
1861 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001862
Eric Blake437db252015-09-29 16:21:02 -06001863
Markus Armbrustere98859a2015-09-16 13:06:16 +02001864def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001865 ret = mcgen('''
1866
Markus Armbrustere98859a2015-09-16 13:06:16 +02001867const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001868''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001869 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001870 for value in values:
1871 index = c_enum_const(name, value, prefix)
1872 ret += mcgen('''
1873 [%(index)s] = "%(value)s",
1874''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001875 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001876
Eric Blake7fb1cf12015-11-18 01:52:57 -07001877 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001878 ret += mcgen('''
1879 [%(max_index)s] = NULL,
1880};
1881''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001882 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001883 return ret
1884
Eric Blake437db252015-09-29 16:21:02 -06001885
Markus Armbrustere98859a2015-09-16 13:06:16 +02001886def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001887 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001888 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001889
1890 ret = mcgen('''
1891
1892typedef enum %(c_name)s {
1893''',
1894 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001895
1896 i = 0
1897 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001898 ret += mcgen('''
1899 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001900''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001901 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001902 i=i)
1903 i += 1
1904
Markus Armbrustere98859a2015-09-16 13:06:16 +02001905 ret += mcgen('''
1906} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001907''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001908 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001909
Markus Armbrustere98859a2015-09-16 13:06:16 +02001910 ret += mcgen('''
1911
1912extern const char *const %(c_name)s_lookup[];
1913''',
1914 c_name=c_name(name))
1915 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001916
Eric Blake437db252015-09-29 16:21:02 -06001917
Eric Blake48825ca2016-07-13 21:50:19 -06001918def gen_params(arg_type, boxed, extra):
Markus Armbruster03b43672015-09-16 13:06:20 +02001919 if not arg_type:
Eric Blakec8184082016-07-13 21:50:20 -06001920 assert not boxed
Markus Armbruster03b43672015-09-16 13:06:20 +02001921 return extra
Markus Armbruster03b43672015-09-16 13:06:20 +02001922 ret = ''
1923 sep = ''
Eric Blake48825ca2016-07-13 21:50:19 -06001924 if boxed:
Eric Blakec8184082016-07-13 21:50:20 -06001925 ret += '%s arg' % arg_type.c_param_type()
1926 sep = ', '
Eric Blake48825ca2016-07-13 21:50:19 -06001927 else:
1928 assert not arg_type.variants
1929 for memb in arg_type.members:
1930 ret += sep
1931 sep = ', '
1932 if memb.optional:
1933 ret += 'bool has_%s, ' % c_name(memb.name)
1934 ret += '%s %s' % (memb.type.c_param_type(),
1935 c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001936 if extra:
1937 ret += sep + extra
1938 return ret
1939
Eric Blake1f353342015-09-29 16:21:13 -06001940
Markus Armbruster00e4b282015-06-10 10:04:36 +02001941#
1942# Common command line parsing
1943#
1944
Eric Blake437db252015-09-29 16:21:02 -06001945
1946def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001947
1948 try:
1949 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001950 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001951 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001952 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001953 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001954 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001955 sys.exit(1)
1956
1957 output_dir = ""
1958 prefix = ""
1959 do_c = False
1960 do_h = False
1961 extra_opts = []
1962
1963 for oa in opts:
1964 o, a = oa
1965 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001966 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1967 if match.end() != len(a):
1968 print >>sys.stderr, \
1969 "%s: 'funny character '%s' in argument of --prefix" \
1970 % (sys.argv[0], a[match.end()])
1971 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001972 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001973 elif o in ("-o", "--output-dir"):
1974 output_dir = a + "/"
1975 elif o in ("-c", "--source"):
1976 do_c = True
1977 elif o in ("-h", "--header"):
1978 do_h = True
1979 else:
1980 extra_opts.append(oa)
1981
1982 if not do_c and not do_h:
1983 do_c = True
1984 do_h = True
1985
Markus Armbruster16d80f62015-04-02 13:32:16 +02001986 if len(args) != 1:
1987 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001988 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001989 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001990
Markus Armbruster54414042015-06-09 16:22:45 +02001991 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001992
Markus Armbruster00e4b282015-06-10 10:04:36 +02001993#
1994# Generate output files with boilerplate
1995#
1996
Eric Blake437db252015-09-29 16:21:02 -06001997
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001998def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1999 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02002000 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002001 c_file = output_dir + prefix + c_file
2002 h_file = output_dir + prefix + h_file
2003
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02002004 if output_dir:
2005 try:
2006 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01002007 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02002008 if e.errno != errno.EEXIST:
2009 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002010
2011 def maybe_open(really, name, opt):
2012 if really:
2013 return open(name, opt)
2014 else:
2015 import StringIO
2016 return StringIO.StringIO()
2017
2018 fdef = maybe_open(do_c, c_file, 'w')
2019 fdecl = maybe_open(do_h, h_file, 'w')
2020
2021 fdef.write(mcgen('''
2022/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2023%(comment)s
2024''',
Eric Blake437db252015-09-29 16:21:02 -06002025 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002026
2027 fdecl.write(mcgen('''
2028/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2029%(comment)s
2030#ifndef %(guard)s
2031#define %(guard)s
2032
2033''',
Eric Blake437db252015-09-29 16:21:02 -06002034 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002035
2036 return (fdef, fdecl)
2037
Eric Blake437db252015-09-29 16:21:02 -06002038
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002039def close_output(fdef, fdecl):
2040 fdecl.write('''
2041#endif
2042''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002043 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002044 fdef.close()