blob: fe9d3cf36d6f0903d1b370bcf7255268f696b24a [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
44returns_whitelist = [
45 # From QMP:
46 'human-monitor-command',
Markus Armbruster6eb39372015-09-16 13:06:25 +020047 'qom-get',
Eric Blake10d4d992015-05-04 09:05:23 -060048 'query-migrate-cache-size',
49 'query-tpm-models',
50 'query-tpm-types',
51 'ringbuf-read',
52
53 # From QGA:
54 'guest-file-open',
55 'guest-fsfreeze-freeze',
56 'guest-fsfreeze-freeze-list',
57 'guest-fsfreeze-status',
58 'guest-fsfreeze-thaw',
59 'guest-get-time',
60 'guest-set-vcpus',
61 'guest-sync',
62 'guest-sync-delimited',
Eric Blake10d4d992015-05-04 09:05:23 -060063]
64
Eric Blake893e1f22015-12-01 22:20:57 -070065# Whitelist of entities allowed to violate case conventions
66case_whitelist = [
67 # From QMP:
68 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
Eric Blake893e1f22015-12-01 22:20:57 -070069 'CpuInfoMIPS', # PC, visible through query-cpu
70 'CpuInfoTricore', # PC, visible through query-cpu
Eric Blake893e1f22015-12-01 22:20:57 -070071 'QapiErrorClass', # all members, visible through errors
72 'UuidInfo', # UUID, visible through query-uuid
73 'X86CPURegister32', # all members, visible indirectly through qom-get
Eric Blake3666a972016-03-17 16:48:40 -060074 'q_obj_CpuInfo-base', # CPU, visible through query-cpu
Eric Blake893e1f22015-12-01 22:20:57 -070075]
76
Eric Blake4dc2e692015-05-04 09:05:17 -060077enum_types = []
78struct_types = []
79union_types = []
80events = []
81all_names = {}
82
Markus Armbruster00e4b282015-06-10 10:04:36 +020083#
84# Parsing the schema into expressions
85#
86
Eric Blake437db252015-09-29 16:21:02 -060087
Lluís Vilanovaa719a272014-05-07 20:46:15 +020088def error_path(parent):
89 res = ""
90 while parent:
91 res = ("In file included from %s:%d:\n" % (parent['file'],
92 parent['line'])) + res
93 parent = parent['parent']
94 return res
95
Eric Blake437db252015-09-29 16:21:02 -060096
Marc-André Lureau4148c292017-01-13 15:41:25 +010097class QAPIError(Exception):
98 def __init__(self, fname, line, col, incl_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -060099 Exception.__init__(self)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100100 self.fname = fname
101 self.line = line
102 self.col = col
103 self.info = incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +0200104 self.msg = msg
Marc-André Lureau4148c292017-01-13 15:41:25 +0100105
106 def __str__(self):
107 loc = "%s:%d" % (self.fname, self.line)
108 if self.col is not None:
109 loc += ":%s" % self.col
110 return error_path(self.info) + "%s: %s" % (loc, self.msg)
111
112
113class QAPIParseError(QAPIError):
114 def __init__(self, parser, msg):
115 col = 1
116 for ch in parser.src[parser.line_pos:parser.pos]:
Wenchao Xia515b9432014-03-04 18:44:33 -0800117 if ch == '\t':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100118 col = (col + 7) % 8 + 1
Markus Armbruster2caba362013-07-27 17:41:56 +0200119 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100120 col += 1
121 QAPIError.__init__(self, parser.fname, parser.line, col,
122 parser.incl_info, msg)
Markus Armbruster2caba362013-07-27 17:41:56 +0200123
Eric Blake437db252015-09-29 16:21:02 -0600124
Marc-André Lureau4148c292017-01-13 15:41:25 +0100125class QAPISemError(QAPIError):
126 def __init__(self, info, msg):
127 QAPIError.__init__(self, info['file'], info['line'], None,
128 info['parent'], msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800129
Eric Blake437db252015-09-29 16:21:02 -0600130
Marc-André Lureau3313b612017-01-13 15:41:29 +0100131class QAPIDoc(object):
132 class Section(object):
133 def __init__(self, name=None):
134 # optional section name (argument/member or section name)
135 self.name = name
136 # the list of lines for this section
137 self.content = []
138
139 def append(self, line):
140 self.content.append(line)
141
142 def __repr__(self):
143 return "\n".join(self.content).strip()
144
145 class ArgSection(Section):
146 pass
147
148 def __init__(self, parser, info):
149 # self.parser is used to report errors with QAPIParseError. The
150 # resulting error position depends on the state of the parser.
151 # It happens to be the beginning of the comment. More or less
152 # servicable, but action at a distance.
153 self.parser = parser
154 self.info = info
155 self.symbol = None
156 self.body = QAPIDoc.Section()
157 # dict mapping parameter name to ArgSection
158 self.args = OrderedDict()
159 # a list of Section
160 self.sections = []
161 # the current section
162 self.section = self.body
163 # associated expression (to be set by expression parser)
164 self.expr = None
165
166 def has_section(self, name):
167 """Return True if we have a section with this name."""
168 for i in self.sections:
169 if i.name == name:
170 return True
171 return False
172
173 def append(self, line):
174 """Parse a comment line and add it to the documentation."""
175 line = line[1:]
176 if not line:
177 self._append_freeform(line)
178 return
179
180 if line[0] != ' ':
181 raise QAPIParseError(self.parser, "Missing space after #")
182 line = line[1:]
183
184 # FIXME not nice: things like '# @foo:' and '# @foo: ' aren't
185 # recognized, and get silently treated as ordinary text
186 if self.symbol:
187 self._append_symbol_line(line)
188 elif not self.body.content and line.startswith("@"):
189 if not line.endswith(":"):
190 raise QAPIParseError(self.parser, "Line should end with :")
191 self.symbol = line[1:-1]
192 # FIXME invalid names other than the empty string aren't flagged
193 if not self.symbol:
194 raise QAPIParseError(self.parser, "Invalid name")
195 else:
196 self._append_freeform(line)
197
198 def _append_symbol_line(self, line):
199 name = line.split(' ', 1)[0]
200
201 if name.startswith("@") and name.endswith(":"):
202 line = line[len(name)+1:]
203 self._start_args_section(name[1:-1])
204 elif name in ("Returns:", "Since:",
205 # those are often singular or plural
206 "Note:", "Notes:",
207 "Example:", "Examples:",
208 "TODO:"):
209 line = line[len(name)+1:]
210 self._start_section(name[:-1])
211
212 self._append_freeform(line)
213
214 def _start_args_section(self, name):
215 # FIXME invalid names other than the empty string aren't flagged
216 if not name:
217 raise QAPIParseError(self.parser, "Invalid parameter name")
218 if name in self.args:
219 raise QAPIParseError(self.parser,
220 "'%s' parameter name duplicated" % name)
221 if self.sections:
222 raise QAPIParseError(self.parser,
223 "'@%s:' can't follow '%s' section"
224 % (name, self.sections[0].name))
225 self.section = QAPIDoc.ArgSection(name)
226 self.args[name] = self.section
227
228 def _start_section(self, name=""):
229 if name in ("Returns", "Since") and self.has_section(name):
230 raise QAPIParseError(self.parser,
231 "Duplicated '%s' section" % name)
232 self.section = QAPIDoc.Section(name)
233 self.sections.append(self.section)
234
235 def _append_freeform(self, line):
236 in_arg = isinstance(self.section, QAPIDoc.ArgSection)
237 if (in_arg and self.section.content
238 and not self.section.content[-1]
239 and line and not line[0].isspace()):
240 self._start_section()
241 if (in_arg or not self.section.name
242 or not self.section.name.startswith("Example")):
243 line = line.strip()
244 self.section.append(line)
245
246
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200247class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500248
Eric Blake437db252015-09-29 16:21:02 -0600249 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200250 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200251 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200252 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200253 previously_included.append(abs_fname)
254 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200255 self.src = fp.read()
256 if self.src == '' or self.src[-1] != '\n':
257 self.src += '\n'
258 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800259 self.line = 1
260 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200261 self.exprs = []
Marc-André Lureau3313b612017-01-13 15:41:29 +0100262 self.docs = []
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200263 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500264
Eric Blake437db252015-09-29 16:21:02 -0600265 while self.tok is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100266 info = {'file': fname, 'line': self.line,
267 'parent': self.incl_info}
Marc-André Lureau3313b612017-01-13 15:41:29 +0100268 if self.tok == '#':
269 doc = self.get_doc(info)
270 self.docs.append(doc)
271 continue
272
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200273 expr = self.get_expr(False)
Markus Armbrustere04dea82017-03-15 13:56:50 +0100274 if 'include' in expr:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200275 if len(expr) != 1:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100276 raise QAPISemError(info, "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200277 include = expr["include"]
278 if not isinstance(include, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100279 raise QAPISemError(info,
280 "Value of 'include' must be a string")
Markus Armbrustere04dea82017-03-15 13:56:50 +0100281 self._include(include, info, os.path.dirname(abs_fname),
282 previously_included)
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100283 elif "pragma" in expr:
284 if len(expr) != 1:
285 raise QAPISemError(info, "Invalid 'pragma' directive")
286 pragma = expr['pragma']
287 if not isinstance(pragma, dict):
288 raise QAPISemError(
289 info, "Value of 'pragma' must be a dictionary")
290 for name, value in pragma.iteritems():
291 self._pragma(name, value, info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200292 else:
293 expr_elem = {'expr': expr,
Marc-André Lureau4148c292017-01-13 15:41:25 +0100294 'info': info}
Marc-André Lureau3313b612017-01-13 15:41:29 +0100295 if (self.docs
296 and self.docs[-1].info['file'] == fname
297 and not self.docs[-1].expr):
298 self.docs[-1].expr = expr
299 expr_elem['doc'] = self.docs[-1]
300
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200301 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500302
Markus Armbrustere04dea82017-03-15 13:56:50 +0100303 def _include(self, include, info, base_dir, previously_included):
304 incl_abs_fname = os.path.join(base_dir, include)
305 # catch inclusion cycle
306 inf = info
307 while inf:
308 if incl_abs_fname == os.path.abspath(inf['file']):
309 raise QAPISemError(info, "Inclusion loop for %s" % include)
310 inf = inf['parent']
311
312 # skip multiple include of the same file
313 if incl_abs_fname in previously_included:
314 return
315 try:
316 fobj = open(incl_abs_fname, 'r')
317 except IOError as e:
318 raise QAPISemError(info, '%s: %s' % (e.strerror, include))
319 exprs_include = QAPISchemaParser(fobj, previously_included, info)
320 self.exprs.extend(exprs_include.exprs)
321 self.docs.extend(exprs_include.docs)
322
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100323 def _pragma(self, name, value, info):
324 global doc_required
325 if name == 'doc-required':
326 if not isinstance(value, bool):
327 raise QAPISemError(info,
328 "Pragma 'doc-required' must be boolean")
329 doc_required = value
330 else:
331 raise QAPISemError(info, "Unknown pragma '%s'" % name)
332
Marc-André Lureau3313b612017-01-13 15:41:29 +0100333 def accept(self, skip_comment=True):
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200334 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200335 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200336 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200337 self.cursor += 1
338 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500339
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200340 if self.tok == '#':
Marc-André Lureau3313b612017-01-13 15:41:29 +0100341 if self.src[self.cursor] == '#':
342 # Start of doc comment
343 skip_comment = False
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200344 self.cursor = self.src.find('\n', self.cursor)
Marc-André Lureau3313b612017-01-13 15:41:29 +0100345 if not skip_comment:
346 self.val = self.src[self.pos:self.cursor]
347 return
Eric Blake8712fa52015-10-26 16:34:41 -0600348 elif self.tok in "{}:,[]":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200349 return
350 elif self.tok == "'":
351 string = ''
352 esc = False
353 while True:
354 ch = self.src[self.cursor]
355 self.cursor += 1
356 if ch == '\n':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100357 raise QAPIParseError(self, 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200358 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600359 if ch == 'b':
360 string += '\b'
361 elif ch == 'f':
362 string += '\f'
363 elif ch == 'n':
364 string += '\n'
365 elif ch == 'r':
366 string += '\r'
367 elif ch == 't':
368 string += '\t'
369 elif ch == 'u':
370 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600371 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600372 ch = self.src[self.cursor]
373 self.cursor += 1
374 if ch not in "0123456789abcdefABCDEF":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100375 raise QAPIParseError(self,
376 '\\u escape needs 4 '
377 'hex digits')
Eric Blakea7f59662015-05-04 09:05:36 -0600378 value = (value << 4) + int(ch, 16)
379 # If Python 2 and 3 didn't disagree so much on
380 # how to handle Unicode, then we could allow
381 # Unicode string defaults. But most of QAPI is
382 # ASCII-only, so we aren't losing much for now.
383 if not value or value > 0x7f:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100384 raise QAPIParseError(self,
385 'For now, \\u escape '
386 'only supports non-zero '
387 'values up to \\u007f')
Eric Blakea7f59662015-05-04 09:05:36 -0600388 string += chr(value)
389 elif ch in "\\/'\"":
390 string += ch
391 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100392 raise QAPIParseError(self,
393 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200394 esc = False
395 elif ch == "\\":
396 esc = True
397 elif ch == "'":
398 self.val = string
399 return
400 else:
401 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200402 elif self.src.startswith("true", self.pos):
403 self.val = True
404 self.cursor += 3
405 return
406 elif self.src.startswith("false", self.pos):
407 self.val = False
408 self.cursor += 4
409 return
410 elif self.src.startswith("null", self.pos):
411 self.val = None
412 self.cursor += 3
413 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200414 elif self.tok == '\n':
415 if self.cursor == len(self.src):
416 self.tok = None
417 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800418 self.line += 1
419 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200420 elif not self.tok.isspace():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100421 raise QAPIParseError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500422
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200423 def get_members(self):
424 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200425 if self.tok == '}':
426 self.accept()
427 return expr
428 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100429 raise QAPIParseError(self, 'Expected string or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200430 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200431 key = self.val
432 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200433 if self.tok != ':':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100434 raise QAPIParseError(self, 'Expected ":"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200435 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800436 if key in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100437 raise QAPIParseError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200438 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200439 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200440 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200441 return expr
442 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100443 raise QAPIParseError(self, 'Expected "," or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200444 self.accept()
445 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100446 raise QAPIParseError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500447
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200448 def get_values(self):
449 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200450 if self.tok == ']':
451 self.accept()
452 return expr
Eric Blake437db252015-09-29 16:21:02 -0600453 if self.tok not in "{['tfn":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100454 raise QAPIParseError(self, 'Expected "{", "[", "]", string, '
455 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200456 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200457 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200458 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200459 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200460 return expr
461 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100462 raise QAPIParseError(self, 'Expected "," or "]"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200463 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500464
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200465 def get_expr(self, nested):
466 if self.tok != '{' and not nested:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100467 raise QAPIParseError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200468 if self.tok == '{':
469 self.accept()
470 expr = self.get_members()
471 elif self.tok == '[':
472 self.accept()
473 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600474 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200475 expr = self.val
476 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200477 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100478 raise QAPIParseError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200479 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200480
Marc-André Lureau3313b612017-01-13 15:41:29 +0100481 def get_doc(self, info):
482 if self.val != '##':
483 raise QAPIParseError(self, "Junk after '##' at start of "
484 "documentation comment")
485
486 doc = QAPIDoc(self, info)
487 self.accept(False)
488 while self.tok == '#':
489 if self.val.startswith('##'):
490 # End of doc comment
491 if self.val != '##':
492 raise QAPIParseError(self, "Junk after '##' at end of "
493 "documentation comment")
494 self.accept()
495 return doc
496 else:
497 doc.append(self.val)
498 self.accept(False)
499
500 raise QAPIParseError(self, "Documentation comment must end with '##'")
501
502
Markus Armbruster00e4b282015-06-10 10:04:36 +0200503#
504# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200505# TODO fold into QAPISchema
506# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200507#
508
Eric Blake437db252015-09-29 16:21:02 -0600509
Eric Blake14f00c62016-03-03 09:16:43 -0700510def find_base_members(base):
Eric Blakeac4338f2016-03-17 16:48:39 -0600511 if isinstance(base, dict):
512 return base
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800513 base_struct_define = find_struct(base)
514 if not base_struct_define:
515 return None
516 return base_struct_define['data']
517
Eric Blake437db252015-09-29 16:21:02 -0600518
Eric Blake811d04f2015-05-04 09:05:10 -0600519# Return the qtype of an alternate branch, or None on error.
520def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600521 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600522 return builtin_types[qapi_type]
523 elif find_struct(qapi_type):
524 return "QTYPE_QDICT"
525 elif find_enum(qapi_type):
526 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600527 elif find_union(qapi_type):
528 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600529 return None
530
Eric Blake437db252015-09-29 16:21:02 -0600531
Wenchao Xiabceae762014-03-06 17:08:56 -0800532# Return the discriminator enum define if discriminator is specified as an
533# enum type, otherwise return None.
534def discriminator_find_enum_define(expr):
535 base = expr.get('base')
536 discriminator = expr.get('discriminator')
537
538 if not (discriminator and base):
539 return None
540
Eric Blake14f00c62016-03-03 09:16:43 -0700541 base_members = find_base_members(base)
542 if not base_members:
Wenchao Xiabceae762014-03-06 17:08:56 -0800543 return None
544
Eric Blake14f00c62016-03-03 09:16:43 -0700545 discriminator_type = base_members.get(discriminator)
Wenchao Xiabceae762014-03-06 17:08:56 -0800546 if not discriminator_type:
547 return None
548
549 return find_enum(discriminator_type)
550
Eric Blake437db252015-09-29 16:21:02 -0600551
Eric Blake59a92fe2015-11-18 01:52:56 -0700552# Names must be letters, numbers, -, and _. They must start with letter,
553# except for downstream extensions which must start with __RFQDN_.
554# Dots are only valid in the downstream extension prefix.
555valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
556 '[a-zA-Z][a-zA-Z0-9_-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600557
558
Marc-André Lureau4148c292017-01-13 15:41:25 +0100559def check_name(info, source, name, allow_optional=False,
Eric Blake437db252015-09-29 16:21:02 -0600560 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600561 global valid_name
562 membername = name
563
564 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100565 raise QAPISemError(info, "%s requires a string name" % source)
Eric Blakec9e0a792015-05-04 09:05:22 -0600566 if name.startswith('*'):
567 membername = name[1:]
568 if not allow_optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100569 raise QAPISemError(info, "%s does not allow optional name '%s'"
570 % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600571 # Enum members can start with a digit, because the generated C
572 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700573 if enum_member and membername[0].isdigit():
574 membername = 'D' + membername
Eric Blake75996972016-03-17 16:48:29 -0600575 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
576 # and 'q_obj_*' implicit type names.
Eric Blake9fb081e2015-10-26 16:34:44 -0600577 if not valid_name.match(membername) or \
578 c_name(membername, False).startswith('q_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100579 raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600580
Eric Blake437db252015-09-29 16:21:02 -0600581
582def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200583 global all_names
584 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200585 # FIXME should reject names that differ only in '_' vs. '.'
586 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200587 if name in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100588 raise QAPISemError(info, "%s '%s' is already defined"
589 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600590 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100591 raise QAPISemError(info, "%s '%s' should not end in '%s'"
592 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200593 all_names[name] = meta
594
Eric Blake437db252015-09-29 16:21:02 -0600595
Markus Armbruster00e4b282015-06-10 10:04:36 +0200596def add_struct(definition, info):
597 global struct_types
598 name = definition['struct']
599 add_name(name, info, 'struct')
600 struct_types.append(definition)
601
Eric Blake437db252015-09-29 16:21:02 -0600602
Markus Armbruster00e4b282015-06-10 10:04:36 +0200603def find_struct(name):
604 global struct_types
605 for struct in struct_types:
606 if struct['struct'] == name:
607 return struct
608 return None
609
Eric Blake437db252015-09-29 16:21:02 -0600610
Markus Armbruster00e4b282015-06-10 10:04:36 +0200611def add_union(definition, info):
612 global union_types
613 name = definition['union']
614 add_name(name, info, 'union')
615 union_types.append(definition)
616
Eric Blake437db252015-09-29 16:21:02 -0600617
Markus Armbruster00e4b282015-06-10 10:04:36 +0200618def find_union(name):
619 global union_types
620 for union in union_types:
621 if union['union'] == name:
622 return union
623 return None
624
Eric Blake437db252015-09-29 16:21:02 -0600625
626def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200627 global enum_types
628 add_name(name, info, 'enum', implicit)
629 enum_types.append({"enum_name": name, "enum_values": enum_values})
630
Eric Blake437db252015-09-29 16:21:02 -0600631
Markus Armbruster00e4b282015-06-10 10:04:36 +0200632def find_enum(name):
633 global enum_types
634 for enum in enum_types:
635 if enum['enum_name'] == name:
636 return enum
637 return None
638
Markus Armbruster00e4b282015-06-10 10:04:36 +0200639
Eric Blake437db252015-09-29 16:21:02 -0600640def is_enum(name):
641 return find_enum(name) is not None
642
643
Marc-André Lureau4148c292017-01-13 15:41:25 +0100644def check_type(info, source, value, allow_array=False,
Eric Blake437db252015-09-29 16:21:02 -0600645 allow_dict=False, allow_optional=False,
646 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600647 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600648
649 if value is None:
650 return
651
Eric Blakedd883c62015-05-04 09:05:21 -0600652 # Check if array type for value is okay
653 if isinstance(value, list):
654 if not allow_array:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100655 raise QAPISemError(info, "%s cannot be an array" % source)
Eric Blakedd883c62015-05-04 09:05:21 -0600656 if len(value) != 1 or not isinstance(value[0], str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100657 raise QAPISemError(info,
658 "%s: array type must contain single type name" %
659 source)
Eric Blakedd883c62015-05-04 09:05:21 -0600660 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600661
662 # Check if type name for value is okay
663 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600664 if value not in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100665 raise QAPISemError(info, "%s uses unknown type '%s'"
666 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600667 if not all_names[value] in allow_metas:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100668 raise QAPISemError(info, "%s cannot use %s type '%s'" %
669 (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600670 return
671
Eric Blakedd883c62015-05-04 09:05:21 -0600672 if not allow_dict:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100673 raise QAPISemError(info, "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200674
675 if not isinstance(value, OrderedDict):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100676 raise QAPISemError(info,
677 "%s should be a dictionary or type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200678
679 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600680 for (key, arg) in value.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100681 check_name(info, "Member of %s" % source, key,
Eric Blakec9e0a792015-05-04 09:05:22 -0600682 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600683 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100684 raise QAPISemError(info, "Member of %s uses reserved name '%s'"
685 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600686 # Todo: allow dictionaries to represent default values of
687 # an optional argument.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100688 check_type(info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200689 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600690 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600691 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600692
Eric Blake437db252015-09-29 16:21:02 -0600693
Marc-André Lureau4148c292017-01-13 15:41:25 +0100694def check_command(expr, info):
Eric Blakedd883c62015-05-04 09:05:21 -0600695 name = expr['command']
Eric Blakec8184082016-07-13 21:50:20 -0600696 boxed = expr.get('boxed', False)
Eric Blake2cbf0992015-05-04 09:05:24 -0600697
Eric Blakec8184082016-07-13 21:50:20 -0600698 args_meta = ['struct']
699 if boxed:
700 args_meta += ['union', 'alternate']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100701 check_type(info, "'data' for command '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600702 expr.get('data'), allow_dict=not boxed, allow_optional=True,
703 allow_metas=args_meta)
Eric Blake10d4d992015-05-04 09:05:23 -0600704 returns_meta = ['union', 'struct']
705 if name in returns_whitelist:
706 returns_meta += ['built-in', 'alternate', 'enum']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100707 check_type(info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200708 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200709 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600710
Eric Blake437db252015-09-29 16:21:02 -0600711
Marc-André Lureau4148c292017-01-13 15:41:25 +0100712def check_event(expr, info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600713 global events
714 name = expr['event']
Eric Blakec8184082016-07-13 21:50:20 -0600715 boxed = expr.get('boxed', False)
Eric Blake4dc2e692015-05-04 09:05:17 -0600716
Eric Blakec8184082016-07-13 21:50:20 -0600717 meta = ['struct']
718 if boxed:
719 meta += ['union', 'alternate']
Eric Blake4dc2e692015-05-04 09:05:17 -0600720 events.append(name)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100721 check_type(info, "'data' for event '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600722 expr.get('data'), allow_dict=not boxed, allow_optional=True,
723 allow_metas=meta)
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200724
Eric Blake437db252015-09-29 16:21:02 -0600725
Marc-André Lureau4148c292017-01-13 15:41:25 +0100726def check_union(expr, info):
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800727 name = expr['union']
728 base = expr.get('base')
729 discriminator = expr.get('discriminator')
730 members = expr['data']
731
Eric Blake811d04f2015-05-04 09:05:10 -0600732 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600733
734 # With no discriminator it is a simple union.
735 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600736 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600737 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600738 if base is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100739 raise QAPISemError(info, "Simple union '%s' must not have a base" %
740 name)
Eric Blake44bd1272015-05-04 09:05:08 -0600741
742 # Else, it's a flat union.
743 else:
Eric Blakeac4338f2016-03-17 16:48:39 -0600744 # The object must have a string or dictionary 'base'.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100745 check_type(info, "'base' for union '%s'" % name,
Eric Blakeac4338f2016-03-17 16:48:39 -0600746 base, allow_dict=True, allow_optional=True,
747 allow_metas=['struct'])
Eric Blake376863e2015-09-29 16:21:07 -0600748 if not base:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100749 raise QAPISemError(info, "Flat union '%s' must have a base"
750 % name)
Eric Blake14f00c62016-03-03 09:16:43 -0700751 base_members = find_base_members(base)
752 assert base_members
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800753
Eric Blakec9e0a792015-05-04 09:05:22 -0600754 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600755 # member of the base struct.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100756 check_name(info, "Discriminator of flat union '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600757 discriminator)
Eric Blake14f00c62016-03-03 09:16:43 -0700758 discriminator_type = base_members.get(discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800759 if not discriminator_type:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100760 raise QAPISemError(info,
761 "Discriminator '%s' is not a member of base "
762 "struct '%s'"
763 % (discriminator, base))
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800764 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600765 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800766 # Do not allow string discriminator
767 if not enum_define:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100768 raise QAPISemError(info,
769 "Discriminator '%s' must be of enumeration "
770 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800771
Eric Blake02a57ae2016-02-17 23:48:16 -0700772 # Check every branch; don't allow an empty union
773 if len(members) == 0:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100774 raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800775 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100776 check_name(info, "Member of union '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600777
Eric Blake01cfbaa2015-12-01 22:20:58 -0700778 # Each value must name a known type
Marc-André Lureau4148c292017-01-13 15:41:25 +0100779 check_type(info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200780 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600781
Eric Blake44bd1272015-05-04 09:05:08 -0600782 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700783 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600784 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600785 if key not in enum_define['enum_values']:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100786 raise QAPISemError(info,
787 "Discriminator value '%s' is not found in "
788 "enum '%s'"
789 % (key, enum_define["enum_name"]))
Eric Blake44bd1272015-05-04 09:05:08 -0600790
Eric Blaked0b18232016-07-13 21:50:13 -0600791 # If discriminator is user-defined, ensure all values are covered
792 if enum_define:
793 for value in enum_define['enum_values']:
794 if value not in members.keys():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100795 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
796 % (name, value))
Eric Blaked0b18232016-07-13 21:50:13 -0600797
Eric Blake437db252015-09-29 16:21:02 -0600798
Marc-André Lureau4148c292017-01-13 15:41:25 +0100799def check_alternate(expr, info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600800 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600801 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600802 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600803
Eric Blake02a57ae2016-02-17 23:48:16 -0700804 # Check every branch; require at least two branches
805 if len(members) < 2:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100806 raise QAPISemError(info,
807 "Alternate '%s' should have at least two branches "
808 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600809 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100810 check_name(info, "Member of alternate '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600811
Eric Blake811d04f2015-05-04 09:05:10 -0600812 # Ensure alternates have no type conflicts.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100813 check_type(info, "Member '%s' of alternate '%s'" % (key, name),
Eric Blakedd883c62015-05-04 09:05:21 -0600814 value,
815 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600816 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700817 if not qtype:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100818 raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
819 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600820 if qtype in types_seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100821 raise QAPISemError(info, "Alternate '%s' member '%s' can't "
822 "be distinguished from member '%s'"
823 % (name, key, types_seen[qtype]))
Eric Blake811d04f2015-05-04 09:05:10 -0600824 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800825
Eric Blake437db252015-09-29 16:21:02 -0600826
Marc-André Lureau4148c292017-01-13 15:41:25 +0100827def check_enum(expr, info):
Eric Blakecf393592015-05-04 09:05:04 -0600828 name = expr['enum']
829 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100830 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600831
832 if not isinstance(members, list):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100833 raise QAPISemError(info,
834 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100835 if prefix is not None and not isinstance(prefix, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100836 raise QAPISemError(info,
837 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600838 for member in members:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100839 check_name(info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600840 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600841
Eric Blake437db252015-09-29 16:21:02 -0600842
Marc-André Lureau4148c292017-01-13 15:41:25 +0100843def check_struct(expr, info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600844 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600845 members = expr['data']
846
Marc-André Lureau4148c292017-01-13 15:41:25 +0100847 check_type(info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600848 allow_dict=True, allow_optional=True)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100849 check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600850 allow_metas=['struct'])
851
Eric Blake437db252015-09-29 16:21:02 -0600852
Eric Blake0545f6b2015-05-04 09:05:15 -0600853def check_keys(expr_elem, meta, required, optional=[]):
854 expr = expr_elem['expr']
855 info = expr_elem['info']
856 name = expr[meta]
857 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100858 raise QAPISemError(info, "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600859 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600860 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600861 if key not in required and key not in optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100862 raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
863 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600864 if (key == 'gen' or key == 'success-response') and value is not False:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100865 raise QAPISemError(info,
866 "'%s' of %s '%s' should only use false value"
867 % (key, meta, name))
Eric Blakec8184082016-07-13 21:50:20 -0600868 if key == 'boxed' and value is not True:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100869 raise QAPISemError(info,
870 "'%s' of %s '%s' should only use true value"
871 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600872 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600873 if key not in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100874 raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
875 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600876
Eric Blake437db252015-09-29 16:21:02 -0600877
Markus Armbruster4d076d62015-06-10 08:55:21 +0200878def check_exprs(exprs):
879 global all_names
880
881 # Learn the types and check for valid expression keys
882 for builtin in builtin_types.keys():
883 all_names[builtin] = 'built-in'
884 for expr_elem in exprs:
885 expr = expr_elem['expr']
886 info = expr_elem['info']
Marc-André Lureau3313b612017-01-13 15:41:29 +0100887
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100888 if 'doc' not in expr_elem and doc_required:
Marc-André Lureau3313b612017-01-13 15:41:29 +0100889 raise QAPISemError(info,
890 "Expression missing documentation comment")
891
Eric Blake437db252015-09-29 16:21:02 -0600892 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100893 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200894 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600895 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200896 check_keys(expr_elem, 'union', ['data'],
897 ['base', 'discriminator'])
898 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600899 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200900 check_keys(expr_elem, 'alternate', ['data'])
901 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600902 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200903 check_keys(expr_elem, 'struct', ['data'], ['base'])
904 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600905 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200906 check_keys(expr_elem, 'command', [],
Eric Blakec8184082016-07-13 21:50:20 -0600907 ['data', 'returns', 'gen', 'success-response', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200908 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600909 elif 'event' in expr:
Eric Blakec8184082016-07-13 21:50:20 -0600910 check_keys(expr_elem, 'event', [], ['data', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200911 add_name(expr['event'], info, 'event')
912 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100913 raise QAPISemError(expr_elem['info'],
914 "Expression is missing metatype")
Markus Armbruster4d076d62015-06-10 08:55:21 +0200915
916 # Try again for hidden UnionKind enum
917 for expr_elem in exprs:
918 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600919 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200920 if not discriminator_find_enum_define(expr):
921 add_enum('%sKind' % expr['union'], expr_elem['info'],
922 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600923 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200924 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
925 implicit=True)
926
927 # Validate that exprs make sense
928 for expr_elem in exprs:
929 expr = expr_elem['expr']
930 info = expr_elem['info']
931
Eric Blake437db252015-09-29 16:21:02 -0600932 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200933 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600934 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200935 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600936 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200937 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600938 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200939 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600940 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200941 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600942 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200943 check_event(expr, info)
944 else:
945 assert False, 'unexpected meta type'
946
Markus Armbrusterac882192015-09-16 13:06:05 +0200947 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600948
Markus Armbrusterac882192015-09-16 13:06:05 +0200949
Marc-André Lureau3313b612017-01-13 15:41:29 +0100950def check_freeform_doc(doc):
951 if doc.symbol:
952 raise QAPISemError(doc.info,
953 "Documention for '%s' is not followed"
954 " by the definition" % doc.symbol)
955
956 body = str(doc.body)
957 if re.search(r'@\S+:', body, re.MULTILINE):
958 raise QAPISemError(doc.info,
959 "Free-form documentation block must not contain"
960 " @NAME: sections")
961
962
963def check_definition_doc(doc, expr, info):
964 for i in ('enum', 'union', 'alternate', 'struct', 'command', 'event'):
965 if i in expr:
966 meta = i
967 break
968
969 name = expr[meta]
970 if doc.symbol != name:
971 raise QAPISemError(info, "Definition of '%s' follows documentation"
972 " for '%s'" % (name, doc.symbol))
973 if doc.has_section('Returns') and 'command' not in expr:
974 raise QAPISemError(info, "'Returns:' is only valid for commands")
975
976 if meta == 'union':
977 args = expr.get('base', [])
978 else:
979 args = expr.get('data', [])
980 if isinstance(args, str):
981 return
982 if isinstance(args, dict):
983 args = args.keys()
984 assert isinstance(args, list)
985
986 if (meta == 'alternate'
987 or (meta == 'union' and not expr.get('discriminator'))):
988 args.append('type')
989
990 for arg in args:
991 if arg[0] == '*':
992 opt = True
993 desc = doc.args.get(arg[1:])
994 else:
995 opt = False
996 desc = doc.args.get(arg)
997 if not desc:
998 continue
999 desc_opt = "#optional" in str(desc)
1000 if desc_opt and not opt:
1001 raise QAPISemError(info, "Description has #optional, "
1002 "but the declaration doesn't")
1003 if not desc_opt and opt:
1004 # silently fix the doc
1005 # TODO either fix the schema and make this an error,
1006 # or drop #optional entirely
1007 desc.append("#optional")
1008
1009 doc_args = set(doc.args.keys())
1010 args = set([name.strip('*') for name in args])
1011 if not doc_args.issubset(args):
1012 raise QAPISemError(info, "The following documented members are not in "
1013 "the declaration: %s" % ", ".join(doc_args - args))
1014
1015
1016def check_docs(docs):
1017 for doc in docs:
1018 for section in doc.args.values() + doc.sections:
1019 content = str(section)
1020 if not content or content.isspace():
1021 raise QAPISemError(doc.info,
1022 "Empty doc section '%s'" % section.name)
1023
1024 if not doc.expr:
1025 check_freeform_doc(doc)
1026 else:
1027 check_definition_doc(doc, doc.expr, doc.info)
1028
1029 return docs
1030
1031
Markus Armbrusterac882192015-09-16 13:06:05 +02001032#
1033# Schema compiler frontend
1034#
1035
1036class QAPISchemaEntity(object):
1037 def __init__(self, name, info):
1038 assert isinstance(name, str)
1039 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -06001040 # For explicitly defined entities, info points to the (explicit)
1041 # definition. For builtins (and their arrays), info is None.
1042 # For implicitly defined entities, info points to a place that
1043 # triggered the implicit definition (there may be more than one
1044 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +02001045 self.info = info
1046
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001047 def c_name(self):
1048 return c_name(self.name)
1049
Markus Armbrusterac882192015-09-16 13:06:05 +02001050 def check(self, schema):
1051 pass
1052
Eric Blake49823c42015-10-12 22:22:27 -06001053 def is_implicit(self):
1054 return not self.info
1055
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001056 def visit(self, visitor):
1057 pass
1058
1059
1060class QAPISchemaVisitor(object):
1061 def visit_begin(self, schema):
1062 pass
1063
1064 def visit_end(self):
1065 pass
1066
Eric Blake25a0d9c2015-10-12 22:22:21 -06001067 def visit_needed(self, entity):
1068 # Default to visiting everything
1069 return True
1070
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001071 def visit_builtin_type(self, name, info, json_type):
1072 pass
1073
1074 def visit_enum_type(self, name, info, values, prefix):
1075 pass
1076
1077 def visit_array_type(self, name, info, element_type):
1078 pass
1079
1080 def visit_object_type(self, name, info, base, members, variants):
1081 pass
1082
Markus Armbruster39a18152015-09-16 13:06:28 +02001083 def visit_object_type_flat(self, name, info, members, variants):
1084 pass
1085
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001086 def visit_alternate_type(self, name, info, variants):
1087 pass
1088
1089 def visit_command(self, name, info, arg_type, ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001090 gen, success_response, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001091 pass
1092
Eric Blake48825ca2016-07-13 21:50:19 -06001093 def visit_event(self, name, info, arg_type, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001094 pass
1095
Markus Armbrusterac882192015-09-16 13:06:05 +02001096
1097class QAPISchemaType(QAPISchemaEntity):
Eric Blake4040d992016-03-17 16:48:28 -06001098 # Return the C type for common use.
1099 # For the types we commonly box, this is a pointer type.
1100 def c_type(self):
1101 pass
1102
1103 # Return the C type to be used in a parameter list.
1104 def c_param_type(self):
1105 return self.c_type()
1106
1107 # Return the C type to be used where we suppress boxing.
1108 def c_unboxed_type(self):
1109 return self.c_type()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001110
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001111 def json_type(self):
1112 pass
1113
1114 def alternate_qtype(self):
1115 json2qtype = {
1116 'string': 'QTYPE_QSTRING',
1117 'number': 'QTYPE_QFLOAT',
1118 'int': 'QTYPE_QINT',
1119 'boolean': 'QTYPE_QBOOL',
1120 'object': 'QTYPE_QDICT'
1121 }
1122 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +02001123
1124
1125class QAPISchemaBuiltinType(QAPISchemaType):
Eric Blake861877a2016-03-17 16:48:36 -06001126 def __init__(self, name, json_type, c_type):
Markus Armbrusterac882192015-09-16 13:06:05 +02001127 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001128 assert not c_type or isinstance(c_type, str)
1129 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
1130 'value')
1131 self._json_type_name = json_type
1132 self._c_type_name = c_type
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001133
1134 def c_name(self):
1135 return self.name
1136
Eric Blake4040d992016-03-17 16:48:28 -06001137 def c_type(self):
1138 return self._c_type_name
1139
1140 def c_param_type(self):
1141 if self.name == 'str':
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001142 return 'const ' + self._c_type_name
1143 return self._c_type_name
1144
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001145 def json_type(self):
1146 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +02001147
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001148 def visit(self, visitor):
1149 visitor.visit_builtin_type(self.name, self.info, self.json_type())
1150
Markus Armbrusterac882192015-09-16 13:06:05 +02001151
1152class QAPISchemaEnumType(QAPISchemaType):
1153 def __init__(self, name, info, values, prefix):
1154 QAPISchemaType.__init__(self, name, info)
1155 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -07001156 assert isinstance(v, QAPISchemaMember)
1157 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001158 assert prefix is None or isinstance(prefix, str)
1159 self.values = values
1160 self.prefix = prefix
1161
1162 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -07001163 seen = {}
1164 for v in self.values:
1165 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001166
Eric Blake99df5282015-10-12 22:22:32 -06001167 def is_implicit(self):
1168 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -06001169 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -06001170
Eric Blake4040d992016-03-17 16:48:28 -06001171 def c_type(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001172 return c_name(self.name)
1173
Eric Blake93bda4d2015-12-01 22:20:55 -07001174 def member_names(self):
1175 return [v.name for v in self.values]
1176
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001177 def json_type(self):
1178 return 'string'
1179
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001180 def visit(self, visitor):
1181 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -07001182 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001183
Markus Armbrusterac882192015-09-16 13:06:05 +02001184
1185class QAPISchemaArrayType(QAPISchemaType):
1186 def __init__(self, name, info, element_type):
1187 QAPISchemaType.__init__(self, name, info)
1188 assert isinstance(element_type, str)
1189 self._element_type_name = element_type
1190 self.element_type = None
1191
1192 def check(self, schema):
1193 self.element_type = schema.lookup_type(self._element_type_name)
1194 assert self.element_type
1195
Eric Blake99df5282015-10-12 22:22:32 -06001196 def is_implicit(self):
1197 return True
1198
Eric Blake4040d992016-03-17 16:48:28 -06001199 def c_type(self):
1200 return c_name(self.name) + pointer_suffix
1201
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001202 def json_type(self):
1203 return 'array'
1204
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001205 def visit(self, visitor):
1206 visitor.visit_array_type(self.name, self.info, self.element_type)
1207
Markus Armbrusterac882192015-09-16 13:06:05 +02001208
1209class QAPISchemaObjectType(QAPISchemaType):
1210 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -07001211 # struct has local_members, optional base, and no variants
1212 # flat union has base, variants, and no local_members
1213 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +02001214 QAPISchemaType.__init__(self, name, info)
1215 assert base is None or isinstance(base, str)
1216 for m in local_members:
1217 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -07001218 m.set_owner(name)
1219 if variants is not None:
1220 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1221 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001222 self._base_name = base
1223 self.base = None
1224 self.local_members = local_members
1225 self.variants = variants
1226 self.members = None
1227
1228 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -07001229 if self.members is False: # check for cycles
Marc-André Lureau4148c292017-01-13 15:41:25 +01001230 raise QAPISemError(self.info,
1231 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001232 if self.members:
1233 return
1234 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -07001235 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +02001236 if self._base_name:
1237 self.base = schema.lookup_type(self._base_name)
1238 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +02001239 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001240 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001241 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001242 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001243 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001244 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +02001245 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001246 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001247 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -07001248 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001249
Eric Blake14f00c62016-03-03 09:16:43 -07001250 # Check that the members of this type do not cause duplicate JSON members,
Eric Blake27b60ab2015-11-18 01:52:51 -07001251 # and update seen to track the members seen so far. Report any errors
1252 # on behalf of info, which is not necessarily self.info
1253 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -07001254 assert not self.variants # not implemented
1255 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -07001256 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -07001257
Eric Blake99df5282015-10-12 22:22:32 -06001258 def is_implicit(self):
Eric Blake75996972016-03-17 16:48:29 -06001259 # See QAPISchema._make_implicit_object_type(), as well as
1260 # _def_predefineds()
1261 return self.name.startswith('q_')
Eric Blake99df5282015-10-12 22:22:32 -06001262
Eric Blakeb6167702016-07-13 21:50:16 -06001263 def is_empty(self):
1264 assert self.members is not None
1265 return not self.members and not self.variants
1266
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001267 def c_name(self):
Eric Blakecd50a252016-07-13 21:50:14 -06001268 assert self.name != 'q_empty'
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001269 return QAPISchemaType.c_name(self)
1270
Eric Blake4040d992016-03-17 16:48:28 -06001271 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001272 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -07001273 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001274
Eric Blake4040d992016-03-17 16:48:28 -06001275 def c_unboxed_type(self):
Eric Blake4040d992016-03-17 16:48:28 -06001276 return c_name(self.name)
1277
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001278 def json_type(self):
1279 return 'object'
1280
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001281 def visit(self, visitor):
1282 visitor.visit_object_type(self.name, self.info,
1283 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001284 visitor.visit_object_type_flat(self.name, self.info,
1285 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001286
Markus Armbrusterac882192015-09-16 13:06:05 +02001287
Eric Blaked44f9ac2015-12-01 22:20:54 -07001288class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001289 role = 'member'
1290
Eric Blaked44f9ac2015-12-01 22:20:54 -07001291 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001292 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001293 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001294 self.owner = None
1295
1296 def set_owner(self, name):
1297 assert not self.owner
1298 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001299
Eric Blake27b60ab2015-11-18 01:52:51 -07001300 def check_clash(self, info, seen):
1301 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001302 if cname.lower() != cname and self.owner not in case_whitelist:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001303 raise QAPISemError(info,
1304 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001305 if cname in seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001306 raise QAPISemError(info, "%s collides with %s" %
1307 (self.describe(), seen[cname].describe()))
Eric Blake27b60ab2015-11-18 01:52:51 -07001308 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001309
Eric Blake88d4ef82015-11-18 01:52:50 -07001310 def _pretty_owner(self):
1311 owner = self.owner
Eric Blake75996972016-03-17 16:48:29 -06001312 if owner.startswith('q_obj_'):
Eric Blake88d4ef82015-11-18 01:52:50 -07001313 # See QAPISchema._make_implicit_object_type() - reverse the
1314 # mapping there to create a nice human-readable description
Eric Blake75996972016-03-17 16:48:29 -06001315 owner = owner[6:]
Eric Blake88d4ef82015-11-18 01:52:50 -07001316 if owner.endswith('-arg'):
1317 return '(parameter of %s)' % owner[:-4]
Eric Blakeac4338f2016-03-17 16:48:39 -06001318 elif owner.endswith('-base'):
1319 return '(base of %s)' % owner[:-5]
Eric Blake88d4ef82015-11-18 01:52:50 -07001320 else:
1321 assert owner.endswith('-wrapper')
1322 # Unreachable and not implemented
1323 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001324 if owner.endswith('Kind'):
1325 # See QAPISchema._make_implicit_enum_type()
1326 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001327 return '(%s of %s)' % (self.role, owner)
1328
1329 def describe(self):
1330 return "'%s' %s" % (self.name, self._pretty_owner())
1331
Markus Armbrusterac882192015-09-16 13:06:05 +02001332
Eric Blaked44f9ac2015-12-01 22:20:54 -07001333class QAPISchemaObjectTypeMember(QAPISchemaMember):
1334 def __init__(self, name, typ, optional):
1335 QAPISchemaMember.__init__(self, name)
1336 assert isinstance(typ, str)
1337 assert isinstance(optional, bool)
1338 self._type_name = typ
1339 self.type = None
1340 self.optional = optional
1341
1342 def check(self, schema):
1343 assert self.owner
1344 self.type = schema.lookup_type(self._type_name)
1345 assert self.type
1346
1347
Markus Armbrusterac882192015-09-16 13:06:05 +02001348class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001349 def __init__(self, tag_name, tag_member, variants):
1350 # Flat unions pass tag_name but not tag_member.
1351 # Simple unions and alternates pass tag_member but not tag_name.
1352 # After check(), tag_member is always set, and tag_name remains
1353 # a reliable witness of being used by a flat union.
1354 assert bool(tag_member) != bool(tag_name)
1355 assert (isinstance(tag_name, str) or
1356 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001357 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001358 for v in variants:
1359 assert isinstance(v, QAPISchemaObjectTypeVariant)
Eric Blakeda9cb192016-07-13 21:50:15 -06001360 self._tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001361 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001362 self.variants = variants
1363
Eric Blake88d4ef82015-11-18 01:52:50 -07001364 def set_owner(self, name):
1365 for v in self.variants:
1366 v.set_owner(name)
1367
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001368 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001369 if not self.tag_member: # flat union
Eric Blakeda9cb192016-07-13 21:50:15 -06001370 self.tag_member = seen[c_name(self._tag_name)]
1371 assert self._tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001372 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1373 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001374 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001375 # Union names must match enum values; alternate names are
1376 # checked separately. Use 'seen' to tell the two apart.
1377 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001378 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001379 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001380 v.type.check(schema)
1381
Eric Blake27b60ab2015-11-18 01:52:51 -07001382 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001383 for v in self.variants:
1384 # Reset seen map for each variant, since qapi names from one
1385 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001386 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001387 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001388
Eric Blake437db252015-09-29 16:21:02 -06001389
Markus Armbrusterac882192015-09-16 13:06:05 +02001390class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001391 role = 'branch'
1392
Markus Armbrusterac882192015-09-16 13:06:05 +02001393 def __init__(self, name, typ):
1394 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1395
Markus Armbrusterac882192015-09-16 13:06:05 +02001396
1397class QAPISchemaAlternateType(QAPISchemaType):
1398 def __init__(self, name, info, variants):
1399 QAPISchemaType.__init__(self, name, info)
1400 assert isinstance(variants, QAPISchemaObjectTypeVariants)
Eric Blakeda9cb192016-07-13 21:50:15 -06001401 assert variants.tag_member
Eric Blake88d4ef82015-11-18 01:52:50 -07001402 variants.set_owner(name)
1403 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001404 self.variants = variants
1405
1406 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001407 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001408 # Not calling self.variants.check_clash(), because there's nothing
1409 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001410 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001411 # Alternate branch names have no relation to the tag enum values;
1412 # so we have to check for potential name collisions ourselves.
1413 seen = {}
1414 for v in self.variants.variants:
1415 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001416
Eric Blake4040d992016-03-17 16:48:28 -06001417 def c_type(self):
1418 return c_name(self.name) + pointer_suffix
1419
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001420 def json_type(self):
1421 return 'value'
1422
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001423 def visit(self, visitor):
1424 visitor.visit_alternate_type(self.name, self.info, self.variants)
1425
Eric Blakec8184082016-07-13 21:50:20 -06001426 def is_empty(self):
1427 return False
1428
Markus Armbrusterac882192015-09-16 13:06:05 +02001429
1430class QAPISchemaCommand(QAPISchemaEntity):
Eric Blake48825ca2016-07-13 21:50:19 -06001431 def __init__(self, name, info, arg_type, ret_type, gen, success_response,
1432 boxed):
Markus Armbrusterac882192015-09-16 13:06:05 +02001433 QAPISchemaEntity.__init__(self, name, info)
1434 assert not arg_type or isinstance(arg_type, str)
1435 assert not ret_type or isinstance(ret_type, str)
1436 self._arg_type_name = arg_type
1437 self.arg_type = None
1438 self._ret_type_name = ret_type
1439 self.ret_type = None
1440 self.gen = gen
1441 self.success_response = success_response
Eric Blake48825ca2016-07-13 21:50:19 -06001442 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001443
1444 def check(self, schema):
1445 if self._arg_type_name:
1446 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001447 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1448 isinstance(self.arg_type, QAPISchemaAlternateType))
1449 self.arg_type.check(schema)
1450 if self.boxed:
1451 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001452 raise QAPISemError(self.info,
1453 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001454 else:
1455 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1456 assert not self.arg_type.variants
1457 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001458 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001459 if self._ret_type_name:
1460 self.ret_type = schema.lookup_type(self._ret_type_name)
1461 assert isinstance(self.ret_type, QAPISchemaType)
1462
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001463 def visit(self, visitor):
1464 visitor.visit_command(self.name, self.info,
1465 self.arg_type, self.ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001466 self.gen, self.success_response, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001467
Markus Armbrusterac882192015-09-16 13:06:05 +02001468
1469class QAPISchemaEvent(QAPISchemaEntity):
Eric Blake48825ca2016-07-13 21:50:19 -06001470 def __init__(self, name, info, arg_type, boxed):
Markus Armbrusterac882192015-09-16 13:06:05 +02001471 QAPISchemaEntity.__init__(self, name, info)
1472 assert not arg_type or isinstance(arg_type, str)
1473 self._arg_type_name = arg_type
1474 self.arg_type = None
Eric Blake48825ca2016-07-13 21:50:19 -06001475 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001476
1477 def check(self, schema):
1478 if self._arg_type_name:
1479 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001480 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1481 isinstance(self.arg_type, QAPISchemaAlternateType))
1482 self.arg_type.check(schema)
1483 if self.boxed:
1484 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001485 raise QAPISemError(self.info,
1486 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001487 else:
1488 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1489 assert not self.arg_type.variants
1490 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001491 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001492
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001493 def visit(self, visitor):
Eric Blake48825ca2016-07-13 21:50:19 -06001494 visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001495
Markus Armbrusterac882192015-09-16 13:06:05 +02001496
1497class QAPISchema(object):
1498 def __init__(self, fname):
1499 try:
Marc-André Lureau3313b612017-01-13 15:41:29 +01001500 parser = QAPISchemaParser(open(fname, "r"))
1501 self.exprs = check_exprs(parser.exprs)
1502 self.docs = check_docs(parser.docs)
Eric Blake7618b912015-10-12 22:22:22 -06001503 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001504 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001505 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001506 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001507 self._def_exprs()
1508 self.check()
Marc-André Lureau4148c292017-01-13 15:41:25 +01001509 except QAPIError as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001510 print >>sys.stderr, err
1511 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001512
Markus Armbrusterac882192015-09-16 13:06:05 +02001513 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001514 # Only the predefined types are allowed to not have info
1515 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001516 assert ent.name not in self._entity_dict
1517 self._entity_dict[ent.name] = ent
1518
1519 def lookup_entity(self, name, typ=None):
1520 ent = self._entity_dict.get(name)
1521 if typ and not isinstance(ent, typ):
1522 return None
1523 return ent
1524
1525 def lookup_type(self, name):
1526 return self.lookup_entity(name, QAPISchemaType)
1527
Eric Blake861877a2016-03-17 16:48:36 -06001528 def _def_builtin_type(self, name, json_type, c_type):
1529 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001530 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1531 # qapi-types.h from a single .c, all arrays of builtins must be
1532 # declared in the first file whether or not they are used. Nicer
1533 # would be to use lazy instantiation, while figuring out how to
1534 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001535 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001536
1537 def _def_predefineds(self):
Eric Blake861877a2016-03-17 16:48:36 -06001538 for t in [('str', 'string', 'char' + pointer_suffix),
1539 ('number', 'number', 'double'),
1540 ('int', 'int', 'int64_t'),
1541 ('int8', 'int', 'int8_t'),
1542 ('int16', 'int', 'int16_t'),
1543 ('int32', 'int', 'int32_t'),
1544 ('int64', 'int', 'int64_t'),
1545 ('uint8', 'int', 'uint8_t'),
1546 ('uint16', 'int', 'uint16_t'),
1547 ('uint32', 'int', 'uint32_t'),
1548 ('uint64', 'int', 'uint64_t'),
1549 ('size', 'int', 'uint64_t'),
1550 ('bool', 'boolean', 'bool'),
1551 ('any', 'value', 'QObject' + pointer_suffix)]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001552 self._def_builtin_type(*t)
Eric Blake75996972016-03-17 16:48:29 -06001553 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1554 None, [], None)
Markus Armbruster39a18152015-09-16 13:06:28 +02001555 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001556 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1557 'qstring', 'qdict', 'qlist',
1558 'qfloat', 'qbool'])
1559 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001560 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001561
Eric Blake93bda4d2015-12-01 22:20:55 -07001562 def _make_enum_members(self, values):
1563 return [QAPISchemaMember(v) for v in values]
1564
Eric Blake99df5282015-10-12 22:22:32 -06001565 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001566 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001567 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001568 self._def_entity(QAPISchemaEnumType(
1569 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001570 return name
1571
Eric Blake99df5282015-10-12 22:22:32 -06001572 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001573 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001574 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001575 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001576 return name
1577
Eric Blake99df5282015-10-12 22:22:32 -06001578 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001579 if not members:
1580 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001581 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake75996972016-03-17 16:48:29 -06001582 name = 'q_obj_%s-%s' % (name, role)
Markus Armbrusterac882192015-09-16 13:06:05 +02001583 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001584 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001585 members, None))
1586 return name
1587
1588 def _def_enum_type(self, expr, info):
1589 name = expr['enum']
1590 data = expr['data']
1591 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001592 self._def_entity(QAPISchemaEnumType(
1593 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001594
Eric Blake99df5282015-10-12 22:22:32 -06001595 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001596 optional = False
1597 if name.startswith('*'):
1598 name = name[1:]
1599 optional = True
1600 if isinstance(typ, list):
1601 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001602 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001603 return QAPISchemaObjectTypeMember(name, typ, optional)
1604
Eric Blake99df5282015-10-12 22:22:32 -06001605 def _make_members(self, data, info):
1606 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001607 for (key, value) in data.iteritems()]
1608
1609 def _def_struct_type(self, expr, info):
1610 name = expr['struct']
1611 base = expr.get('base')
1612 data = expr['data']
1613 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001614 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001615 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001616
1617 def _make_variant(self, case, typ):
1618 return QAPISchemaObjectTypeVariant(case, typ)
1619
Eric Blake99df5282015-10-12 22:22:32 -06001620 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001621 if isinstance(typ, list):
1622 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001623 typ = self._make_array_type(typ[0], info)
1624 typ = self._make_implicit_object_type(
1625 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001626 return QAPISchemaObjectTypeVariant(case, typ)
1627
Markus Armbrusterac882192015-09-16 13:06:05 +02001628 def _def_union_type(self, expr, info):
1629 name = expr['union']
1630 data = expr['data']
1631 base = expr.get('base')
1632 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001633 tag_member = None
Eric Blakeac4338f2016-03-17 16:48:39 -06001634 if isinstance(base, dict):
1635 base = (self._make_implicit_object_type(
1636 name, info, 'base', self._make_members(base, info)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001637 if tag_name:
1638 variants = [self._make_variant(key, value)
1639 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001640 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001641 else:
Eric Blake99df5282015-10-12 22:22:32 -06001642 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001643 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001644 typ = self._make_implicit_enum_type(name, info,
1645 [v.name for v in variants])
1646 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001647 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001648 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001649 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001650 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001651 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001652 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001653
1654 def _def_alternate_type(self, expr, info):
1655 name = expr['alternate']
1656 data = expr['data']
1657 variants = [self._make_variant(key, value)
1658 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001659 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001660 self._def_entity(
1661 QAPISchemaAlternateType(name, info,
1662 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001663 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001664 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001665
1666 def _def_command(self, expr, info):
1667 name = expr['command']
1668 data = expr.get('data')
1669 rets = expr.get('returns')
1670 gen = expr.get('gen', True)
1671 success_response = expr.get('success-response', True)
Eric Blake48825ca2016-07-13 21:50:19 -06001672 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001673 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001674 data = self._make_implicit_object_type(
1675 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001676 if isinstance(rets, list):
1677 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001678 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001679 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
Eric Blake48825ca2016-07-13 21:50:19 -06001680 success_response, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001681
1682 def _def_event(self, expr, info):
1683 name = expr['event']
1684 data = expr.get('data')
Eric Blake48825ca2016-07-13 21:50:19 -06001685 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001686 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001687 data = self._make_implicit_object_type(
1688 name, info, 'arg', self._make_members(data, info))
Eric Blake48825ca2016-07-13 21:50:19 -06001689 self._def_entity(QAPISchemaEvent(name, info, data, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001690
1691 def _def_exprs(self):
1692 for expr_elem in self.exprs:
1693 expr = expr_elem['expr']
1694 info = expr_elem['info']
1695 if 'enum' in expr:
1696 self._def_enum_type(expr, info)
1697 elif 'struct' in expr:
1698 self._def_struct_type(expr, info)
1699 elif 'union' in expr:
1700 self._def_union_type(expr, info)
1701 elif 'alternate' in expr:
1702 self._def_alternate_type(expr, info)
1703 elif 'command' in expr:
1704 self._def_command(expr, info)
1705 elif 'event' in expr:
1706 self._def_event(expr, info)
1707 else:
1708 assert False
1709
1710 def check(self):
1711 for ent in self._entity_dict.values():
1712 ent.check(self)
1713
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001714 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001715 visitor.visit_begin(self)
1716 for (name, entity) in sorted(self._entity_dict.items()):
1717 if visitor.visit_needed(entity):
1718 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001719 visitor.visit_end()
1720
Markus Armbruster2caba362013-07-27 17:41:56 +02001721
Markus Armbruster00e4b282015-06-10 10:04:36 +02001722#
1723# Code generation helpers
1724#
1725
Michael Roth0f923be2011-07-19 14:50:39 -05001726def camel_case(name):
1727 new_name = ''
1728 first = True
1729 for ch in name:
1730 if ch in ['_', '-']:
1731 first = True
1732 elif first:
1733 new_name += ch.upper()
1734 first = False
1735 else:
1736 new_name += ch.lower()
1737 return new_name
1738
Eric Blake437db252015-09-29 16:21:02 -06001739
Markus Armbruster849bc532015-05-14 06:50:53 -06001740# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1741# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1742# ENUM24_Name -> ENUM24_NAME
1743def camel_to_upper(value):
1744 c_fun_str = c_name(value, False)
1745 if value.isupper():
1746 return c_fun_str
1747
1748 new_name = ''
1749 l = len(c_fun_str)
1750 for i in range(l):
1751 c = c_fun_str[i]
1752 # When c is upper and no "_" appears before, do more checks
1753 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001754 if i < l - 1 and c_fun_str[i + 1].islower():
1755 new_name += '_'
1756 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001757 new_name += '_'
1758 new_name += c
1759 return new_name.lstrip('_').upper()
1760
Eric Blake437db252015-09-29 16:21:02 -06001761
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001762def c_enum_const(type_name, const_name, prefix=None):
1763 if prefix is not None:
1764 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001765 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001766
Eric Blake18df5152015-05-14 06:50:48 -06001767c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001768
Eric Blake437db252015-09-29 16:21:02 -06001769
Eric Blakec6405b52015-05-14 06:50:55 -06001770# Map @name to a valid C identifier.
1771# If @protect, avoid returning certain ticklish identifiers (like
1772# C keywords) by prepending "q_".
1773#
1774# Used for converting 'name' from a 'name':'type' qapi definition
1775# into a generated struct member, as well as converting type names
1776# into substrings of a generated C function name.
1777# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1778# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001779def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001780 # ANSI X3J11/88-090, 3.1.1
1781 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001782 'default', 'do', 'double', 'else', 'enum', 'extern',
1783 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1784 'return', 'short', 'signed', 'sizeof', 'static',
1785 'struct', 'switch', 'typedef', 'union', 'unsigned',
1786 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001787 # ISO/IEC 9899:1999, 6.4.1
1788 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1789 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001790 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1791 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001792 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1793 # excluding _.*
1794 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001795 # C++ ISO/IEC 14882:2003 2.11
1796 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1797 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1798 'namespace', 'new', 'operator', 'private', 'protected',
1799 'public', 'reinterpret_cast', 'static_cast', 'template',
1800 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1801 'using', 'virtual', 'wchar_t',
1802 # alternative representations
1803 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1804 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001805 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001806 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001807 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001808 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1809 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001810 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001811 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001812
Amos Kong05dfb262014-06-10 19:25:53 +08001813eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001814pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001815
Eric Blake437db252015-09-29 16:21:02 -06001816
Michael Roth0f923be2011-07-19 14:50:39 -05001817def genindent(count):
1818 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001819 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001820 ret += " "
1821 return ret
1822
1823indent_level = 0
1824
Eric Blake437db252015-09-29 16:21:02 -06001825
Michael Roth0f923be2011-07-19 14:50:39 -05001826def push_indent(indent_amount=4):
1827 global indent_level
1828 indent_level += indent_amount
1829
Eric Blake437db252015-09-29 16:21:02 -06001830
Michael Roth0f923be2011-07-19 14:50:39 -05001831def pop_indent(indent_amount=4):
1832 global indent_level
1833 indent_level -= indent_amount
1834
Eric Blake437db252015-09-29 16:21:02 -06001835
Markus Armbruster77e703b2015-06-24 19:27:32 +02001836# Generate @code with @kwds interpolated.
1837# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001838def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001839 raw = code % kwds
1840 if indent_level:
1841 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001842 # re.subn() lacks flags support before Python 2.7, use re.compile()
1843 raw = re.subn(re.compile("^.", re.MULTILINE),
1844 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001845 raw = raw[0]
1846 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001847
Eric Blake437db252015-09-29 16:21:02 -06001848
Michael Roth0f923be2011-07-19 14:50:39 -05001849def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001850 if code[0] == '\n':
1851 code = code[1:]
1852 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001853
Michael Roth0f923be2011-07-19 14:50:39 -05001854
1855def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001856 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001857
Eric Blake437db252015-09-29 16:21:02 -06001858
Michael Rothc0afa9c2013-05-10 17:46:00 -05001859def guardstart(name):
1860 return mcgen('''
1861
1862#ifndef %(name)s
1863#define %(name)s
1864
1865''',
1866 name=guardname(name))
1867
Eric Blake437db252015-09-29 16:21:02 -06001868
Michael Rothc0afa9c2013-05-10 17:46:00 -05001869def guardend(name):
1870 return mcgen('''
1871
1872#endif /* %(name)s */
1873
1874''',
1875 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001876
Eric Blake437db252015-09-29 16:21:02 -06001877
Markus Armbrustere98859a2015-09-16 13:06:16 +02001878def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001879 ret = mcgen('''
1880
Markus Armbrustere98859a2015-09-16 13:06:16 +02001881const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001882''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001883 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001884 for value in values:
1885 index = c_enum_const(name, value, prefix)
1886 ret += mcgen('''
1887 [%(index)s] = "%(value)s",
1888''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001889 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001890
Eric Blake7fb1cf12015-11-18 01:52:57 -07001891 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001892 ret += mcgen('''
1893 [%(max_index)s] = NULL,
1894};
1895''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001896 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001897 return ret
1898
Eric Blake437db252015-09-29 16:21:02 -06001899
Markus Armbrustere98859a2015-09-16 13:06:16 +02001900def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001901 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001902 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001903
1904 ret = mcgen('''
1905
1906typedef enum %(c_name)s {
1907''',
1908 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001909
1910 i = 0
1911 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001912 ret += mcgen('''
1913 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001914''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001915 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001916 i=i)
1917 i += 1
1918
Markus Armbrustere98859a2015-09-16 13:06:16 +02001919 ret += mcgen('''
1920} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001921''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001922 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001923
Markus Armbrustere98859a2015-09-16 13:06:16 +02001924 ret += mcgen('''
1925
1926extern const char *const %(c_name)s_lookup[];
1927''',
1928 c_name=c_name(name))
1929 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001930
Eric Blake437db252015-09-29 16:21:02 -06001931
Eric Blake48825ca2016-07-13 21:50:19 -06001932def gen_params(arg_type, boxed, extra):
Markus Armbruster03b43672015-09-16 13:06:20 +02001933 if not arg_type:
Eric Blakec8184082016-07-13 21:50:20 -06001934 assert not boxed
Markus Armbruster03b43672015-09-16 13:06:20 +02001935 return extra
Markus Armbruster03b43672015-09-16 13:06:20 +02001936 ret = ''
1937 sep = ''
Eric Blake48825ca2016-07-13 21:50:19 -06001938 if boxed:
Eric Blakec8184082016-07-13 21:50:20 -06001939 ret += '%s arg' % arg_type.c_param_type()
1940 sep = ', '
Eric Blake48825ca2016-07-13 21:50:19 -06001941 else:
1942 assert not arg_type.variants
1943 for memb in arg_type.members:
1944 ret += sep
1945 sep = ', '
1946 if memb.optional:
1947 ret += 'bool has_%s, ' % c_name(memb.name)
1948 ret += '%s %s' % (memb.type.c_param_type(),
1949 c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001950 if extra:
1951 ret += sep + extra
1952 return ret
1953
Eric Blake1f353342015-09-29 16:21:13 -06001954
Markus Armbruster00e4b282015-06-10 10:04:36 +02001955#
1956# Common command line parsing
1957#
1958
Eric Blake437db252015-09-29 16:21:02 -06001959
1960def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001961
1962 try:
1963 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001964 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001965 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001966 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001967 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001968 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001969 sys.exit(1)
1970
1971 output_dir = ""
1972 prefix = ""
1973 do_c = False
1974 do_h = False
1975 extra_opts = []
1976
1977 for oa in opts:
1978 o, a = oa
1979 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001980 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1981 if match.end() != len(a):
1982 print >>sys.stderr, \
1983 "%s: 'funny character '%s' in argument of --prefix" \
1984 % (sys.argv[0], a[match.end()])
1985 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001986 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001987 elif o in ("-o", "--output-dir"):
1988 output_dir = a + "/"
1989 elif o in ("-c", "--source"):
1990 do_c = True
1991 elif o in ("-h", "--header"):
1992 do_h = True
1993 else:
1994 extra_opts.append(oa)
1995
1996 if not do_c and not do_h:
1997 do_c = True
1998 do_h = True
1999
Markus Armbruster16d80f62015-04-02 13:32:16 +02002000 if len(args) != 1:
2001 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02002002 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02002003 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02002004
Markus Armbruster54414042015-06-09 16:22:45 +02002005 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002006
Markus Armbruster00e4b282015-06-10 10:04:36 +02002007#
2008# Generate output files with boilerplate
2009#
2010
Eric Blake437db252015-09-29 16:21:02 -06002011
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002012def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
2013 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02002014 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002015 c_file = output_dir + prefix + c_file
2016 h_file = output_dir + prefix + h_file
2017
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02002018 if output_dir:
2019 try:
2020 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01002021 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02002022 if e.errno != errno.EEXIST:
2023 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002024
2025 def maybe_open(really, name, opt):
2026 if really:
2027 return open(name, opt)
2028 else:
2029 import StringIO
2030 return StringIO.StringIO()
2031
2032 fdef = maybe_open(do_c, c_file, 'w')
2033 fdecl = maybe_open(do_h, h_file, 'w')
2034
2035 fdef.write(mcgen('''
2036/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2037%(comment)s
2038''',
Eric Blake437db252015-09-29 16:21:02 -06002039 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002040
2041 fdecl.write(mcgen('''
2042/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2043%(comment)s
2044#ifndef %(guard)s
2045#define %(guard)s
2046
2047''',
Eric Blake437db252015-09-29 16:21:02 -06002048 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002049
2050 return (fdef, fdecl)
2051
Eric Blake437db252015-09-29 16:21:02 -06002052
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002053def close_output(fdef, fdecl):
2054 fdecl.write('''
2055#endif
2056''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002057 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002058 fdef.close()