blob: 345cde157ee17daa1e5dbf4b57c67a852539da7a [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
Eric Blake10d4d992015-05-04 09:05:23 -060040# Whitelist of commands allowed to return a non-dictionary
41returns_whitelist = [
42 # From QMP:
43 'human-monitor-command',
Markus Armbruster6eb39372015-09-16 13:06:25 +020044 'qom-get',
Eric Blake10d4d992015-05-04 09:05:23 -060045 'query-migrate-cache-size',
46 'query-tpm-models',
47 'query-tpm-types',
48 'ringbuf-read',
49
50 # From QGA:
51 'guest-file-open',
52 'guest-fsfreeze-freeze',
53 'guest-fsfreeze-freeze-list',
54 'guest-fsfreeze-status',
55 'guest-fsfreeze-thaw',
56 'guest-get-time',
57 'guest-set-vcpus',
58 'guest-sync',
59 'guest-sync-delimited',
Eric Blake10d4d992015-05-04 09:05:23 -060060]
61
Eric Blake893e1f22015-12-01 22:20:57 -070062# Whitelist of entities allowed to violate case conventions
63case_whitelist = [
64 # From QMP:
65 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
Eric Blake893e1f22015-12-01 22:20:57 -070066 'CpuInfoMIPS', # PC, visible through query-cpu
67 'CpuInfoTricore', # PC, visible through query-cpu
Eric Blake893e1f22015-12-01 22:20:57 -070068 'QapiErrorClass', # all members, visible through errors
69 'UuidInfo', # UUID, visible through query-uuid
70 'X86CPURegister32', # all members, visible indirectly through qom-get
Eric Blake3666a972016-03-17 16:48:40 -060071 'q_obj_CpuInfo-base', # CPU, visible through query-cpu
Eric Blake893e1f22015-12-01 22:20:57 -070072]
73
Eric Blake4dc2e692015-05-04 09:05:17 -060074enum_types = []
75struct_types = []
76union_types = []
77events = []
78all_names = {}
79
Markus Armbruster00e4b282015-06-10 10:04:36 +020080#
81# Parsing the schema into expressions
82#
83
Eric Blake437db252015-09-29 16:21:02 -060084
Lluís Vilanovaa719a272014-05-07 20:46:15 +020085def error_path(parent):
86 res = ""
87 while parent:
88 res = ("In file included from %s:%d:\n" % (parent['file'],
89 parent['line'])) + res
90 parent = parent['parent']
91 return res
92
Eric Blake437db252015-09-29 16:21:02 -060093
Marc-André Lureau4148c292017-01-13 15:41:25 +010094class QAPIError(Exception):
95 def __init__(self, fname, line, col, incl_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -060096 Exception.__init__(self)
Marc-André Lureau4148c292017-01-13 15:41:25 +010097 self.fname = fname
98 self.line = line
99 self.col = col
100 self.info = incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +0200101 self.msg = msg
Marc-André Lureau4148c292017-01-13 15:41:25 +0100102
103 def __str__(self):
104 loc = "%s:%d" % (self.fname, self.line)
105 if self.col is not None:
106 loc += ":%s" % self.col
107 return error_path(self.info) + "%s: %s" % (loc, self.msg)
108
109
110class QAPIParseError(QAPIError):
111 def __init__(self, parser, msg):
112 col = 1
113 for ch in parser.src[parser.line_pos:parser.pos]:
Wenchao Xia515b9432014-03-04 18:44:33 -0800114 if ch == '\t':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100115 col = (col + 7) % 8 + 1
Markus Armbruster2caba362013-07-27 17:41:56 +0200116 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100117 col += 1
118 QAPIError.__init__(self, parser.fname, parser.line, col,
119 parser.incl_info, msg)
Markus Armbruster2caba362013-07-27 17:41:56 +0200120
Eric Blake437db252015-09-29 16:21:02 -0600121
Marc-André Lureau4148c292017-01-13 15:41:25 +0100122class QAPISemError(QAPIError):
123 def __init__(self, info, msg):
124 QAPIError.__init__(self, info['file'], info['line'], None,
125 info['parent'], msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800126
Eric Blake437db252015-09-29 16:21:02 -0600127
Marc-André Lureau3313b612017-01-13 15:41:29 +0100128class QAPIDoc(object):
129 class Section(object):
130 def __init__(self, name=None):
131 # optional section name (argument/member or section name)
132 self.name = name
133 # the list of lines for this section
134 self.content = []
135
136 def append(self, line):
137 self.content.append(line)
138
139 def __repr__(self):
140 return "\n".join(self.content).strip()
141
142 class ArgSection(Section):
143 pass
144
145 def __init__(self, parser, info):
146 # self.parser is used to report errors with QAPIParseError. The
147 # resulting error position depends on the state of the parser.
148 # It happens to be the beginning of the comment. More or less
149 # servicable, but action at a distance.
150 self.parser = parser
151 self.info = info
152 self.symbol = None
153 self.body = QAPIDoc.Section()
154 # dict mapping parameter name to ArgSection
155 self.args = OrderedDict()
156 # a list of Section
157 self.sections = []
158 # the current section
159 self.section = self.body
160 # associated expression (to be set by expression parser)
161 self.expr = None
162
163 def has_section(self, name):
164 """Return True if we have a section with this name."""
165 for i in self.sections:
166 if i.name == name:
167 return True
168 return False
169
170 def append(self, line):
171 """Parse a comment line and add it to the documentation."""
172 line = line[1:]
173 if not line:
174 self._append_freeform(line)
175 return
176
177 if line[0] != ' ':
178 raise QAPIParseError(self.parser, "Missing space after #")
179 line = line[1:]
180
181 # FIXME not nice: things like '# @foo:' and '# @foo: ' aren't
182 # recognized, and get silently treated as ordinary text
183 if self.symbol:
184 self._append_symbol_line(line)
185 elif not self.body.content and line.startswith("@"):
186 if not line.endswith(":"):
187 raise QAPIParseError(self.parser, "Line should end with :")
188 self.symbol = line[1:-1]
189 # FIXME invalid names other than the empty string aren't flagged
190 if not self.symbol:
191 raise QAPIParseError(self.parser, "Invalid name")
192 else:
193 self._append_freeform(line)
194
195 def _append_symbol_line(self, line):
196 name = line.split(' ', 1)[0]
197
198 if name.startswith("@") and name.endswith(":"):
199 line = line[len(name)+1:]
200 self._start_args_section(name[1:-1])
201 elif name in ("Returns:", "Since:",
202 # those are often singular or plural
203 "Note:", "Notes:",
204 "Example:", "Examples:",
205 "TODO:"):
206 line = line[len(name)+1:]
207 self._start_section(name[:-1])
208
209 self._append_freeform(line)
210
211 def _start_args_section(self, name):
212 # FIXME invalid names other than the empty string aren't flagged
213 if not name:
214 raise QAPIParseError(self.parser, "Invalid parameter name")
215 if name in self.args:
216 raise QAPIParseError(self.parser,
217 "'%s' parameter name duplicated" % name)
218 if self.sections:
219 raise QAPIParseError(self.parser,
220 "'@%s:' can't follow '%s' section"
221 % (name, self.sections[0].name))
222 self.section = QAPIDoc.ArgSection(name)
223 self.args[name] = self.section
224
225 def _start_section(self, name=""):
226 if name in ("Returns", "Since") and self.has_section(name):
227 raise QAPIParseError(self.parser,
228 "Duplicated '%s' section" % name)
229 self.section = QAPIDoc.Section(name)
230 self.sections.append(self.section)
231
232 def _append_freeform(self, line):
233 in_arg = isinstance(self.section, QAPIDoc.ArgSection)
234 if (in_arg and self.section.content
235 and not self.section.content[-1]
236 and line and not line[0].isspace()):
237 self._start_section()
238 if (in_arg or not self.section.name
239 or not self.section.name.startswith("Example")):
240 line = line.strip()
241 self.section.append(line)
242
243
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200244class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500245
Eric Blake437db252015-09-29 16:21:02 -0600246 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200247 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200248 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200249 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200250 previously_included.append(abs_fname)
251 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200252 self.src = fp.read()
253 if self.src == '' or self.src[-1] != '\n':
254 self.src += '\n'
255 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800256 self.line = 1
257 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200258 self.exprs = []
Marc-André Lureau3313b612017-01-13 15:41:29 +0100259 self.docs = []
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200260 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500261
Eric Blake437db252015-09-29 16:21:02 -0600262 while self.tok is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100263 info = {'file': fname, 'line': self.line,
264 'parent': self.incl_info}
Marc-André Lureau3313b612017-01-13 15:41:29 +0100265 if self.tok == '#':
266 doc = self.get_doc(info)
267 self.docs.append(doc)
268 continue
269
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200270 expr = self.get_expr(False)
Markus Armbrustere04dea82017-03-15 13:56:50 +0100271 if 'include' in expr:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200272 if len(expr) != 1:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100273 raise QAPISemError(info, "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200274 include = expr["include"]
275 if not isinstance(include, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100276 raise QAPISemError(info,
277 "Value of 'include' must be a string")
Markus Armbrustere04dea82017-03-15 13:56:50 +0100278 self._include(include, info, os.path.dirname(abs_fname),
279 previously_included)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200280 else:
281 expr_elem = {'expr': expr,
Marc-André Lureau4148c292017-01-13 15:41:25 +0100282 'info': info}
Marc-André Lureau3313b612017-01-13 15:41:29 +0100283 if (self.docs
284 and self.docs[-1].info['file'] == fname
285 and not self.docs[-1].expr):
286 self.docs[-1].expr = expr
287 expr_elem['doc'] = self.docs[-1]
288
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200289 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500290
Markus Armbrustere04dea82017-03-15 13:56:50 +0100291 def _include(self, include, info, base_dir, previously_included):
292 incl_abs_fname = os.path.join(base_dir, include)
293 # catch inclusion cycle
294 inf = info
295 while inf:
296 if incl_abs_fname == os.path.abspath(inf['file']):
297 raise QAPISemError(info, "Inclusion loop for %s" % include)
298 inf = inf['parent']
299
300 # skip multiple include of the same file
301 if incl_abs_fname in previously_included:
302 return
303 try:
304 fobj = open(incl_abs_fname, 'r')
305 except IOError as e:
306 raise QAPISemError(info, '%s: %s' % (e.strerror, include))
307 exprs_include = QAPISchemaParser(fobj, previously_included, info)
308 self.exprs.extend(exprs_include.exprs)
309 self.docs.extend(exprs_include.docs)
310
Marc-André Lureau3313b612017-01-13 15:41:29 +0100311 def accept(self, skip_comment=True):
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200312 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200313 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200314 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200315 self.cursor += 1
316 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500317
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200318 if self.tok == '#':
Marc-André Lureau3313b612017-01-13 15:41:29 +0100319 if self.src[self.cursor] == '#':
320 # Start of doc comment
321 skip_comment = False
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200322 self.cursor = self.src.find('\n', self.cursor)
Marc-André Lureau3313b612017-01-13 15:41:29 +0100323 if not skip_comment:
324 self.val = self.src[self.pos:self.cursor]
325 return
Eric Blake8712fa52015-10-26 16:34:41 -0600326 elif self.tok in "{}:,[]":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200327 return
328 elif self.tok == "'":
329 string = ''
330 esc = False
331 while True:
332 ch = self.src[self.cursor]
333 self.cursor += 1
334 if ch == '\n':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100335 raise QAPIParseError(self, 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200336 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600337 if ch == 'b':
338 string += '\b'
339 elif ch == 'f':
340 string += '\f'
341 elif ch == 'n':
342 string += '\n'
343 elif ch == 'r':
344 string += '\r'
345 elif ch == 't':
346 string += '\t'
347 elif ch == 'u':
348 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600349 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600350 ch = self.src[self.cursor]
351 self.cursor += 1
352 if ch not in "0123456789abcdefABCDEF":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100353 raise QAPIParseError(self,
354 '\\u escape needs 4 '
355 'hex digits')
Eric Blakea7f59662015-05-04 09:05:36 -0600356 value = (value << 4) + int(ch, 16)
357 # If Python 2 and 3 didn't disagree so much on
358 # how to handle Unicode, then we could allow
359 # Unicode string defaults. But most of QAPI is
360 # ASCII-only, so we aren't losing much for now.
361 if not value or value > 0x7f:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100362 raise QAPIParseError(self,
363 'For now, \\u escape '
364 'only supports non-zero '
365 'values up to \\u007f')
Eric Blakea7f59662015-05-04 09:05:36 -0600366 string += chr(value)
367 elif ch in "\\/'\"":
368 string += ch
369 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100370 raise QAPIParseError(self,
371 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200372 esc = False
373 elif ch == "\\":
374 esc = True
375 elif ch == "'":
376 self.val = string
377 return
378 else:
379 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200380 elif self.src.startswith("true", self.pos):
381 self.val = True
382 self.cursor += 3
383 return
384 elif self.src.startswith("false", self.pos):
385 self.val = False
386 self.cursor += 4
387 return
388 elif self.src.startswith("null", self.pos):
389 self.val = None
390 self.cursor += 3
391 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200392 elif self.tok == '\n':
393 if self.cursor == len(self.src):
394 self.tok = None
395 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800396 self.line += 1
397 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200398 elif not self.tok.isspace():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100399 raise QAPIParseError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500400
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200401 def get_members(self):
402 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200403 if self.tok == '}':
404 self.accept()
405 return expr
406 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100407 raise QAPIParseError(self, 'Expected string or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200408 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200409 key = self.val
410 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200411 if self.tok != ':':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100412 raise QAPIParseError(self, 'Expected ":"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200413 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800414 if key in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100415 raise QAPIParseError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200416 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200417 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200418 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200419 return expr
420 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100421 raise QAPIParseError(self, 'Expected "," or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200422 self.accept()
423 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100424 raise QAPIParseError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500425
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200426 def get_values(self):
427 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200428 if self.tok == ']':
429 self.accept()
430 return expr
Eric Blake437db252015-09-29 16:21:02 -0600431 if self.tok not in "{['tfn":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100432 raise QAPIParseError(self, 'Expected "{", "[", "]", string, '
433 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200434 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200435 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200436 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200437 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200438 return expr
439 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100440 raise QAPIParseError(self, 'Expected "," or "]"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200441 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500442
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200443 def get_expr(self, nested):
444 if self.tok != '{' and not nested:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100445 raise QAPIParseError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200446 if self.tok == '{':
447 self.accept()
448 expr = self.get_members()
449 elif self.tok == '[':
450 self.accept()
451 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600452 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200453 expr = self.val
454 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200455 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100456 raise QAPIParseError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200457 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200458
Marc-André Lureau3313b612017-01-13 15:41:29 +0100459 def get_doc(self, info):
460 if self.val != '##':
461 raise QAPIParseError(self, "Junk after '##' at start of "
462 "documentation comment")
463
464 doc = QAPIDoc(self, info)
465 self.accept(False)
466 while self.tok == '#':
467 if self.val.startswith('##'):
468 # End of doc comment
469 if self.val != '##':
470 raise QAPIParseError(self, "Junk after '##' at end of "
471 "documentation comment")
472 self.accept()
473 return doc
474 else:
475 doc.append(self.val)
476 self.accept(False)
477
478 raise QAPIParseError(self, "Documentation comment must end with '##'")
479
480
Markus Armbruster00e4b282015-06-10 10:04:36 +0200481#
482# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200483# TODO fold into QAPISchema
484# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200485#
486
Eric Blake437db252015-09-29 16:21:02 -0600487
Eric Blake14f00c62016-03-03 09:16:43 -0700488def find_base_members(base):
Eric Blakeac4338f2016-03-17 16:48:39 -0600489 if isinstance(base, dict):
490 return base
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800491 base_struct_define = find_struct(base)
492 if not base_struct_define:
493 return None
494 return base_struct_define['data']
495
Eric Blake437db252015-09-29 16:21:02 -0600496
Eric Blake811d04f2015-05-04 09:05:10 -0600497# Return the qtype of an alternate branch, or None on error.
498def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600499 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600500 return builtin_types[qapi_type]
501 elif find_struct(qapi_type):
502 return "QTYPE_QDICT"
503 elif find_enum(qapi_type):
504 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600505 elif find_union(qapi_type):
506 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600507 return None
508
Eric Blake437db252015-09-29 16:21:02 -0600509
Wenchao Xiabceae762014-03-06 17:08:56 -0800510# Return the discriminator enum define if discriminator is specified as an
511# enum type, otherwise return None.
512def discriminator_find_enum_define(expr):
513 base = expr.get('base')
514 discriminator = expr.get('discriminator')
515
516 if not (discriminator and base):
517 return None
518
Eric Blake14f00c62016-03-03 09:16:43 -0700519 base_members = find_base_members(base)
520 if not base_members:
Wenchao Xiabceae762014-03-06 17:08:56 -0800521 return None
522
Eric Blake14f00c62016-03-03 09:16:43 -0700523 discriminator_type = base_members.get(discriminator)
Wenchao Xiabceae762014-03-06 17:08:56 -0800524 if not discriminator_type:
525 return None
526
527 return find_enum(discriminator_type)
528
Eric Blake437db252015-09-29 16:21:02 -0600529
Eric Blake59a92fe2015-11-18 01:52:56 -0700530# Names must be letters, numbers, -, and _. They must start with letter,
531# except for downstream extensions which must start with __RFQDN_.
532# Dots are only valid in the downstream extension prefix.
533valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
534 '[a-zA-Z][a-zA-Z0-9_-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600535
536
Marc-André Lureau4148c292017-01-13 15:41:25 +0100537def check_name(info, source, name, allow_optional=False,
Eric Blake437db252015-09-29 16:21:02 -0600538 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600539 global valid_name
540 membername = name
541
542 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100543 raise QAPISemError(info, "%s requires a string name" % source)
Eric Blakec9e0a792015-05-04 09:05:22 -0600544 if name.startswith('*'):
545 membername = name[1:]
546 if not allow_optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100547 raise QAPISemError(info, "%s does not allow optional name '%s'"
548 % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600549 # Enum members can start with a digit, because the generated C
550 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700551 if enum_member and membername[0].isdigit():
552 membername = 'D' + membername
Eric Blake75996972016-03-17 16:48:29 -0600553 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
554 # and 'q_obj_*' implicit type names.
Eric Blake9fb081e2015-10-26 16:34:44 -0600555 if not valid_name.match(membername) or \
556 c_name(membername, False).startswith('q_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100557 raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600558
Eric Blake437db252015-09-29 16:21:02 -0600559
560def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200561 global all_names
562 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200563 # FIXME should reject names that differ only in '_' vs. '.'
564 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200565 if name in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100566 raise QAPISemError(info, "%s '%s' is already defined"
567 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600568 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100569 raise QAPISemError(info, "%s '%s' should not end in '%s'"
570 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200571 all_names[name] = meta
572
Eric Blake437db252015-09-29 16:21:02 -0600573
Markus Armbruster00e4b282015-06-10 10:04:36 +0200574def add_struct(definition, info):
575 global struct_types
576 name = definition['struct']
577 add_name(name, info, 'struct')
578 struct_types.append(definition)
579
Eric Blake437db252015-09-29 16:21:02 -0600580
Markus Armbruster00e4b282015-06-10 10:04:36 +0200581def find_struct(name):
582 global struct_types
583 for struct in struct_types:
584 if struct['struct'] == name:
585 return struct
586 return None
587
Eric Blake437db252015-09-29 16:21:02 -0600588
Markus Armbruster00e4b282015-06-10 10:04:36 +0200589def add_union(definition, info):
590 global union_types
591 name = definition['union']
592 add_name(name, info, 'union')
593 union_types.append(definition)
594
Eric Blake437db252015-09-29 16:21:02 -0600595
Markus Armbruster00e4b282015-06-10 10:04:36 +0200596def find_union(name):
597 global union_types
598 for union in union_types:
599 if union['union'] == name:
600 return union
601 return None
602
Eric Blake437db252015-09-29 16:21:02 -0600603
604def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200605 global enum_types
606 add_name(name, info, 'enum', implicit)
607 enum_types.append({"enum_name": name, "enum_values": enum_values})
608
Eric Blake437db252015-09-29 16:21:02 -0600609
Markus Armbruster00e4b282015-06-10 10:04:36 +0200610def find_enum(name):
611 global enum_types
612 for enum in enum_types:
613 if enum['enum_name'] == name:
614 return enum
615 return None
616
Markus Armbruster00e4b282015-06-10 10:04:36 +0200617
Eric Blake437db252015-09-29 16:21:02 -0600618def is_enum(name):
619 return find_enum(name) is not None
620
621
Marc-André Lureau4148c292017-01-13 15:41:25 +0100622def check_type(info, source, value, allow_array=False,
Eric Blake437db252015-09-29 16:21:02 -0600623 allow_dict=False, allow_optional=False,
624 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600625 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600626
627 if value is None:
628 return
629
Eric Blakedd883c62015-05-04 09:05:21 -0600630 # Check if array type for value is okay
631 if isinstance(value, list):
632 if not allow_array:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100633 raise QAPISemError(info, "%s cannot be an array" % source)
Eric Blakedd883c62015-05-04 09:05:21 -0600634 if len(value) != 1 or not isinstance(value[0], str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100635 raise QAPISemError(info,
636 "%s: array type must contain single type name" %
637 source)
Eric Blakedd883c62015-05-04 09:05:21 -0600638 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600639
640 # Check if type name for value is okay
641 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600642 if value not in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100643 raise QAPISemError(info, "%s uses unknown type '%s'"
644 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600645 if not all_names[value] in allow_metas:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100646 raise QAPISemError(info, "%s cannot use %s type '%s'" %
647 (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600648 return
649
Eric Blakedd883c62015-05-04 09:05:21 -0600650 if not allow_dict:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100651 raise QAPISemError(info, "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200652
653 if not isinstance(value, OrderedDict):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100654 raise QAPISemError(info,
655 "%s should be a dictionary or type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200656
657 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600658 for (key, arg) in value.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100659 check_name(info, "Member of %s" % source, key,
Eric Blakec9e0a792015-05-04 09:05:22 -0600660 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600661 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100662 raise QAPISemError(info, "Member of %s uses reserved name '%s'"
663 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600664 # Todo: allow dictionaries to represent default values of
665 # an optional argument.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100666 check_type(info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200667 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600668 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600669 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600670
Eric Blake437db252015-09-29 16:21:02 -0600671
Marc-André Lureau4148c292017-01-13 15:41:25 +0100672def check_command(expr, info):
Eric Blakedd883c62015-05-04 09:05:21 -0600673 name = expr['command']
Eric Blakec8184082016-07-13 21:50:20 -0600674 boxed = expr.get('boxed', False)
Eric Blake2cbf0992015-05-04 09:05:24 -0600675
Eric Blakec8184082016-07-13 21:50:20 -0600676 args_meta = ['struct']
677 if boxed:
678 args_meta += ['union', 'alternate']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100679 check_type(info, "'data' for command '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600680 expr.get('data'), allow_dict=not boxed, allow_optional=True,
681 allow_metas=args_meta)
Eric Blake10d4d992015-05-04 09:05:23 -0600682 returns_meta = ['union', 'struct']
683 if name in returns_whitelist:
684 returns_meta += ['built-in', 'alternate', 'enum']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100685 check_type(info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200686 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200687 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600688
Eric Blake437db252015-09-29 16:21:02 -0600689
Marc-André Lureau4148c292017-01-13 15:41:25 +0100690def check_event(expr, info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600691 global events
692 name = expr['event']
Eric Blakec8184082016-07-13 21:50:20 -0600693 boxed = expr.get('boxed', False)
Eric Blake4dc2e692015-05-04 09:05:17 -0600694
Eric Blakec8184082016-07-13 21:50:20 -0600695 meta = ['struct']
696 if boxed:
697 meta += ['union', 'alternate']
Eric Blake4dc2e692015-05-04 09:05:17 -0600698 events.append(name)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100699 check_type(info, "'data' for event '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600700 expr.get('data'), allow_dict=not boxed, allow_optional=True,
701 allow_metas=meta)
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200702
Eric Blake437db252015-09-29 16:21:02 -0600703
Marc-André Lureau4148c292017-01-13 15:41:25 +0100704def check_union(expr, info):
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800705 name = expr['union']
706 base = expr.get('base')
707 discriminator = expr.get('discriminator')
708 members = expr['data']
709
Eric Blake811d04f2015-05-04 09:05:10 -0600710 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600711
712 # With no discriminator it is a simple union.
713 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600714 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600715 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600716 if base is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100717 raise QAPISemError(info, "Simple union '%s' must not have a base" %
718 name)
Eric Blake44bd1272015-05-04 09:05:08 -0600719
720 # Else, it's a flat union.
721 else:
Eric Blakeac4338f2016-03-17 16:48:39 -0600722 # The object must have a string or dictionary 'base'.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100723 check_type(info, "'base' for union '%s'" % name,
Eric Blakeac4338f2016-03-17 16:48:39 -0600724 base, allow_dict=True, allow_optional=True,
725 allow_metas=['struct'])
Eric Blake376863e2015-09-29 16:21:07 -0600726 if not base:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100727 raise QAPISemError(info, "Flat union '%s' must have a base"
728 % name)
Eric Blake14f00c62016-03-03 09:16:43 -0700729 base_members = find_base_members(base)
730 assert base_members
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800731
Eric Blakec9e0a792015-05-04 09:05:22 -0600732 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600733 # member of the base struct.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100734 check_name(info, "Discriminator of flat union '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600735 discriminator)
Eric Blake14f00c62016-03-03 09:16:43 -0700736 discriminator_type = base_members.get(discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800737 if not discriminator_type:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100738 raise QAPISemError(info,
739 "Discriminator '%s' is not a member of base "
740 "struct '%s'"
741 % (discriminator, base))
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800742 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600743 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800744 # Do not allow string discriminator
745 if not enum_define:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100746 raise QAPISemError(info,
747 "Discriminator '%s' must be of enumeration "
748 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800749
Eric Blake02a57ae2016-02-17 23:48:16 -0700750 # Check every branch; don't allow an empty union
751 if len(members) == 0:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100752 raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800753 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100754 check_name(info, "Member of union '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600755
Eric Blake01cfbaa2015-12-01 22:20:58 -0700756 # Each value must name a known type
Marc-André Lureau4148c292017-01-13 15:41:25 +0100757 check_type(info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200758 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600759
Eric Blake44bd1272015-05-04 09:05:08 -0600760 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700761 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600762 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600763 if key not in enum_define['enum_values']:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100764 raise QAPISemError(info,
765 "Discriminator value '%s' is not found in "
766 "enum '%s'"
767 % (key, enum_define["enum_name"]))
Eric Blake44bd1272015-05-04 09:05:08 -0600768
Eric Blaked0b18232016-07-13 21:50:13 -0600769 # If discriminator is user-defined, ensure all values are covered
770 if enum_define:
771 for value in enum_define['enum_values']:
772 if value not in members.keys():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100773 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
774 % (name, value))
Eric Blaked0b18232016-07-13 21:50:13 -0600775
Eric Blake437db252015-09-29 16:21:02 -0600776
Marc-André Lureau4148c292017-01-13 15:41:25 +0100777def check_alternate(expr, info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600778 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600779 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600780 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600781
Eric Blake02a57ae2016-02-17 23:48:16 -0700782 # Check every branch; require at least two branches
783 if len(members) < 2:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100784 raise QAPISemError(info,
785 "Alternate '%s' should have at least two branches "
786 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600787 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100788 check_name(info, "Member of alternate '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600789
Eric Blake811d04f2015-05-04 09:05:10 -0600790 # Ensure alternates have no type conflicts.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100791 check_type(info, "Member '%s' of alternate '%s'" % (key, name),
Eric Blakedd883c62015-05-04 09:05:21 -0600792 value,
793 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600794 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700795 if not qtype:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100796 raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
797 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600798 if qtype in types_seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100799 raise QAPISemError(info, "Alternate '%s' member '%s' can't "
800 "be distinguished from member '%s'"
801 % (name, key, types_seen[qtype]))
Eric Blake811d04f2015-05-04 09:05:10 -0600802 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800803
Eric Blake437db252015-09-29 16:21:02 -0600804
Marc-André Lureau4148c292017-01-13 15:41:25 +0100805def check_enum(expr, info):
Eric Blakecf393592015-05-04 09:05:04 -0600806 name = expr['enum']
807 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100808 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600809
810 if not isinstance(members, list):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100811 raise QAPISemError(info,
812 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100813 if prefix is not None and not isinstance(prefix, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100814 raise QAPISemError(info,
815 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600816 for member in members:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100817 check_name(info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600818 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600819
Eric Blake437db252015-09-29 16:21:02 -0600820
Marc-André Lureau4148c292017-01-13 15:41:25 +0100821def check_struct(expr, info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600822 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600823 members = expr['data']
824
Marc-André Lureau4148c292017-01-13 15:41:25 +0100825 check_type(info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600826 allow_dict=True, allow_optional=True)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100827 check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600828 allow_metas=['struct'])
829
Eric Blake437db252015-09-29 16:21:02 -0600830
Eric Blake0545f6b2015-05-04 09:05:15 -0600831def check_keys(expr_elem, meta, required, optional=[]):
832 expr = expr_elem['expr']
833 info = expr_elem['info']
834 name = expr[meta]
835 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100836 raise QAPISemError(info, "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600837 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600838 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600839 if key not in required and key not in optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100840 raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
841 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600842 if (key == 'gen' or key == 'success-response') and value is not False:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100843 raise QAPISemError(info,
844 "'%s' of %s '%s' should only use false value"
845 % (key, meta, name))
Eric Blakec8184082016-07-13 21:50:20 -0600846 if key == 'boxed' and value is not True:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100847 raise QAPISemError(info,
848 "'%s' of %s '%s' should only use true value"
849 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600850 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600851 if key not in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100852 raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
853 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600854
Eric Blake437db252015-09-29 16:21:02 -0600855
Markus Armbruster4d076d62015-06-10 08:55:21 +0200856def check_exprs(exprs):
857 global all_names
858
859 # Learn the types and check for valid expression keys
860 for builtin in builtin_types.keys():
861 all_names[builtin] = 'built-in'
862 for expr_elem in exprs:
863 expr = expr_elem['expr']
864 info = expr_elem['info']
Marc-André Lureau3313b612017-01-13 15:41:29 +0100865
866 if 'doc' not in expr_elem:
867 raise QAPISemError(info,
868 "Expression missing documentation comment")
869
Eric Blake437db252015-09-29 16:21:02 -0600870 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100871 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200872 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600873 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200874 check_keys(expr_elem, 'union', ['data'],
875 ['base', 'discriminator'])
876 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600877 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200878 check_keys(expr_elem, 'alternate', ['data'])
879 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600880 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200881 check_keys(expr_elem, 'struct', ['data'], ['base'])
882 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600883 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200884 check_keys(expr_elem, 'command', [],
Eric Blakec8184082016-07-13 21:50:20 -0600885 ['data', 'returns', 'gen', 'success-response', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200886 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600887 elif 'event' in expr:
Eric Blakec8184082016-07-13 21:50:20 -0600888 check_keys(expr_elem, 'event', [], ['data', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200889 add_name(expr['event'], info, 'event')
890 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100891 raise QAPISemError(expr_elem['info'],
892 "Expression is missing metatype")
Markus Armbruster4d076d62015-06-10 08:55:21 +0200893
894 # Try again for hidden UnionKind enum
895 for expr_elem in exprs:
896 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600897 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200898 if not discriminator_find_enum_define(expr):
899 add_enum('%sKind' % expr['union'], expr_elem['info'],
900 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600901 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200902 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
903 implicit=True)
904
905 # Validate that exprs make sense
906 for expr_elem in exprs:
907 expr = expr_elem['expr']
908 info = expr_elem['info']
909
Eric Blake437db252015-09-29 16:21:02 -0600910 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200911 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600912 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200913 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600914 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200915 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600916 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200917 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600918 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200919 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600920 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200921 check_event(expr, info)
922 else:
923 assert False, 'unexpected meta type'
924
Markus Armbrusterac882192015-09-16 13:06:05 +0200925 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600926
Markus Armbrusterac882192015-09-16 13:06:05 +0200927
Marc-André Lureau3313b612017-01-13 15:41:29 +0100928def check_freeform_doc(doc):
929 if doc.symbol:
930 raise QAPISemError(doc.info,
931 "Documention for '%s' is not followed"
932 " by the definition" % doc.symbol)
933
934 body = str(doc.body)
935 if re.search(r'@\S+:', body, re.MULTILINE):
936 raise QAPISemError(doc.info,
937 "Free-form documentation block must not contain"
938 " @NAME: sections")
939
940
941def check_definition_doc(doc, expr, info):
942 for i in ('enum', 'union', 'alternate', 'struct', 'command', 'event'):
943 if i in expr:
944 meta = i
945 break
946
947 name = expr[meta]
948 if doc.symbol != name:
949 raise QAPISemError(info, "Definition of '%s' follows documentation"
950 " for '%s'" % (name, doc.symbol))
951 if doc.has_section('Returns') and 'command' not in expr:
952 raise QAPISemError(info, "'Returns:' is only valid for commands")
953
954 if meta == 'union':
955 args = expr.get('base', [])
956 else:
957 args = expr.get('data', [])
958 if isinstance(args, str):
959 return
960 if isinstance(args, dict):
961 args = args.keys()
962 assert isinstance(args, list)
963
964 if (meta == 'alternate'
965 or (meta == 'union' and not expr.get('discriminator'))):
966 args.append('type')
967
968 for arg in args:
969 if arg[0] == '*':
970 opt = True
971 desc = doc.args.get(arg[1:])
972 else:
973 opt = False
974 desc = doc.args.get(arg)
975 if not desc:
976 continue
977 desc_opt = "#optional" in str(desc)
978 if desc_opt and not opt:
979 raise QAPISemError(info, "Description has #optional, "
980 "but the declaration doesn't")
981 if not desc_opt and opt:
982 # silently fix the doc
983 # TODO either fix the schema and make this an error,
984 # or drop #optional entirely
985 desc.append("#optional")
986
987 doc_args = set(doc.args.keys())
988 args = set([name.strip('*') for name in args])
989 if not doc_args.issubset(args):
990 raise QAPISemError(info, "The following documented members are not in "
991 "the declaration: %s" % ", ".join(doc_args - args))
992
993
994def check_docs(docs):
995 for doc in docs:
996 for section in doc.args.values() + doc.sections:
997 content = str(section)
998 if not content or content.isspace():
999 raise QAPISemError(doc.info,
1000 "Empty doc section '%s'" % section.name)
1001
1002 if not doc.expr:
1003 check_freeform_doc(doc)
1004 else:
1005 check_definition_doc(doc, doc.expr, doc.info)
1006
1007 return docs
1008
1009
Markus Armbrusterac882192015-09-16 13:06:05 +02001010#
1011# Schema compiler frontend
1012#
1013
1014class QAPISchemaEntity(object):
1015 def __init__(self, name, info):
1016 assert isinstance(name, str)
1017 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -06001018 # For explicitly defined entities, info points to the (explicit)
1019 # definition. For builtins (and their arrays), info is None.
1020 # For implicitly defined entities, info points to a place that
1021 # triggered the implicit definition (there may be more than one
1022 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +02001023 self.info = info
1024
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001025 def c_name(self):
1026 return c_name(self.name)
1027
Markus Armbrusterac882192015-09-16 13:06:05 +02001028 def check(self, schema):
1029 pass
1030
Eric Blake49823c42015-10-12 22:22:27 -06001031 def is_implicit(self):
1032 return not self.info
1033
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001034 def visit(self, visitor):
1035 pass
1036
1037
1038class QAPISchemaVisitor(object):
1039 def visit_begin(self, schema):
1040 pass
1041
1042 def visit_end(self):
1043 pass
1044
Eric Blake25a0d9c2015-10-12 22:22:21 -06001045 def visit_needed(self, entity):
1046 # Default to visiting everything
1047 return True
1048
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001049 def visit_builtin_type(self, name, info, json_type):
1050 pass
1051
1052 def visit_enum_type(self, name, info, values, prefix):
1053 pass
1054
1055 def visit_array_type(self, name, info, element_type):
1056 pass
1057
1058 def visit_object_type(self, name, info, base, members, variants):
1059 pass
1060
Markus Armbruster39a18152015-09-16 13:06:28 +02001061 def visit_object_type_flat(self, name, info, members, variants):
1062 pass
1063
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001064 def visit_alternate_type(self, name, info, variants):
1065 pass
1066
1067 def visit_command(self, name, info, arg_type, ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001068 gen, success_response, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001069 pass
1070
Eric Blake48825ca2016-07-13 21:50:19 -06001071 def visit_event(self, name, info, arg_type, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001072 pass
1073
Markus Armbrusterac882192015-09-16 13:06:05 +02001074
1075class QAPISchemaType(QAPISchemaEntity):
Eric Blake4040d992016-03-17 16:48:28 -06001076 # Return the C type for common use.
1077 # For the types we commonly box, this is a pointer type.
1078 def c_type(self):
1079 pass
1080
1081 # Return the C type to be used in a parameter list.
1082 def c_param_type(self):
1083 return self.c_type()
1084
1085 # Return the C type to be used where we suppress boxing.
1086 def c_unboxed_type(self):
1087 return self.c_type()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001088
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001089 def json_type(self):
1090 pass
1091
1092 def alternate_qtype(self):
1093 json2qtype = {
1094 'string': 'QTYPE_QSTRING',
1095 'number': 'QTYPE_QFLOAT',
1096 'int': 'QTYPE_QINT',
1097 'boolean': 'QTYPE_QBOOL',
1098 'object': 'QTYPE_QDICT'
1099 }
1100 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +02001101
1102
1103class QAPISchemaBuiltinType(QAPISchemaType):
Eric Blake861877a2016-03-17 16:48:36 -06001104 def __init__(self, name, json_type, c_type):
Markus Armbrusterac882192015-09-16 13:06:05 +02001105 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001106 assert not c_type or isinstance(c_type, str)
1107 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
1108 'value')
1109 self._json_type_name = json_type
1110 self._c_type_name = c_type
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001111
1112 def c_name(self):
1113 return self.name
1114
Eric Blake4040d992016-03-17 16:48:28 -06001115 def c_type(self):
1116 return self._c_type_name
1117
1118 def c_param_type(self):
1119 if self.name == 'str':
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001120 return 'const ' + self._c_type_name
1121 return self._c_type_name
1122
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001123 def json_type(self):
1124 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +02001125
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001126 def visit(self, visitor):
1127 visitor.visit_builtin_type(self.name, self.info, self.json_type())
1128
Markus Armbrusterac882192015-09-16 13:06:05 +02001129
1130class QAPISchemaEnumType(QAPISchemaType):
1131 def __init__(self, name, info, values, prefix):
1132 QAPISchemaType.__init__(self, name, info)
1133 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -07001134 assert isinstance(v, QAPISchemaMember)
1135 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001136 assert prefix is None or isinstance(prefix, str)
1137 self.values = values
1138 self.prefix = prefix
1139
1140 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -07001141 seen = {}
1142 for v in self.values:
1143 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001144
Eric Blake99df5282015-10-12 22:22:32 -06001145 def is_implicit(self):
1146 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -06001147 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -06001148
Eric Blake4040d992016-03-17 16:48:28 -06001149 def c_type(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001150 return c_name(self.name)
1151
Eric Blake93bda4d2015-12-01 22:20:55 -07001152 def member_names(self):
1153 return [v.name for v in self.values]
1154
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001155 def json_type(self):
1156 return 'string'
1157
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001158 def visit(self, visitor):
1159 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -07001160 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001161
Markus Armbrusterac882192015-09-16 13:06:05 +02001162
1163class QAPISchemaArrayType(QAPISchemaType):
1164 def __init__(self, name, info, element_type):
1165 QAPISchemaType.__init__(self, name, info)
1166 assert isinstance(element_type, str)
1167 self._element_type_name = element_type
1168 self.element_type = None
1169
1170 def check(self, schema):
1171 self.element_type = schema.lookup_type(self._element_type_name)
1172 assert self.element_type
1173
Eric Blake99df5282015-10-12 22:22:32 -06001174 def is_implicit(self):
1175 return True
1176
Eric Blake4040d992016-03-17 16:48:28 -06001177 def c_type(self):
1178 return c_name(self.name) + pointer_suffix
1179
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001180 def json_type(self):
1181 return 'array'
1182
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001183 def visit(self, visitor):
1184 visitor.visit_array_type(self.name, self.info, self.element_type)
1185
Markus Armbrusterac882192015-09-16 13:06:05 +02001186
1187class QAPISchemaObjectType(QAPISchemaType):
1188 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -07001189 # struct has local_members, optional base, and no variants
1190 # flat union has base, variants, and no local_members
1191 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +02001192 QAPISchemaType.__init__(self, name, info)
1193 assert base is None or isinstance(base, str)
1194 for m in local_members:
1195 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -07001196 m.set_owner(name)
1197 if variants is not None:
1198 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1199 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001200 self._base_name = base
1201 self.base = None
1202 self.local_members = local_members
1203 self.variants = variants
1204 self.members = None
1205
1206 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -07001207 if self.members is False: # check for cycles
Marc-André Lureau4148c292017-01-13 15:41:25 +01001208 raise QAPISemError(self.info,
1209 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001210 if self.members:
1211 return
1212 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -07001213 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +02001214 if self._base_name:
1215 self.base = schema.lookup_type(self._base_name)
1216 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +02001217 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001218 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001219 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001220 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001221 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001222 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +02001223 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001224 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001225 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -07001226 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001227
Eric Blake14f00c62016-03-03 09:16:43 -07001228 # Check that the members of this type do not cause duplicate JSON members,
Eric Blake27b60ab2015-11-18 01:52:51 -07001229 # and update seen to track the members seen so far. Report any errors
1230 # on behalf of info, which is not necessarily self.info
1231 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -07001232 assert not self.variants # not implemented
1233 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -07001234 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -07001235
Eric Blake99df5282015-10-12 22:22:32 -06001236 def is_implicit(self):
Eric Blake75996972016-03-17 16:48:29 -06001237 # See QAPISchema._make_implicit_object_type(), as well as
1238 # _def_predefineds()
1239 return self.name.startswith('q_')
Eric Blake99df5282015-10-12 22:22:32 -06001240
Eric Blakeb6167702016-07-13 21:50:16 -06001241 def is_empty(self):
1242 assert self.members is not None
1243 return not self.members and not self.variants
1244
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001245 def c_name(self):
Eric Blakecd50a252016-07-13 21:50:14 -06001246 assert self.name != 'q_empty'
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001247 return QAPISchemaType.c_name(self)
1248
Eric Blake4040d992016-03-17 16:48:28 -06001249 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001250 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -07001251 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001252
Eric Blake4040d992016-03-17 16:48:28 -06001253 def c_unboxed_type(self):
Eric Blake4040d992016-03-17 16:48:28 -06001254 return c_name(self.name)
1255
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001256 def json_type(self):
1257 return 'object'
1258
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001259 def visit(self, visitor):
1260 visitor.visit_object_type(self.name, self.info,
1261 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001262 visitor.visit_object_type_flat(self.name, self.info,
1263 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001264
Markus Armbrusterac882192015-09-16 13:06:05 +02001265
Eric Blaked44f9ac2015-12-01 22:20:54 -07001266class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001267 role = 'member'
1268
Eric Blaked44f9ac2015-12-01 22:20:54 -07001269 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001270 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001271 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001272 self.owner = None
1273
1274 def set_owner(self, name):
1275 assert not self.owner
1276 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001277
Eric Blake27b60ab2015-11-18 01:52:51 -07001278 def check_clash(self, info, seen):
1279 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001280 if cname.lower() != cname and self.owner not in case_whitelist:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001281 raise QAPISemError(info,
1282 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001283 if cname in seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001284 raise QAPISemError(info, "%s collides with %s" %
1285 (self.describe(), seen[cname].describe()))
Eric Blake27b60ab2015-11-18 01:52:51 -07001286 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001287
Eric Blake88d4ef82015-11-18 01:52:50 -07001288 def _pretty_owner(self):
1289 owner = self.owner
Eric Blake75996972016-03-17 16:48:29 -06001290 if owner.startswith('q_obj_'):
Eric Blake88d4ef82015-11-18 01:52:50 -07001291 # See QAPISchema._make_implicit_object_type() - reverse the
1292 # mapping there to create a nice human-readable description
Eric Blake75996972016-03-17 16:48:29 -06001293 owner = owner[6:]
Eric Blake88d4ef82015-11-18 01:52:50 -07001294 if owner.endswith('-arg'):
1295 return '(parameter of %s)' % owner[:-4]
Eric Blakeac4338f2016-03-17 16:48:39 -06001296 elif owner.endswith('-base'):
1297 return '(base of %s)' % owner[:-5]
Eric Blake88d4ef82015-11-18 01:52:50 -07001298 else:
1299 assert owner.endswith('-wrapper')
1300 # Unreachable and not implemented
1301 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001302 if owner.endswith('Kind'):
1303 # See QAPISchema._make_implicit_enum_type()
1304 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001305 return '(%s of %s)' % (self.role, owner)
1306
1307 def describe(self):
1308 return "'%s' %s" % (self.name, self._pretty_owner())
1309
Markus Armbrusterac882192015-09-16 13:06:05 +02001310
Eric Blaked44f9ac2015-12-01 22:20:54 -07001311class QAPISchemaObjectTypeMember(QAPISchemaMember):
1312 def __init__(self, name, typ, optional):
1313 QAPISchemaMember.__init__(self, name)
1314 assert isinstance(typ, str)
1315 assert isinstance(optional, bool)
1316 self._type_name = typ
1317 self.type = None
1318 self.optional = optional
1319
1320 def check(self, schema):
1321 assert self.owner
1322 self.type = schema.lookup_type(self._type_name)
1323 assert self.type
1324
1325
Markus Armbrusterac882192015-09-16 13:06:05 +02001326class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001327 def __init__(self, tag_name, tag_member, variants):
1328 # Flat unions pass tag_name but not tag_member.
1329 # Simple unions and alternates pass tag_member but not tag_name.
1330 # After check(), tag_member is always set, and tag_name remains
1331 # a reliable witness of being used by a flat union.
1332 assert bool(tag_member) != bool(tag_name)
1333 assert (isinstance(tag_name, str) or
1334 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001335 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001336 for v in variants:
1337 assert isinstance(v, QAPISchemaObjectTypeVariant)
Eric Blakeda9cb192016-07-13 21:50:15 -06001338 self._tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001339 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001340 self.variants = variants
1341
Eric Blake88d4ef82015-11-18 01:52:50 -07001342 def set_owner(self, name):
1343 for v in self.variants:
1344 v.set_owner(name)
1345
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001346 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001347 if not self.tag_member: # flat union
Eric Blakeda9cb192016-07-13 21:50:15 -06001348 self.tag_member = seen[c_name(self._tag_name)]
1349 assert self._tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001350 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1351 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001352 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001353 # Union names must match enum values; alternate names are
1354 # checked separately. Use 'seen' to tell the two apart.
1355 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001356 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001357 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001358 v.type.check(schema)
1359
Eric Blake27b60ab2015-11-18 01:52:51 -07001360 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001361 for v in self.variants:
1362 # Reset seen map for each variant, since qapi names from one
1363 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001364 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001365 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001366
Eric Blake437db252015-09-29 16:21:02 -06001367
Markus Armbrusterac882192015-09-16 13:06:05 +02001368class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001369 role = 'branch'
1370
Markus Armbrusterac882192015-09-16 13:06:05 +02001371 def __init__(self, name, typ):
1372 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1373
Markus Armbrusterac882192015-09-16 13:06:05 +02001374
1375class QAPISchemaAlternateType(QAPISchemaType):
1376 def __init__(self, name, info, variants):
1377 QAPISchemaType.__init__(self, name, info)
1378 assert isinstance(variants, QAPISchemaObjectTypeVariants)
Eric Blakeda9cb192016-07-13 21:50:15 -06001379 assert variants.tag_member
Eric Blake88d4ef82015-11-18 01:52:50 -07001380 variants.set_owner(name)
1381 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001382 self.variants = variants
1383
1384 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001385 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001386 # Not calling self.variants.check_clash(), because there's nothing
1387 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001388 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001389 # Alternate branch names have no relation to the tag enum values;
1390 # so we have to check for potential name collisions ourselves.
1391 seen = {}
1392 for v in self.variants.variants:
1393 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001394
Eric Blake4040d992016-03-17 16:48:28 -06001395 def c_type(self):
1396 return c_name(self.name) + pointer_suffix
1397
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001398 def json_type(self):
1399 return 'value'
1400
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001401 def visit(self, visitor):
1402 visitor.visit_alternate_type(self.name, self.info, self.variants)
1403
Eric Blakec8184082016-07-13 21:50:20 -06001404 def is_empty(self):
1405 return False
1406
Markus Armbrusterac882192015-09-16 13:06:05 +02001407
1408class QAPISchemaCommand(QAPISchemaEntity):
Eric Blake48825ca2016-07-13 21:50:19 -06001409 def __init__(self, name, info, arg_type, ret_type, gen, success_response,
1410 boxed):
Markus Armbrusterac882192015-09-16 13:06:05 +02001411 QAPISchemaEntity.__init__(self, name, info)
1412 assert not arg_type or isinstance(arg_type, str)
1413 assert not ret_type or isinstance(ret_type, str)
1414 self._arg_type_name = arg_type
1415 self.arg_type = None
1416 self._ret_type_name = ret_type
1417 self.ret_type = None
1418 self.gen = gen
1419 self.success_response = success_response
Eric Blake48825ca2016-07-13 21:50:19 -06001420 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001421
1422 def check(self, schema):
1423 if self._arg_type_name:
1424 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001425 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1426 isinstance(self.arg_type, QAPISchemaAlternateType))
1427 self.arg_type.check(schema)
1428 if self.boxed:
1429 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001430 raise QAPISemError(self.info,
1431 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001432 else:
1433 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1434 assert not self.arg_type.variants
1435 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001436 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001437 if self._ret_type_name:
1438 self.ret_type = schema.lookup_type(self._ret_type_name)
1439 assert isinstance(self.ret_type, QAPISchemaType)
1440
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001441 def visit(self, visitor):
1442 visitor.visit_command(self.name, self.info,
1443 self.arg_type, self.ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001444 self.gen, self.success_response, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001445
Markus Armbrusterac882192015-09-16 13:06:05 +02001446
1447class QAPISchemaEvent(QAPISchemaEntity):
Eric Blake48825ca2016-07-13 21:50:19 -06001448 def __init__(self, name, info, arg_type, boxed):
Markus Armbrusterac882192015-09-16 13:06:05 +02001449 QAPISchemaEntity.__init__(self, name, info)
1450 assert not arg_type or isinstance(arg_type, str)
1451 self._arg_type_name = arg_type
1452 self.arg_type = None
Eric Blake48825ca2016-07-13 21:50:19 -06001453 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001454
1455 def check(self, schema):
1456 if self._arg_type_name:
1457 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001458 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1459 isinstance(self.arg_type, QAPISchemaAlternateType))
1460 self.arg_type.check(schema)
1461 if self.boxed:
1462 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001463 raise QAPISemError(self.info,
1464 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001465 else:
1466 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1467 assert not self.arg_type.variants
1468 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001469 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001470
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001471 def visit(self, visitor):
Eric Blake48825ca2016-07-13 21:50:19 -06001472 visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001473
Markus Armbrusterac882192015-09-16 13:06:05 +02001474
1475class QAPISchema(object):
1476 def __init__(self, fname):
1477 try:
Marc-André Lureau3313b612017-01-13 15:41:29 +01001478 parser = QAPISchemaParser(open(fname, "r"))
1479 self.exprs = check_exprs(parser.exprs)
1480 self.docs = check_docs(parser.docs)
Eric Blake7618b912015-10-12 22:22:22 -06001481 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001482 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001483 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001484 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001485 self._def_exprs()
1486 self.check()
Marc-André Lureau4148c292017-01-13 15:41:25 +01001487 except QAPIError as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001488 print >>sys.stderr, err
1489 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001490
Markus Armbrusterac882192015-09-16 13:06:05 +02001491 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001492 # Only the predefined types are allowed to not have info
1493 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001494 assert ent.name not in self._entity_dict
1495 self._entity_dict[ent.name] = ent
1496
1497 def lookup_entity(self, name, typ=None):
1498 ent = self._entity_dict.get(name)
1499 if typ and not isinstance(ent, typ):
1500 return None
1501 return ent
1502
1503 def lookup_type(self, name):
1504 return self.lookup_entity(name, QAPISchemaType)
1505
Eric Blake861877a2016-03-17 16:48:36 -06001506 def _def_builtin_type(self, name, json_type, c_type):
1507 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001508 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1509 # qapi-types.h from a single .c, all arrays of builtins must be
1510 # declared in the first file whether or not they are used. Nicer
1511 # would be to use lazy instantiation, while figuring out how to
1512 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001513 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001514
1515 def _def_predefineds(self):
Eric Blake861877a2016-03-17 16:48:36 -06001516 for t in [('str', 'string', 'char' + pointer_suffix),
1517 ('number', 'number', 'double'),
1518 ('int', 'int', 'int64_t'),
1519 ('int8', 'int', 'int8_t'),
1520 ('int16', 'int', 'int16_t'),
1521 ('int32', 'int', 'int32_t'),
1522 ('int64', 'int', 'int64_t'),
1523 ('uint8', 'int', 'uint8_t'),
1524 ('uint16', 'int', 'uint16_t'),
1525 ('uint32', 'int', 'uint32_t'),
1526 ('uint64', 'int', 'uint64_t'),
1527 ('size', 'int', 'uint64_t'),
1528 ('bool', 'boolean', 'bool'),
1529 ('any', 'value', 'QObject' + pointer_suffix)]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001530 self._def_builtin_type(*t)
Eric Blake75996972016-03-17 16:48:29 -06001531 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1532 None, [], None)
Markus Armbruster39a18152015-09-16 13:06:28 +02001533 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001534 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1535 'qstring', 'qdict', 'qlist',
1536 'qfloat', 'qbool'])
1537 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001538 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001539
Eric Blake93bda4d2015-12-01 22:20:55 -07001540 def _make_enum_members(self, values):
1541 return [QAPISchemaMember(v) for v in values]
1542
Eric Blake99df5282015-10-12 22:22:32 -06001543 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001544 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001545 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001546 self._def_entity(QAPISchemaEnumType(
1547 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001548 return name
1549
Eric Blake99df5282015-10-12 22:22:32 -06001550 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001551 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001552 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001553 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001554 return name
1555
Eric Blake99df5282015-10-12 22:22:32 -06001556 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001557 if not members:
1558 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001559 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake75996972016-03-17 16:48:29 -06001560 name = 'q_obj_%s-%s' % (name, role)
Markus Armbrusterac882192015-09-16 13:06:05 +02001561 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001562 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001563 members, None))
1564 return name
1565
1566 def _def_enum_type(self, expr, info):
1567 name = expr['enum']
1568 data = expr['data']
1569 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001570 self._def_entity(QAPISchemaEnumType(
1571 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001572
Eric Blake99df5282015-10-12 22:22:32 -06001573 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001574 optional = False
1575 if name.startswith('*'):
1576 name = name[1:]
1577 optional = True
1578 if isinstance(typ, list):
1579 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001580 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001581 return QAPISchemaObjectTypeMember(name, typ, optional)
1582
Eric Blake99df5282015-10-12 22:22:32 -06001583 def _make_members(self, data, info):
1584 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001585 for (key, value) in data.iteritems()]
1586
1587 def _def_struct_type(self, expr, info):
1588 name = expr['struct']
1589 base = expr.get('base')
1590 data = expr['data']
1591 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001592 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001593 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001594
1595 def _make_variant(self, case, typ):
1596 return QAPISchemaObjectTypeVariant(case, typ)
1597
Eric Blake99df5282015-10-12 22:22:32 -06001598 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001599 if isinstance(typ, list):
1600 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001601 typ = self._make_array_type(typ[0], info)
1602 typ = self._make_implicit_object_type(
1603 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001604 return QAPISchemaObjectTypeVariant(case, typ)
1605
Markus Armbrusterac882192015-09-16 13:06:05 +02001606 def _def_union_type(self, expr, info):
1607 name = expr['union']
1608 data = expr['data']
1609 base = expr.get('base')
1610 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001611 tag_member = None
Eric Blakeac4338f2016-03-17 16:48:39 -06001612 if isinstance(base, dict):
1613 base = (self._make_implicit_object_type(
1614 name, info, 'base', self._make_members(base, info)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001615 if tag_name:
1616 variants = [self._make_variant(key, value)
1617 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001618 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001619 else:
Eric Blake99df5282015-10-12 22:22:32 -06001620 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001621 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001622 typ = self._make_implicit_enum_type(name, info,
1623 [v.name for v in variants])
1624 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001625 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001626 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001627 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001628 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001629 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001630 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001631
1632 def _def_alternate_type(self, expr, info):
1633 name = expr['alternate']
1634 data = expr['data']
1635 variants = [self._make_variant(key, value)
1636 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001637 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001638 self._def_entity(
1639 QAPISchemaAlternateType(name, info,
1640 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001641 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001642 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001643
1644 def _def_command(self, expr, info):
1645 name = expr['command']
1646 data = expr.get('data')
1647 rets = expr.get('returns')
1648 gen = expr.get('gen', True)
1649 success_response = expr.get('success-response', True)
Eric Blake48825ca2016-07-13 21:50:19 -06001650 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001651 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001652 data = self._make_implicit_object_type(
1653 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001654 if isinstance(rets, list):
1655 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001656 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001657 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
Eric Blake48825ca2016-07-13 21:50:19 -06001658 success_response, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001659
1660 def _def_event(self, expr, info):
1661 name = expr['event']
1662 data = expr.get('data')
Eric Blake48825ca2016-07-13 21:50:19 -06001663 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001664 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001665 data = self._make_implicit_object_type(
1666 name, info, 'arg', self._make_members(data, info))
Eric Blake48825ca2016-07-13 21:50:19 -06001667 self._def_entity(QAPISchemaEvent(name, info, data, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001668
1669 def _def_exprs(self):
1670 for expr_elem in self.exprs:
1671 expr = expr_elem['expr']
1672 info = expr_elem['info']
1673 if 'enum' in expr:
1674 self._def_enum_type(expr, info)
1675 elif 'struct' in expr:
1676 self._def_struct_type(expr, info)
1677 elif 'union' in expr:
1678 self._def_union_type(expr, info)
1679 elif 'alternate' in expr:
1680 self._def_alternate_type(expr, info)
1681 elif 'command' in expr:
1682 self._def_command(expr, info)
1683 elif 'event' in expr:
1684 self._def_event(expr, info)
1685 else:
1686 assert False
1687
1688 def check(self):
1689 for ent in self._entity_dict.values():
1690 ent.check(self)
1691
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001692 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001693 visitor.visit_begin(self)
1694 for (name, entity) in sorted(self._entity_dict.items()):
1695 if visitor.visit_needed(entity):
1696 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001697 visitor.visit_end()
1698
Markus Armbruster2caba362013-07-27 17:41:56 +02001699
Markus Armbruster00e4b282015-06-10 10:04:36 +02001700#
1701# Code generation helpers
1702#
1703
Michael Roth0f923be2011-07-19 14:50:39 -05001704def camel_case(name):
1705 new_name = ''
1706 first = True
1707 for ch in name:
1708 if ch in ['_', '-']:
1709 first = True
1710 elif first:
1711 new_name += ch.upper()
1712 first = False
1713 else:
1714 new_name += ch.lower()
1715 return new_name
1716
Eric Blake437db252015-09-29 16:21:02 -06001717
Markus Armbruster849bc532015-05-14 06:50:53 -06001718# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1719# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1720# ENUM24_Name -> ENUM24_NAME
1721def camel_to_upper(value):
1722 c_fun_str = c_name(value, False)
1723 if value.isupper():
1724 return c_fun_str
1725
1726 new_name = ''
1727 l = len(c_fun_str)
1728 for i in range(l):
1729 c = c_fun_str[i]
1730 # When c is upper and no "_" appears before, do more checks
1731 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001732 if i < l - 1 and c_fun_str[i + 1].islower():
1733 new_name += '_'
1734 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001735 new_name += '_'
1736 new_name += c
1737 return new_name.lstrip('_').upper()
1738
Eric Blake437db252015-09-29 16:21:02 -06001739
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001740def c_enum_const(type_name, const_name, prefix=None):
1741 if prefix is not None:
1742 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001743 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001744
Eric Blake18df5152015-05-14 06:50:48 -06001745c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001746
Eric Blake437db252015-09-29 16:21:02 -06001747
Eric Blakec6405b52015-05-14 06:50:55 -06001748# Map @name to a valid C identifier.
1749# If @protect, avoid returning certain ticklish identifiers (like
1750# C keywords) by prepending "q_".
1751#
1752# Used for converting 'name' from a 'name':'type' qapi definition
1753# into a generated struct member, as well as converting type names
1754# into substrings of a generated C function name.
1755# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1756# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001757def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001758 # ANSI X3J11/88-090, 3.1.1
1759 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001760 'default', 'do', 'double', 'else', 'enum', 'extern',
1761 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1762 'return', 'short', 'signed', 'sizeof', 'static',
1763 'struct', 'switch', 'typedef', 'union', 'unsigned',
1764 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001765 # ISO/IEC 9899:1999, 6.4.1
1766 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1767 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001768 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1769 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001770 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1771 # excluding _.*
1772 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001773 # C++ ISO/IEC 14882:2003 2.11
1774 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1775 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1776 'namespace', 'new', 'operator', 'private', 'protected',
1777 'public', 'reinterpret_cast', 'static_cast', 'template',
1778 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1779 'using', 'virtual', 'wchar_t',
1780 # alternative representations
1781 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1782 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001783 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001784 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001785 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001786 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1787 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001788 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001789 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001790
Amos Kong05dfb262014-06-10 19:25:53 +08001791eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001792pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001793
Eric Blake437db252015-09-29 16:21:02 -06001794
Michael Roth0f923be2011-07-19 14:50:39 -05001795def genindent(count):
1796 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001797 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001798 ret += " "
1799 return ret
1800
1801indent_level = 0
1802
Eric Blake437db252015-09-29 16:21:02 -06001803
Michael Roth0f923be2011-07-19 14:50:39 -05001804def push_indent(indent_amount=4):
1805 global indent_level
1806 indent_level += indent_amount
1807
Eric Blake437db252015-09-29 16:21:02 -06001808
Michael Roth0f923be2011-07-19 14:50:39 -05001809def pop_indent(indent_amount=4):
1810 global indent_level
1811 indent_level -= indent_amount
1812
Eric Blake437db252015-09-29 16:21:02 -06001813
Markus Armbruster77e703b2015-06-24 19:27:32 +02001814# Generate @code with @kwds interpolated.
1815# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001816def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001817 raw = code % kwds
1818 if indent_level:
1819 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001820 # re.subn() lacks flags support before Python 2.7, use re.compile()
1821 raw = re.subn(re.compile("^.", re.MULTILINE),
1822 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001823 raw = raw[0]
1824 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001825
Eric Blake437db252015-09-29 16:21:02 -06001826
Michael Roth0f923be2011-07-19 14:50:39 -05001827def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001828 if code[0] == '\n':
1829 code = code[1:]
1830 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001831
Michael Roth0f923be2011-07-19 14:50:39 -05001832
1833def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001834 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001835
Eric Blake437db252015-09-29 16:21:02 -06001836
Michael Rothc0afa9c2013-05-10 17:46:00 -05001837def guardstart(name):
1838 return mcgen('''
1839
1840#ifndef %(name)s
1841#define %(name)s
1842
1843''',
1844 name=guardname(name))
1845
Eric Blake437db252015-09-29 16:21:02 -06001846
Michael Rothc0afa9c2013-05-10 17:46:00 -05001847def guardend(name):
1848 return mcgen('''
1849
1850#endif /* %(name)s */
1851
1852''',
1853 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001854
Eric Blake437db252015-09-29 16:21:02 -06001855
Markus Armbrustere98859a2015-09-16 13:06:16 +02001856def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001857 ret = mcgen('''
1858
Markus Armbrustere98859a2015-09-16 13:06:16 +02001859const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001860''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001861 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001862 for value in values:
1863 index = c_enum_const(name, value, prefix)
1864 ret += mcgen('''
1865 [%(index)s] = "%(value)s",
1866''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001867 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001868
Eric Blake7fb1cf12015-11-18 01:52:57 -07001869 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001870 ret += mcgen('''
1871 [%(max_index)s] = NULL,
1872};
1873''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001874 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001875 return ret
1876
Eric Blake437db252015-09-29 16:21:02 -06001877
Markus Armbrustere98859a2015-09-16 13:06:16 +02001878def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001879 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001880 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001881
1882 ret = mcgen('''
1883
1884typedef enum %(c_name)s {
1885''',
1886 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001887
1888 i = 0
1889 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001890 ret += mcgen('''
1891 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001892''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001893 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001894 i=i)
1895 i += 1
1896
Markus Armbrustere98859a2015-09-16 13:06:16 +02001897 ret += mcgen('''
1898} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001899''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001900 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001901
Markus Armbrustere98859a2015-09-16 13:06:16 +02001902 ret += mcgen('''
1903
1904extern const char *const %(c_name)s_lookup[];
1905''',
1906 c_name=c_name(name))
1907 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001908
Eric Blake437db252015-09-29 16:21:02 -06001909
Eric Blake48825ca2016-07-13 21:50:19 -06001910def gen_params(arg_type, boxed, extra):
Markus Armbruster03b43672015-09-16 13:06:20 +02001911 if not arg_type:
Eric Blakec8184082016-07-13 21:50:20 -06001912 assert not boxed
Markus Armbruster03b43672015-09-16 13:06:20 +02001913 return extra
Markus Armbruster03b43672015-09-16 13:06:20 +02001914 ret = ''
1915 sep = ''
Eric Blake48825ca2016-07-13 21:50:19 -06001916 if boxed:
Eric Blakec8184082016-07-13 21:50:20 -06001917 ret += '%s arg' % arg_type.c_param_type()
1918 sep = ', '
Eric Blake48825ca2016-07-13 21:50:19 -06001919 else:
1920 assert not arg_type.variants
1921 for memb in arg_type.members:
1922 ret += sep
1923 sep = ', '
1924 if memb.optional:
1925 ret += 'bool has_%s, ' % c_name(memb.name)
1926 ret += '%s %s' % (memb.type.c_param_type(),
1927 c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001928 if extra:
1929 ret += sep + extra
1930 return ret
1931
Eric Blake1f353342015-09-29 16:21:13 -06001932
Markus Armbruster00e4b282015-06-10 10:04:36 +02001933#
1934# Common command line parsing
1935#
1936
Eric Blake437db252015-09-29 16:21:02 -06001937
1938def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001939
1940 try:
1941 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001942 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001943 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001944 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001945 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001946 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001947 sys.exit(1)
1948
1949 output_dir = ""
1950 prefix = ""
1951 do_c = False
1952 do_h = False
1953 extra_opts = []
1954
1955 for oa in opts:
1956 o, a = oa
1957 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001958 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1959 if match.end() != len(a):
1960 print >>sys.stderr, \
1961 "%s: 'funny character '%s' in argument of --prefix" \
1962 % (sys.argv[0], a[match.end()])
1963 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001964 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001965 elif o in ("-o", "--output-dir"):
1966 output_dir = a + "/"
1967 elif o in ("-c", "--source"):
1968 do_c = True
1969 elif o in ("-h", "--header"):
1970 do_h = True
1971 else:
1972 extra_opts.append(oa)
1973
1974 if not do_c and not do_h:
1975 do_c = True
1976 do_h = True
1977
Markus Armbruster16d80f62015-04-02 13:32:16 +02001978 if len(args) != 1:
1979 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001980 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001981 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001982
Markus Armbruster54414042015-06-09 16:22:45 +02001983 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001984
Markus Armbruster00e4b282015-06-10 10:04:36 +02001985#
1986# Generate output files with boilerplate
1987#
1988
Eric Blake437db252015-09-29 16:21:02 -06001989
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001990def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1991 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001992 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001993 c_file = output_dir + prefix + c_file
1994 h_file = output_dir + prefix + h_file
1995
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001996 if output_dir:
1997 try:
1998 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01001999 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02002000 if e.errno != errno.EEXIST:
2001 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002002
2003 def maybe_open(really, name, opt):
2004 if really:
2005 return open(name, opt)
2006 else:
2007 import StringIO
2008 return StringIO.StringIO()
2009
2010 fdef = maybe_open(do_c, c_file, 'w')
2011 fdecl = maybe_open(do_h, h_file, 'w')
2012
2013 fdef.write(mcgen('''
2014/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2015%(comment)s
2016''',
Eric Blake437db252015-09-29 16:21:02 -06002017 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002018
2019 fdecl.write(mcgen('''
2020/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2021%(comment)s
2022#ifndef %(guard)s
2023#define %(guard)s
2024
2025''',
Eric Blake437db252015-09-29 16:21:02 -06002026 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002027
2028 return (fdef, fdecl)
2029
Eric Blake437db252015-09-29 16:21:02 -06002030
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002031def close_output(fdef, fdecl):
2032 fdecl.write('''
2033#endif
2034''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002035 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002036 fdef.close()