blob: 53a44779d0b513c011916d044ba76fb88fe481ac [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)
271 if isinstance(expr, dict) and "include" in expr:
272 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 Armbruster54414042015-06-09 16:22:45 +0200278 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
279 include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200280 # catch inclusion cycle
Marc-André Lureau4148c292017-01-13 15:41:25 +0100281 inf = info
Markus Armbrustera1366082015-06-09 16:54:09 +0200282 while inf:
283 if incl_abs_fname == os.path.abspath(inf['file']):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100284 raise QAPISemError(info, "Inclusion loop for %s"
285 % include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200286 inf = inf['parent']
Marc-André Lureau3313b612017-01-13 15:41:29 +0100287
Benoît Canet24fd8482014-05-16 12:51:56 +0200288 # skip multiple include of the same file
Markus Armbruster54414042015-06-09 16:22:45 +0200289 if incl_abs_fname in previously_included:
Benoît Canet24fd8482014-05-16 12:51:56 +0200290 continue
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200291 try:
Markus Armbruster54414042015-06-09 16:22:45 +0200292 fobj = open(incl_abs_fname, 'r')
Markus Armbruster291928a2015-12-18 08:52:41 +0100293 except IOError as e:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100294 raise QAPISemError(info, '%s: %s' % (e.strerror, include))
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200295 exprs_include = QAPISchemaParser(fobj, previously_included,
Marc-André Lureau4148c292017-01-13 15:41:25 +0100296 info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200297 self.exprs.extend(exprs_include.exprs)
Marc-André Lureau3313b612017-01-13 15:41:29 +0100298 self.docs.extend(exprs_include.docs)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200299 else:
300 expr_elem = {'expr': expr,
Marc-André Lureau4148c292017-01-13 15:41:25 +0100301 'info': info}
Marc-André Lureau3313b612017-01-13 15:41:29 +0100302 if (self.docs
303 and self.docs[-1].info['file'] == fname
304 and not self.docs[-1].expr):
305 self.docs[-1].expr = expr
306 expr_elem['doc'] = self.docs[-1]
307
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200308 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500309
Marc-André Lureau3313b612017-01-13 15:41:29 +0100310 def accept(self, skip_comment=True):
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200311 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200312 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200313 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200314 self.cursor += 1
315 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500316
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200317 if self.tok == '#':
Marc-André Lureau3313b612017-01-13 15:41:29 +0100318 if self.src[self.cursor] == '#':
319 # Start of doc comment
320 skip_comment = False
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200321 self.cursor = self.src.find('\n', self.cursor)
Marc-André Lureau3313b612017-01-13 15:41:29 +0100322 if not skip_comment:
323 self.val = self.src[self.pos:self.cursor]
324 return
Eric Blake8712fa52015-10-26 16:34:41 -0600325 elif self.tok in "{}:,[]":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200326 return
327 elif self.tok == "'":
328 string = ''
329 esc = False
330 while True:
331 ch = self.src[self.cursor]
332 self.cursor += 1
333 if ch == '\n':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100334 raise QAPIParseError(self, 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200335 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600336 if ch == 'b':
337 string += '\b'
338 elif ch == 'f':
339 string += '\f'
340 elif ch == 'n':
341 string += '\n'
342 elif ch == 'r':
343 string += '\r'
344 elif ch == 't':
345 string += '\t'
346 elif ch == 'u':
347 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600348 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600349 ch = self.src[self.cursor]
350 self.cursor += 1
351 if ch not in "0123456789abcdefABCDEF":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100352 raise QAPIParseError(self,
353 '\\u escape needs 4 '
354 'hex digits')
Eric Blakea7f59662015-05-04 09:05:36 -0600355 value = (value << 4) + int(ch, 16)
356 # If Python 2 and 3 didn't disagree so much on
357 # how to handle Unicode, then we could allow
358 # Unicode string defaults. But most of QAPI is
359 # ASCII-only, so we aren't losing much for now.
360 if not value or value > 0x7f:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100361 raise QAPIParseError(self,
362 'For now, \\u escape '
363 'only supports non-zero '
364 'values up to \\u007f')
Eric Blakea7f59662015-05-04 09:05:36 -0600365 string += chr(value)
366 elif ch in "\\/'\"":
367 string += ch
368 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100369 raise QAPIParseError(self,
370 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200371 esc = False
372 elif ch == "\\":
373 esc = True
374 elif ch == "'":
375 self.val = string
376 return
377 else:
378 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200379 elif self.src.startswith("true", self.pos):
380 self.val = True
381 self.cursor += 3
382 return
383 elif self.src.startswith("false", self.pos):
384 self.val = False
385 self.cursor += 4
386 return
387 elif self.src.startswith("null", self.pos):
388 self.val = None
389 self.cursor += 3
390 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200391 elif self.tok == '\n':
392 if self.cursor == len(self.src):
393 self.tok = None
394 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800395 self.line += 1
396 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200397 elif not self.tok.isspace():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100398 raise QAPIParseError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500399
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200400 def get_members(self):
401 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200402 if self.tok == '}':
403 self.accept()
404 return expr
405 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100406 raise QAPIParseError(self, 'Expected string or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200407 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200408 key = self.val
409 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200410 if self.tok != ':':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100411 raise QAPIParseError(self, 'Expected ":"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200412 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800413 if key in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100414 raise QAPIParseError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200415 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200416 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200417 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200418 return expr
419 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100420 raise QAPIParseError(self, 'Expected "," or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200421 self.accept()
422 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100423 raise QAPIParseError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500424
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200425 def get_values(self):
426 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200427 if self.tok == ']':
428 self.accept()
429 return expr
Eric Blake437db252015-09-29 16:21:02 -0600430 if self.tok not in "{['tfn":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100431 raise QAPIParseError(self, 'Expected "{", "[", "]", string, '
432 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200433 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200434 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200435 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200436 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200437 return expr
438 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100439 raise QAPIParseError(self, 'Expected "," or "]"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200440 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500441
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200442 def get_expr(self, nested):
443 if self.tok != '{' and not nested:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100444 raise QAPIParseError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200445 if self.tok == '{':
446 self.accept()
447 expr = self.get_members()
448 elif self.tok == '[':
449 self.accept()
450 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600451 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200452 expr = self.val
453 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200454 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100455 raise QAPIParseError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200456 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200457
Marc-André Lureau3313b612017-01-13 15:41:29 +0100458 def get_doc(self, info):
459 if self.val != '##':
460 raise QAPIParseError(self, "Junk after '##' at start of "
461 "documentation comment")
462
463 doc = QAPIDoc(self, info)
464 self.accept(False)
465 while self.tok == '#':
466 if self.val.startswith('##'):
467 # End of doc comment
468 if self.val != '##':
469 raise QAPIParseError(self, "Junk after '##' at end of "
470 "documentation comment")
471 self.accept()
472 return doc
473 else:
474 doc.append(self.val)
475 self.accept(False)
476
477 raise QAPIParseError(self, "Documentation comment must end with '##'")
478
479
Markus Armbruster00e4b282015-06-10 10:04:36 +0200480#
481# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200482# TODO fold into QAPISchema
483# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200484#
485
Eric Blake437db252015-09-29 16:21:02 -0600486
Eric Blake14f00c62016-03-03 09:16:43 -0700487def find_base_members(base):
Eric Blakeac4338f2016-03-17 16:48:39 -0600488 if isinstance(base, dict):
489 return base
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800490 base_struct_define = find_struct(base)
491 if not base_struct_define:
492 return None
493 return base_struct_define['data']
494
Eric Blake437db252015-09-29 16:21:02 -0600495
Eric Blake811d04f2015-05-04 09:05:10 -0600496# Return the qtype of an alternate branch, or None on error.
497def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600498 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600499 return builtin_types[qapi_type]
500 elif find_struct(qapi_type):
501 return "QTYPE_QDICT"
502 elif find_enum(qapi_type):
503 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600504 elif find_union(qapi_type):
505 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600506 return None
507
Eric Blake437db252015-09-29 16:21:02 -0600508
Wenchao Xiabceae762014-03-06 17:08:56 -0800509# Return the discriminator enum define if discriminator is specified as an
510# enum type, otherwise return None.
511def discriminator_find_enum_define(expr):
512 base = expr.get('base')
513 discriminator = expr.get('discriminator')
514
515 if not (discriminator and base):
516 return None
517
Eric Blake14f00c62016-03-03 09:16:43 -0700518 base_members = find_base_members(base)
519 if not base_members:
Wenchao Xiabceae762014-03-06 17:08:56 -0800520 return None
521
Eric Blake14f00c62016-03-03 09:16:43 -0700522 discriminator_type = base_members.get(discriminator)
Wenchao Xiabceae762014-03-06 17:08:56 -0800523 if not discriminator_type:
524 return None
525
526 return find_enum(discriminator_type)
527
Eric Blake437db252015-09-29 16:21:02 -0600528
Eric Blake59a92fe2015-11-18 01:52:56 -0700529# Names must be letters, numbers, -, and _. They must start with letter,
530# except for downstream extensions which must start with __RFQDN_.
531# Dots are only valid in the downstream extension prefix.
532valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
533 '[a-zA-Z][a-zA-Z0-9_-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600534
535
Marc-André Lureau4148c292017-01-13 15:41:25 +0100536def check_name(info, source, name, allow_optional=False,
Eric Blake437db252015-09-29 16:21:02 -0600537 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600538 global valid_name
539 membername = name
540
541 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100542 raise QAPISemError(info, "%s requires a string name" % source)
Eric Blakec9e0a792015-05-04 09:05:22 -0600543 if name.startswith('*'):
544 membername = name[1:]
545 if not allow_optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100546 raise QAPISemError(info, "%s does not allow optional name '%s'"
547 % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600548 # Enum members can start with a digit, because the generated C
549 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700550 if enum_member and membername[0].isdigit():
551 membername = 'D' + membername
Eric Blake75996972016-03-17 16:48:29 -0600552 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
553 # and 'q_obj_*' implicit type names.
Eric Blake9fb081e2015-10-26 16:34:44 -0600554 if not valid_name.match(membername) or \
555 c_name(membername, False).startswith('q_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100556 raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600557
Eric Blake437db252015-09-29 16:21:02 -0600558
559def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200560 global all_names
561 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200562 # FIXME should reject names that differ only in '_' vs. '.'
563 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200564 if name in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100565 raise QAPISemError(info, "%s '%s' is already defined"
566 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600567 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100568 raise QAPISemError(info, "%s '%s' should not end in '%s'"
569 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200570 all_names[name] = meta
571
Eric Blake437db252015-09-29 16:21:02 -0600572
Markus Armbruster00e4b282015-06-10 10:04:36 +0200573def add_struct(definition, info):
574 global struct_types
575 name = definition['struct']
576 add_name(name, info, 'struct')
577 struct_types.append(definition)
578
Eric Blake437db252015-09-29 16:21:02 -0600579
Markus Armbruster00e4b282015-06-10 10:04:36 +0200580def find_struct(name):
581 global struct_types
582 for struct in struct_types:
583 if struct['struct'] == name:
584 return struct
585 return None
586
Eric Blake437db252015-09-29 16:21:02 -0600587
Markus Armbruster00e4b282015-06-10 10:04:36 +0200588def add_union(definition, info):
589 global union_types
590 name = definition['union']
591 add_name(name, info, 'union')
592 union_types.append(definition)
593
Eric Blake437db252015-09-29 16:21:02 -0600594
Markus Armbruster00e4b282015-06-10 10:04:36 +0200595def find_union(name):
596 global union_types
597 for union in union_types:
598 if union['union'] == name:
599 return union
600 return None
601
Eric Blake437db252015-09-29 16:21:02 -0600602
603def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200604 global enum_types
605 add_name(name, info, 'enum', implicit)
606 enum_types.append({"enum_name": name, "enum_values": enum_values})
607
Eric Blake437db252015-09-29 16:21:02 -0600608
Markus Armbruster00e4b282015-06-10 10:04:36 +0200609def find_enum(name):
610 global enum_types
611 for enum in enum_types:
612 if enum['enum_name'] == name:
613 return enum
614 return None
615
Markus Armbruster00e4b282015-06-10 10:04:36 +0200616
Eric Blake437db252015-09-29 16:21:02 -0600617def is_enum(name):
618 return find_enum(name) is not None
619
620
Marc-André Lureau4148c292017-01-13 15:41:25 +0100621def check_type(info, source, value, allow_array=False,
Eric Blake437db252015-09-29 16:21:02 -0600622 allow_dict=False, allow_optional=False,
623 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600624 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600625
626 if value is None:
627 return
628
Eric Blakedd883c62015-05-04 09:05:21 -0600629 # Check if array type for value is okay
630 if isinstance(value, list):
631 if not allow_array:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100632 raise QAPISemError(info, "%s cannot be an array" % source)
Eric Blakedd883c62015-05-04 09:05:21 -0600633 if len(value) != 1 or not isinstance(value[0], str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100634 raise QAPISemError(info,
635 "%s: array type must contain single type name" %
636 source)
Eric Blakedd883c62015-05-04 09:05:21 -0600637 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600638
639 # Check if type name for value is okay
640 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600641 if value not in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100642 raise QAPISemError(info, "%s uses unknown type '%s'"
643 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600644 if not all_names[value] in allow_metas:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100645 raise QAPISemError(info, "%s cannot use %s type '%s'" %
646 (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600647 return
648
Eric Blakedd883c62015-05-04 09:05:21 -0600649 if not allow_dict:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100650 raise QAPISemError(info, "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200651
652 if not isinstance(value, OrderedDict):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100653 raise QAPISemError(info,
654 "%s should be a dictionary or type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200655
656 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600657 for (key, arg) in value.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100658 check_name(info, "Member of %s" % source, key,
Eric Blakec9e0a792015-05-04 09:05:22 -0600659 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600660 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100661 raise QAPISemError(info, "Member of %s uses reserved name '%s'"
662 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600663 # Todo: allow dictionaries to represent default values of
664 # an optional argument.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100665 check_type(info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200666 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600667 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600668 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600669
Eric Blake437db252015-09-29 16:21:02 -0600670
Marc-André Lureau4148c292017-01-13 15:41:25 +0100671def check_command(expr, info):
Eric Blakedd883c62015-05-04 09:05:21 -0600672 name = expr['command']
Eric Blakec8184082016-07-13 21:50:20 -0600673 boxed = expr.get('boxed', False)
Eric Blake2cbf0992015-05-04 09:05:24 -0600674
Eric Blakec8184082016-07-13 21:50:20 -0600675 args_meta = ['struct']
676 if boxed:
677 args_meta += ['union', 'alternate']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100678 check_type(info, "'data' for command '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600679 expr.get('data'), allow_dict=not boxed, allow_optional=True,
680 allow_metas=args_meta)
Eric Blake10d4d992015-05-04 09:05:23 -0600681 returns_meta = ['union', 'struct']
682 if name in returns_whitelist:
683 returns_meta += ['built-in', 'alternate', 'enum']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100684 check_type(info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200685 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200686 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600687
Eric Blake437db252015-09-29 16:21:02 -0600688
Marc-André Lureau4148c292017-01-13 15:41:25 +0100689def check_event(expr, info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600690 global events
691 name = expr['event']
Eric Blakec8184082016-07-13 21:50:20 -0600692 boxed = expr.get('boxed', False)
Eric Blake4dc2e692015-05-04 09:05:17 -0600693
Eric Blakec8184082016-07-13 21:50:20 -0600694 meta = ['struct']
695 if boxed:
696 meta += ['union', 'alternate']
Eric Blake4dc2e692015-05-04 09:05:17 -0600697 events.append(name)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100698 check_type(info, "'data' for event '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600699 expr.get('data'), allow_dict=not boxed, allow_optional=True,
700 allow_metas=meta)
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200701
Eric Blake437db252015-09-29 16:21:02 -0600702
Marc-André Lureau4148c292017-01-13 15:41:25 +0100703def check_union(expr, info):
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800704 name = expr['union']
705 base = expr.get('base')
706 discriminator = expr.get('discriminator')
707 members = expr['data']
708
Eric Blake811d04f2015-05-04 09:05:10 -0600709 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600710
711 # With no discriminator it is a simple union.
712 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600713 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600714 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600715 if base is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100716 raise QAPISemError(info, "Simple union '%s' must not have a base" %
717 name)
Eric Blake44bd1272015-05-04 09:05:08 -0600718
719 # Else, it's a flat union.
720 else:
Eric Blakeac4338f2016-03-17 16:48:39 -0600721 # The object must have a string or dictionary 'base'.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100722 check_type(info, "'base' for union '%s'" % name,
Eric Blakeac4338f2016-03-17 16:48:39 -0600723 base, allow_dict=True, allow_optional=True,
724 allow_metas=['struct'])
Eric Blake376863e2015-09-29 16:21:07 -0600725 if not base:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100726 raise QAPISemError(info, "Flat union '%s' must have a base"
727 % name)
Eric Blake14f00c62016-03-03 09:16:43 -0700728 base_members = find_base_members(base)
729 assert base_members
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800730
Eric Blakec9e0a792015-05-04 09:05:22 -0600731 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600732 # member of the base struct.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100733 check_name(info, "Discriminator of flat union '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600734 discriminator)
Eric Blake14f00c62016-03-03 09:16:43 -0700735 discriminator_type = base_members.get(discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800736 if not discriminator_type:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100737 raise QAPISemError(info,
738 "Discriminator '%s' is not a member of base "
739 "struct '%s'"
740 % (discriminator, base))
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800741 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600742 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800743 # Do not allow string discriminator
744 if not enum_define:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100745 raise QAPISemError(info,
746 "Discriminator '%s' must be of enumeration "
747 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800748
Eric Blake02a57ae2016-02-17 23:48:16 -0700749 # Check every branch; don't allow an empty union
750 if len(members) == 0:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100751 raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800752 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100753 check_name(info, "Member of union '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600754
Eric Blake01cfbaa2015-12-01 22:20:58 -0700755 # Each value must name a known type
Marc-André Lureau4148c292017-01-13 15:41:25 +0100756 check_type(info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200757 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600758
Eric Blake44bd1272015-05-04 09:05:08 -0600759 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700760 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600761 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600762 if key not in enum_define['enum_values']:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100763 raise QAPISemError(info,
764 "Discriminator value '%s' is not found in "
765 "enum '%s'"
766 % (key, enum_define["enum_name"]))
Eric Blake44bd1272015-05-04 09:05:08 -0600767
Eric Blaked0b18232016-07-13 21:50:13 -0600768 # If discriminator is user-defined, ensure all values are covered
769 if enum_define:
770 for value in enum_define['enum_values']:
771 if value not in members.keys():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100772 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
773 % (name, value))
Eric Blaked0b18232016-07-13 21:50:13 -0600774
Eric Blake437db252015-09-29 16:21:02 -0600775
Marc-André Lureau4148c292017-01-13 15:41:25 +0100776def check_alternate(expr, info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600777 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600778 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600779 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600780
Eric Blake02a57ae2016-02-17 23:48:16 -0700781 # Check every branch; require at least two branches
782 if len(members) < 2:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100783 raise QAPISemError(info,
784 "Alternate '%s' should have at least two branches "
785 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600786 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100787 check_name(info, "Member of alternate '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600788
Eric Blake811d04f2015-05-04 09:05:10 -0600789 # Ensure alternates have no type conflicts.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100790 check_type(info, "Member '%s' of alternate '%s'" % (key, name),
Eric Blakedd883c62015-05-04 09:05:21 -0600791 value,
792 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600793 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700794 if not qtype:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100795 raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
796 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600797 if qtype in types_seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100798 raise QAPISemError(info, "Alternate '%s' member '%s' can't "
799 "be distinguished from member '%s'"
800 % (name, key, types_seen[qtype]))
Eric Blake811d04f2015-05-04 09:05:10 -0600801 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800802
Eric Blake437db252015-09-29 16:21:02 -0600803
Marc-André Lureau4148c292017-01-13 15:41:25 +0100804def check_enum(expr, info):
Eric Blakecf393592015-05-04 09:05:04 -0600805 name = expr['enum']
806 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100807 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600808
809 if not isinstance(members, list):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100810 raise QAPISemError(info,
811 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100812 if prefix is not None and not isinstance(prefix, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100813 raise QAPISemError(info,
814 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600815 for member in members:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100816 check_name(info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600817 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600818
Eric Blake437db252015-09-29 16:21:02 -0600819
Marc-André Lureau4148c292017-01-13 15:41:25 +0100820def check_struct(expr, info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600821 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600822 members = expr['data']
823
Marc-André Lureau4148c292017-01-13 15:41:25 +0100824 check_type(info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600825 allow_dict=True, allow_optional=True)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100826 check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600827 allow_metas=['struct'])
828
Eric Blake437db252015-09-29 16:21:02 -0600829
Eric Blake0545f6b2015-05-04 09:05:15 -0600830def check_keys(expr_elem, meta, required, optional=[]):
831 expr = expr_elem['expr']
832 info = expr_elem['info']
833 name = expr[meta]
834 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100835 raise QAPISemError(info, "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600836 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600837 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600838 if key not in required and key not in optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100839 raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
840 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600841 if (key == 'gen' or key == 'success-response') and value is not False:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100842 raise QAPISemError(info,
843 "'%s' of %s '%s' should only use false value"
844 % (key, meta, name))
Eric Blakec8184082016-07-13 21:50:20 -0600845 if key == 'boxed' and value is not True:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100846 raise QAPISemError(info,
847 "'%s' of %s '%s' should only use true value"
848 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600849 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600850 if key not in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100851 raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
852 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600853
Eric Blake437db252015-09-29 16:21:02 -0600854
Markus Armbruster4d076d62015-06-10 08:55:21 +0200855def check_exprs(exprs):
856 global all_names
857
858 # Learn the types and check for valid expression keys
859 for builtin in builtin_types.keys():
860 all_names[builtin] = 'built-in'
861 for expr_elem in exprs:
862 expr = expr_elem['expr']
863 info = expr_elem['info']
Marc-André Lureau3313b612017-01-13 15:41:29 +0100864
865 if 'doc' not in expr_elem:
866 raise QAPISemError(info,
867 "Expression missing documentation comment")
868
Eric Blake437db252015-09-29 16:21:02 -0600869 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100870 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200871 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600872 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200873 check_keys(expr_elem, 'union', ['data'],
874 ['base', 'discriminator'])
875 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600876 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200877 check_keys(expr_elem, 'alternate', ['data'])
878 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600879 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200880 check_keys(expr_elem, 'struct', ['data'], ['base'])
881 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600882 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200883 check_keys(expr_elem, 'command', [],
Eric Blakec8184082016-07-13 21:50:20 -0600884 ['data', 'returns', 'gen', 'success-response', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200885 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600886 elif 'event' in expr:
Eric Blakec8184082016-07-13 21:50:20 -0600887 check_keys(expr_elem, 'event', [], ['data', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200888 add_name(expr['event'], info, 'event')
889 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100890 raise QAPISemError(expr_elem['info'],
891 "Expression is missing metatype")
Markus Armbruster4d076d62015-06-10 08:55:21 +0200892
893 # Try again for hidden UnionKind enum
894 for expr_elem in exprs:
895 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600896 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200897 if not discriminator_find_enum_define(expr):
898 add_enum('%sKind' % expr['union'], expr_elem['info'],
899 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600900 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200901 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
902 implicit=True)
903
904 # Validate that exprs make sense
905 for expr_elem in exprs:
906 expr = expr_elem['expr']
907 info = expr_elem['info']
908
Eric Blake437db252015-09-29 16:21:02 -0600909 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200910 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600911 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200912 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600913 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200914 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600915 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200916 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600917 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200918 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600919 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200920 check_event(expr, info)
921 else:
922 assert False, 'unexpected meta type'
923
Markus Armbrusterac882192015-09-16 13:06:05 +0200924 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600925
Markus Armbrusterac882192015-09-16 13:06:05 +0200926
Marc-André Lureau3313b612017-01-13 15:41:29 +0100927def check_freeform_doc(doc):
928 if doc.symbol:
929 raise QAPISemError(doc.info,
930 "Documention for '%s' is not followed"
931 " by the definition" % doc.symbol)
932
933 body = str(doc.body)
934 if re.search(r'@\S+:', body, re.MULTILINE):
935 raise QAPISemError(doc.info,
936 "Free-form documentation block must not contain"
937 " @NAME: sections")
938
939
940def check_definition_doc(doc, expr, info):
941 for i in ('enum', 'union', 'alternate', 'struct', 'command', 'event'):
942 if i in expr:
943 meta = i
944 break
945
946 name = expr[meta]
947 if doc.symbol != name:
948 raise QAPISemError(info, "Definition of '%s' follows documentation"
949 " for '%s'" % (name, doc.symbol))
950 if doc.has_section('Returns') and 'command' not in expr:
951 raise QAPISemError(info, "'Returns:' is only valid for commands")
952
953 if meta == 'union':
954 args = expr.get('base', [])
955 else:
956 args = expr.get('data', [])
957 if isinstance(args, str):
958 return
959 if isinstance(args, dict):
960 args = args.keys()
961 assert isinstance(args, list)
962
963 if (meta == 'alternate'
964 or (meta == 'union' and not expr.get('discriminator'))):
965 args.append('type')
966
967 for arg in args:
968 if arg[0] == '*':
969 opt = True
970 desc = doc.args.get(arg[1:])
971 else:
972 opt = False
973 desc = doc.args.get(arg)
974 if not desc:
975 continue
976 desc_opt = "#optional" in str(desc)
977 if desc_opt and not opt:
978 raise QAPISemError(info, "Description has #optional, "
979 "but the declaration doesn't")
980 if not desc_opt and opt:
981 # silently fix the doc
982 # TODO either fix the schema and make this an error,
983 # or drop #optional entirely
984 desc.append("#optional")
985
986 doc_args = set(doc.args.keys())
987 args = set([name.strip('*') for name in args])
988 if not doc_args.issubset(args):
989 raise QAPISemError(info, "The following documented members are not in "
990 "the declaration: %s" % ", ".join(doc_args - args))
991
992
993def check_docs(docs):
994 for doc in docs:
995 for section in doc.args.values() + doc.sections:
996 content = str(section)
997 if not content or content.isspace():
998 raise QAPISemError(doc.info,
999 "Empty doc section '%s'" % section.name)
1000
1001 if not doc.expr:
1002 check_freeform_doc(doc)
1003 else:
1004 check_definition_doc(doc, doc.expr, doc.info)
1005
1006 return docs
1007
1008
Markus Armbrusterac882192015-09-16 13:06:05 +02001009#
1010# Schema compiler frontend
1011#
1012
1013class QAPISchemaEntity(object):
1014 def __init__(self, name, info):
1015 assert isinstance(name, str)
1016 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -06001017 # For explicitly defined entities, info points to the (explicit)
1018 # definition. For builtins (and their arrays), info is None.
1019 # For implicitly defined entities, info points to a place that
1020 # triggered the implicit definition (there may be more than one
1021 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +02001022 self.info = info
1023
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001024 def c_name(self):
1025 return c_name(self.name)
1026
Markus Armbrusterac882192015-09-16 13:06:05 +02001027 def check(self, schema):
1028 pass
1029
Eric Blake49823c42015-10-12 22:22:27 -06001030 def is_implicit(self):
1031 return not self.info
1032
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001033 def visit(self, visitor):
1034 pass
1035
1036
1037class QAPISchemaVisitor(object):
1038 def visit_begin(self, schema):
1039 pass
1040
1041 def visit_end(self):
1042 pass
1043
Eric Blake25a0d9c2015-10-12 22:22:21 -06001044 def visit_needed(self, entity):
1045 # Default to visiting everything
1046 return True
1047
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001048 def visit_builtin_type(self, name, info, json_type):
1049 pass
1050
1051 def visit_enum_type(self, name, info, values, prefix):
1052 pass
1053
1054 def visit_array_type(self, name, info, element_type):
1055 pass
1056
1057 def visit_object_type(self, name, info, base, members, variants):
1058 pass
1059
Markus Armbruster39a18152015-09-16 13:06:28 +02001060 def visit_object_type_flat(self, name, info, members, variants):
1061 pass
1062
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001063 def visit_alternate_type(self, name, info, variants):
1064 pass
1065
1066 def visit_command(self, name, info, arg_type, ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001067 gen, success_response, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001068 pass
1069
Eric Blake48825ca2016-07-13 21:50:19 -06001070 def visit_event(self, name, info, arg_type, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001071 pass
1072
Markus Armbrusterac882192015-09-16 13:06:05 +02001073
1074class QAPISchemaType(QAPISchemaEntity):
Eric Blake4040d992016-03-17 16:48:28 -06001075 # Return the C type for common use.
1076 # For the types we commonly box, this is a pointer type.
1077 def c_type(self):
1078 pass
1079
1080 # Return the C type to be used in a parameter list.
1081 def c_param_type(self):
1082 return self.c_type()
1083
1084 # Return the C type to be used where we suppress boxing.
1085 def c_unboxed_type(self):
1086 return self.c_type()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001087
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001088 def json_type(self):
1089 pass
1090
1091 def alternate_qtype(self):
1092 json2qtype = {
1093 'string': 'QTYPE_QSTRING',
1094 'number': 'QTYPE_QFLOAT',
1095 'int': 'QTYPE_QINT',
1096 'boolean': 'QTYPE_QBOOL',
1097 'object': 'QTYPE_QDICT'
1098 }
1099 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +02001100
1101
1102class QAPISchemaBuiltinType(QAPISchemaType):
Eric Blake861877a2016-03-17 16:48:36 -06001103 def __init__(self, name, json_type, c_type):
Markus Armbrusterac882192015-09-16 13:06:05 +02001104 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001105 assert not c_type or isinstance(c_type, str)
1106 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
1107 'value')
1108 self._json_type_name = json_type
1109 self._c_type_name = c_type
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001110
1111 def c_name(self):
1112 return self.name
1113
Eric Blake4040d992016-03-17 16:48:28 -06001114 def c_type(self):
1115 return self._c_type_name
1116
1117 def c_param_type(self):
1118 if self.name == 'str':
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001119 return 'const ' + self._c_type_name
1120 return self._c_type_name
1121
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001122 def json_type(self):
1123 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +02001124
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001125 def visit(self, visitor):
1126 visitor.visit_builtin_type(self.name, self.info, self.json_type())
1127
Markus Armbrusterac882192015-09-16 13:06:05 +02001128
1129class QAPISchemaEnumType(QAPISchemaType):
1130 def __init__(self, name, info, values, prefix):
1131 QAPISchemaType.__init__(self, name, info)
1132 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -07001133 assert isinstance(v, QAPISchemaMember)
1134 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001135 assert prefix is None or isinstance(prefix, str)
1136 self.values = values
1137 self.prefix = prefix
1138
1139 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -07001140 seen = {}
1141 for v in self.values:
1142 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001143
Eric Blake99df5282015-10-12 22:22:32 -06001144 def is_implicit(self):
1145 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -06001146 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -06001147
Eric Blake4040d992016-03-17 16:48:28 -06001148 def c_type(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001149 return c_name(self.name)
1150
Eric Blake93bda4d2015-12-01 22:20:55 -07001151 def member_names(self):
1152 return [v.name for v in self.values]
1153
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001154 def json_type(self):
1155 return 'string'
1156
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001157 def visit(self, visitor):
1158 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -07001159 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001160
Markus Armbrusterac882192015-09-16 13:06:05 +02001161
1162class QAPISchemaArrayType(QAPISchemaType):
1163 def __init__(self, name, info, element_type):
1164 QAPISchemaType.__init__(self, name, info)
1165 assert isinstance(element_type, str)
1166 self._element_type_name = element_type
1167 self.element_type = None
1168
1169 def check(self, schema):
1170 self.element_type = schema.lookup_type(self._element_type_name)
1171 assert self.element_type
1172
Eric Blake99df5282015-10-12 22:22:32 -06001173 def is_implicit(self):
1174 return True
1175
Eric Blake4040d992016-03-17 16:48:28 -06001176 def c_type(self):
1177 return c_name(self.name) + pointer_suffix
1178
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001179 def json_type(self):
1180 return 'array'
1181
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001182 def visit(self, visitor):
1183 visitor.visit_array_type(self.name, self.info, self.element_type)
1184
Markus Armbrusterac882192015-09-16 13:06:05 +02001185
1186class QAPISchemaObjectType(QAPISchemaType):
1187 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -07001188 # struct has local_members, optional base, and no variants
1189 # flat union has base, variants, and no local_members
1190 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +02001191 QAPISchemaType.__init__(self, name, info)
1192 assert base is None or isinstance(base, str)
1193 for m in local_members:
1194 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -07001195 m.set_owner(name)
1196 if variants is not None:
1197 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1198 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001199 self._base_name = base
1200 self.base = None
1201 self.local_members = local_members
1202 self.variants = variants
1203 self.members = None
1204
1205 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -07001206 if self.members is False: # check for cycles
Marc-André Lureau4148c292017-01-13 15:41:25 +01001207 raise QAPISemError(self.info,
1208 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001209 if self.members:
1210 return
1211 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -07001212 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +02001213 if self._base_name:
1214 self.base = schema.lookup_type(self._base_name)
1215 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +02001216 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001217 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001218 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001219 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001220 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001221 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +02001222 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001223 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001224 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -07001225 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001226
Eric Blake14f00c62016-03-03 09:16:43 -07001227 # Check that the members of this type do not cause duplicate JSON members,
Eric Blake27b60ab2015-11-18 01:52:51 -07001228 # and update seen to track the members seen so far. Report any errors
1229 # on behalf of info, which is not necessarily self.info
1230 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -07001231 assert not self.variants # not implemented
1232 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -07001233 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -07001234
Eric Blake99df5282015-10-12 22:22:32 -06001235 def is_implicit(self):
Eric Blake75996972016-03-17 16:48:29 -06001236 # See QAPISchema._make_implicit_object_type(), as well as
1237 # _def_predefineds()
1238 return self.name.startswith('q_')
Eric Blake99df5282015-10-12 22:22:32 -06001239
Eric Blakeb6167702016-07-13 21:50:16 -06001240 def is_empty(self):
1241 assert self.members is not None
1242 return not self.members and not self.variants
1243
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001244 def c_name(self):
Eric Blakecd50a252016-07-13 21:50:14 -06001245 assert self.name != 'q_empty'
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001246 return QAPISchemaType.c_name(self)
1247
Eric Blake4040d992016-03-17 16:48:28 -06001248 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001249 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -07001250 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001251
Eric Blake4040d992016-03-17 16:48:28 -06001252 def c_unboxed_type(self):
Eric Blake4040d992016-03-17 16:48:28 -06001253 return c_name(self.name)
1254
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001255 def json_type(self):
1256 return 'object'
1257
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001258 def visit(self, visitor):
1259 visitor.visit_object_type(self.name, self.info,
1260 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001261 visitor.visit_object_type_flat(self.name, self.info,
1262 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001263
Markus Armbrusterac882192015-09-16 13:06:05 +02001264
Eric Blaked44f9ac2015-12-01 22:20:54 -07001265class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001266 role = 'member'
1267
Eric Blaked44f9ac2015-12-01 22:20:54 -07001268 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001269 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001270 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001271 self.owner = None
1272
1273 def set_owner(self, name):
1274 assert not self.owner
1275 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001276
Eric Blake27b60ab2015-11-18 01:52:51 -07001277 def check_clash(self, info, seen):
1278 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001279 if cname.lower() != cname and self.owner not in case_whitelist:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001280 raise QAPISemError(info,
1281 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001282 if cname in seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001283 raise QAPISemError(info, "%s collides with %s" %
1284 (self.describe(), seen[cname].describe()))
Eric Blake27b60ab2015-11-18 01:52:51 -07001285 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001286
Eric Blake88d4ef82015-11-18 01:52:50 -07001287 def _pretty_owner(self):
1288 owner = self.owner
Eric Blake75996972016-03-17 16:48:29 -06001289 if owner.startswith('q_obj_'):
Eric Blake88d4ef82015-11-18 01:52:50 -07001290 # See QAPISchema._make_implicit_object_type() - reverse the
1291 # mapping there to create a nice human-readable description
Eric Blake75996972016-03-17 16:48:29 -06001292 owner = owner[6:]
Eric Blake88d4ef82015-11-18 01:52:50 -07001293 if owner.endswith('-arg'):
1294 return '(parameter of %s)' % owner[:-4]
Eric Blakeac4338f2016-03-17 16:48:39 -06001295 elif owner.endswith('-base'):
1296 return '(base of %s)' % owner[:-5]
Eric Blake88d4ef82015-11-18 01:52:50 -07001297 else:
1298 assert owner.endswith('-wrapper')
1299 # Unreachable and not implemented
1300 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001301 if owner.endswith('Kind'):
1302 # See QAPISchema._make_implicit_enum_type()
1303 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001304 return '(%s of %s)' % (self.role, owner)
1305
1306 def describe(self):
1307 return "'%s' %s" % (self.name, self._pretty_owner())
1308
Markus Armbrusterac882192015-09-16 13:06:05 +02001309
Eric Blaked44f9ac2015-12-01 22:20:54 -07001310class QAPISchemaObjectTypeMember(QAPISchemaMember):
1311 def __init__(self, name, typ, optional):
1312 QAPISchemaMember.__init__(self, name)
1313 assert isinstance(typ, str)
1314 assert isinstance(optional, bool)
1315 self._type_name = typ
1316 self.type = None
1317 self.optional = optional
1318
1319 def check(self, schema):
1320 assert self.owner
1321 self.type = schema.lookup_type(self._type_name)
1322 assert self.type
1323
1324
Markus Armbrusterac882192015-09-16 13:06:05 +02001325class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001326 def __init__(self, tag_name, tag_member, variants):
1327 # Flat unions pass tag_name but not tag_member.
1328 # Simple unions and alternates pass tag_member but not tag_name.
1329 # After check(), tag_member is always set, and tag_name remains
1330 # a reliable witness of being used by a flat union.
1331 assert bool(tag_member) != bool(tag_name)
1332 assert (isinstance(tag_name, str) or
1333 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001334 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001335 for v in variants:
1336 assert isinstance(v, QAPISchemaObjectTypeVariant)
Eric Blakeda9cb192016-07-13 21:50:15 -06001337 self._tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001338 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001339 self.variants = variants
1340
Eric Blake88d4ef82015-11-18 01:52:50 -07001341 def set_owner(self, name):
1342 for v in self.variants:
1343 v.set_owner(name)
1344
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001345 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001346 if not self.tag_member: # flat union
Eric Blakeda9cb192016-07-13 21:50:15 -06001347 self.tag_member = seen[c_name(self._tag_name)]
1348 assert self._tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001349 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1350 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001351 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001352 # Union names must match enum values; alternate names are
1353 # checked separately. Use 'seen' to tell the two apart.
1354 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001355 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001356 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001357 v.type.check(schema)
1358
Eric Blake27b60ab2015-11-18 01:52:51 -07001359 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001360 for v in self.variants:
1361 # Reset seen map for each variant, since qapi names from one
1362 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001363 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001364 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001365
Eric Blake437db252015-09-29 16:21:02 -06001366
Markus Armbrusterac882192015-09-16 13:06:05 +02001367class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001368 role = 'branch'
1369
Markus Armbrusterac882192015-09-16 13:06:05 +02001370 def __init__(self, name, typ):
1371 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1372
Markus Armbrusterac882192015-09-16 13:06:05 +02001373
1374class QAPISchemaAlternateType(QAPISchemaType):
1375 def __init__(self, name, info, variants):
1376 QAPISchemaType.__init__(self, name, info)
1377 assert isinstance(variants, QAPISchemaObjectTypeVariants)
Eric Blakeda9cb192016-07-13 21:50:15 -06001378 assert variants.tag_member
Eric Blake88d4ef82015-11-18 01:52:50 -07001379 variants.set_owner(name)
1380 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001381 self.variants = variants
1382
1383 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001384 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001385 # Not calling self.variants.check_clash(), because there's nothing
1386 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001387 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001388 # Alternate branch names have no relation to the tag enum values;
1389 # so we have to check for potential name collisions ourselves.
1390 seen = {}
1391 for v in self.variants.variants:
1392 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001393
Eric Blake4040d992016-03-17 16:48:28 -06001394 def c_type(self):
1395 return c_name(self.name) + pointer_suffix
1396
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001397 def json_type(self):
1398 return 'value'
1399
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001400 def visit(self, visitor):
1401 visitor.visit_alternate_type(self.name, self.info, self.variants)
1402
Eric Blakec8184082016-07-13 21:50:20 -06001403 def is_empty(self):
1404 return False
1405
Markus Armbrusterac882192015-09-16 13:06:05 +02001406
1407class QAPISchemaCommand(QAPISchemaEntity):
Eric Blake48825ca2016-07-13 21:50:19 -06001408 def __init__(self, name, info, arg_type, ret_type, gen, success_response,
1409 boxed):
Markus Armbrusterac882192015-09-16 13:06:05 +02001410 QAPISchemaEntity.__init__(self, name, info)
1411 assert not arg_type or isinstance(arg_type, str)
1412 assert not ret_type or isinstance(ret_type, str)
1413 self._arg_type_name = arg_type
1414 self.arg_type = None
1415 self._ret_type_name = ret_type
1416 self.ret_type = None
1417 self.gen = gen
1418 self.success_response = success_response
Eric Blake48825ca2016-07-13 21:50:19 -06001419 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001420
1421 def check(self, schema):
1422 if self._arg_type_name:
1423 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001424 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1425 isinstance(self.arg_type, QAPISchemaAlternateType))
1426 self.arg_type.check(schema)
1427 if self.boxed:
1428 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001429 raise QAPISemError(self.info,
1430 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001431 else:
1432 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1433 assert not self.arg_type.variants
1434 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001435 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001436 if self._ret_type_name:
1437 self.ret_type = schema.lookup_type(self._ret_type_name)
1438 assert isinstance(self.ret_type, QAPISchemaType)
1439
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001440 def visit(self, visitor):
1441 visitor.visit_command(self.name, self.info,
1442 self.arg_type, self.ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001443 self.gen, self.success_response, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001444
Markus Armbrusterac882192015-09-16 13:06:05 +02001445
1446class QAPISchemaEvent(QAPISchemaEntity):
Eric Blake48825ca2016-07-13 21:50:19 -06001447 def __init__(self, name, info, arg_type, boxed):
Markus Armbrusterac882192015-09-16 13:06:05 +02001448 QAPISchemaEntity.__init__(self, name, info)
1449 assert not arg_type or isinstance(arg_type, str)
1450 self._arg_type_name = arg_type
1451 self.arg_type = None
Eric Blake48825ca2016-07-13 21:50:19 -06001452 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001453
1454 def check(self, schema):
1455 if self._arg_type_name:
1456 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001457 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1458 isinstance(self.arg_type, QAPISchemaAlternateType))
1459 self.arg_type.check(schema)
1460 if self.boxed:
1461 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001462 raise QAPISemError(self.info,
1463 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001464 else:
1465 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1466 assert not self.arg_type.variants
1467 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001468 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001469
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001470 def visit(self, visitor):
Eric Blake48825ca2016-07-13 21:50:19 -06001471 visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001472
Markus Armbrusterac882192015-09-16 13:06:05 +02001473
1474class QAPISchema(object):
1475 def __init__(self, fname):
1476 try:
Marc-André Lureau3313b612017-01-13 15:41:29 +01001477 parser = QAPISchemaParser(open(fname, "r"))
1478 self.exprs = check_exprs(parser.exprs)
1479 self.docs = check_docs(parser.docs)
Eric Blake7618b912015-10-12 22:22:22 -06001480 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001481 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001482 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001483 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001484 self._def_exprs()
1485 self.check()
Marc-André Lureau4148c292017-01-13 15:41:25 +01001486 except QAPIError as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001487 print >>sys.stderr, err
1488 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001489
Markus Armbrusterac882192015-09-16 13:06:05 +02001490 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001491 # Only the predefined types are allowed to not have info
1492 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001493 assert ent.name not in self._entity_dict
1494 self._entity_dict[ent.name] = ent
1495
1496 def lookup_entity(self, name, typ=None):
1497 ent = self._entity_dict.get(name)
1498 if typ and not isinstance(ent, typ):
1499 return None
1500 return ent
1501
1502 def lookup_type(self, name):
1503 return self.lookup_entity(name, QAPISchemaType)
1504
Eric Blake861877a2016-03-17 16:48:36 -06001505 def _def_builtin_type(self, name, json_type, c_type):
1506 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001507 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1508 # qapi-types.h from a single .c, all arrays of builtins must be
1509 # declared in the first file whether or not they are used. Nicer
1510 # would be to use lazy instantiation, while figuring out how to
1511 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001512 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001513
1514 def _def_predefineds(self):
Eric Blake861877a2016-03-17 16:48:36 -06001515 for t in [('str', 'string', 'char' + pointer_suffix),
1516 ('number', 'number', 'double'),
1517 ('int', 'int', 'int64_t'),
1518 ('int8', 'int', 'int8_t'),
1519 ('int16', 'int', 'int16_t'),
1520 ('int32', 'int', 'int32_t'),
1521 ('int64', 'int', 'int64_t'),
1522 ('uint8', 'int', 'uint8_t'),
1523 ('uint16', 'int', 'uint16_t'),
1524 ('uint32', 'int', 'uint32_t'),
1525 ('uint64', 'int', 'uint64_t'),
1526 ('size', 'int', 'uint64_t'),
1527 ('bool', 'boolean', 'bool'),
1528 ('any', 'value', 'QObject' + pointer_suffix)]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001529 self._def_builtin_type(*t)
Eric Blake75996972016-03-17 16:48:29 -06001530 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1531 None, [], None)
Markus Armbruster39a18152015-09-16 13:06:28 +02001532 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001533 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1534 'qstring', 'qdict', 'qlist',
1535 'qfloat', 'qbool'])
1536 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001537 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001538
Eric Blake93bda4d2015-12-01 22:20:55 -07001539 def _make_enum_members(self, values):
1540 return [QAPISchemaMember(v) for v in values]
1541
Eric Blake99df5282015-10-12 22:22:32 -06001542 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001543 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001544 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001545 self._def_entity(QAPISchemaEnumType(
1546 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001547 return name
1548
Eric Blake99df5282015-10-12 22:22:32 -06001549 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001550 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001551 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001552 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001553 return name
1554
Eric Blake99df5282015-10-12 22:22:32 -06001555 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001556 if not members:
1557 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001558 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake75996972016-03-17 16:48:29 -06001559 name = 'q_obj_%s-%s' % (name, role)
Markus Armbrusterac882192015-09-16 13:06:05 +02001560 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001561 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001562 members, None))
1563 return name
1564
1565 def _def_enum_type(self, expr, info):
1566 name = expr['enum']
1567 data = expr['data']
1568 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001569 self._def_entity(QAPISchemaEnumType(
1570 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001571
Eric Blake99df5282015-10-12 22:22:32 -06001572 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001573 optional = False
1574 if name.startswith('*'):
1575 name = name[1:]
1576 optional = True
1577 if isinstance(typ, list):
1578 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001579 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001580 return QAPISchemaObjectTypeMember(name, typ, optional)
1581
Eric Blake99df5282015-10-12 22:22:32 -06001582 def _make_members(self, data, info):
1583 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001584 for (key, value) in data.iteritems()]
1585
1586 def _def_struct_type(self, expr, info):
1587 name = expr['struct']
1588 base = expr.get('base')
1589 data = expr['data']
1590 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001591 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001592 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001593
1594 def _make_variant(self, case, typ):
1595 return QAPISchemaObjectTypeVariant(case, typ)
1596
Eric Blake99df5282015-10-12 22:22:32 -06001597 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001598 if isinstance(typ, list):
1599 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001600 typ = self._make_array_type(typ[0], info)
1601 typ = self._make_implicit_object_type(
1602 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001603 return QAPISchemaObjectTypeVariant(case, typ)
1604
Markus Armbrusterac882192015-09-16 13:06:05 +02001605 def _def_union_type(self, expr, info):
1606 name = expr['union']
1607 data = expr['data']
1608 base = expr.get('base')
1609 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001610 tag_member = None
Eric Blakeac4338f2016-03-17 16:48:39 -06001611 if isinstance(base, dict):
1612 base = (self._make_implicit_object_type(
1613 name, info, 'base', self._make_members(base, info)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001614 if tag_name:
1615 variants = [self._make_variant(key, value)
1616 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001617 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001618 else:
Eric Blake99df5282015-10-12 22:22:32 -06001619 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001620 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001621 typ = self._make_implicit_enum_type(name, info,
1622 [v.name for v in variants])
1623 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001624 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001625 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001626 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001627 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001628 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001629 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001630
1631 def _def_alternate_type(self, expr, info):
1632 name = expr['alternate']
1633 data = expr['data']
1634 variants = [self._make_variant(key, value)
1635 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001636 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001637 self._def_entity(
1638 QAPISchemaAlternateType(name, info,
1639 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001640 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001641 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001642
1643 def _def_command(self, expr, info):
1644 name = expr['command']
1645 data = expr.get('data')
1646 rets = expr.get('returns')
1647 gen = expr.get('gen', True)
1648 success_response = expr.get('success-response', True)
Eric Blake48825ca2016-07-13 21:50:19 -06001649 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001650 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001651 data = self._make_implicit_object_type(
1652 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001653 if isinstance(rets, list):
1654 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001655 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001656 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
Eric Blake48825ca2016-07-13 21:50:19 -06001657 success_response, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001658
1659 def _def_event(self, expr, info):
1660 name = expr['event']
1661 data = expr.get('data')
Eric Blake48825ca2016-07-13 21:50:19 -06001662 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001663 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001664 data = self._make_implicit_object_type(
1665 name, info, 'arg', self._make_members(data, info))
Eric Blake48825ca2016-07-13 21:50:19 -06001666 self._def_entity(QAPISchemaEvent(name, info, data, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001667
1668 def _def_exprs(self):
1669 for expr_elem in self.exprs:
1670 expr = expr_elem['expr']
1671 info = expr_elem['info']
1672 if 'enum' in expr:
1673 self._def_enum_type(expr, info)
1674 elif 'struct' in expr:
1675 self._def_struct_type(expr, info)
1676 elif 'union' in expr:
1677 self._def_union_type(expr, info)
1678 elif 'alternate' in expr:
1679 self._def_alternate_type(expr, info)
1680 elif 'command' in expr:
1681 self._def_command(expr, info)
1682 elif 'event' in expr:
1683 self._def_event(expr, info)
1684 else:
1685 assert False
1686
1687 def check(self):
1688 for ent in self._entity_dict.values():
1689 ent.check(self)
1690
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001691 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001692 visitor.visit_begin(self)
1693 for (name, entity) in sorted(self._entity_dict.items()):
1694 if visitor.visit_needed(entity):
1695 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001696 visitor.visit_end()
1697
Markus Armbruster2caba362013-07-27 17:41:56 +02001698
Markus Armbruster00e4b282015-06-10 10:04:36 +02001699#
1700# Code generation helpers
1701#
1702
Michael Roth0f923be2011-07-19 14:50:39 -05001703def camel_case(name):
1704 new_name = ''
1705 first = True
1706 for ch in name:
1707 if ch in ['_', '-']:
1708 first = True
1709 elif first:
1710 new_name += ch.upper()
1711 first = False
1712 else:
1713 new_name += ch.lower()
1714 return new_name
1715
Eric Blake437db252015-09-29 16:21:02 -06001716
Markus Armbruster849bc532015-05-14 06:50:53 -06001717# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1718# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1719# ENUM24_Name -> ENUM24_NAME
1720def camel_to_upper(value):
1721 c_fun_str = c_name(value, False)
1722 if value.isupper():
1723 return c_fun_str
1724
1725 new_name = ''
1726 l = len(c_fun_str)
1727 for i in range(l):
1728 c = c_fun_str[i]
1729 # When c is upper and no "_" appears before, do more checks
1730 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001731 if i < l - 1 and c_fun_str[i + 1].islower():
1732 new_name += '_'
1733 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001734 new_name += '_'
1735 new_name += c
1736 return new_name.lstrip('_').upper()
1737
Eric Blake437db252015-09-29 16:21:02 -06001738
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001739def c_enum_const(type_name, const_name, prefix=None):
1740 if prefix is not None:
1741 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001742 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001743
Eric Blake18df5152015-05-14 06:50:48 -06001744c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001745
Eric Blake437db252015-09-29 16:21:02 -06001746
Eric Blakec6405b52015-05-14 06:50:55 -06001747# Map @name to a valid C identifier.
1748# If @protect, avoid returning certain ticklish identifiers (like
1749# C keywords) by prepending "q_".
1750#
1751# Used for converting 'name' from a 'name':'type' qapi definition
1752# into a generated struct member, as well as converting type names
1753# into substrings of a generated C function name.
1754# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1755# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001756def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001757 # ANSI X3J11/88-090, 3.1.1
1758 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001759 'default', 'do', 'double', 'else', 'enum', 'extern',
1760 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1761 'return', 'short', 'signed', 'sizeof', 'static',
1762 'struct', 'switch', 'typedef', 'union', 'unsigned',
1763 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001764 # ISO/IEC 9899:1999, 6.4.1
1765 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1766 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001767 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1768 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001769 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1770 # excluding _.*
1771 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001772 # C++ ISO/IEC 14882:2003 2.11
1773 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1774 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1775 'namespace', 'new', 'operator', 'private', 'protected',
1776 'public', 'reinterpret_cast', 'static_cast', 'template',
1777 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1778 'using', 'virtual', 'wchar_t',
1779 # alternative representations
1780 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1781 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001782 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001783 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001784 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001785 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1786 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001787 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001788 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001789
Amos Kong05dfb262014-06-10 19:25:53 +08001790eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001791pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001792
Eric Blake437db252015-09-29 16:21:02 -06001793
Michael Roth0f923be2011-07-19 14:50:39 -05001794def genindent(count):
1795 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001796 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001797 ret += " "
1798 return ret
1799
1800indent_level = 0
1801
Eric Blake437db252015-09-29 16:21:02 -06001802
Michael Roth0f923be2011-07-19 14:50:39 -05001803def push_indent(indent_amount=4):
1804 global indent_level
1805 indent_level += indent_amount
1806
Eric Blake437db252015-09-29 16:21:02 -06001807
Michael Roth0f923be2011-07-19 14:50:39 -05001808def pop_indent(indent_amount=4):
1809 global indent_level
1810 indent_level -= indent_amount
1811
Eric Blake437db252015-09-29 16:21:02 -06001812
Markus Armbruster77e703b2015-06-24 19:27:32 +02001813# Generate @code with @kwds interpolated.
1814# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001815def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001816 raw = code % kwds
1817 if indent_level:
1818 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001819 # re.subn() lacks flags support before Python 2.7, use re.compile()
1820 raw = re.subn(re.compile("^.", re.MULTILINE),
1821 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001822 raw = raw[0]
1823 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001824
Eric Blake437db252015-09-29 16:21:02 -06001825
Michael Roth0f923be2011-07-19 14:50:39 -05001826def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001827 if code[0] == '\n':
1828 code = code[1:]
1829 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001830
Michael Roth0f923be2011-07-19 14:50:39 -05001831
1832def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001833 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001834
Eric Blake437db252015-09-29 16:21:02 -06001835
Michael Rothc0afa9c2013-05-10 17:46:00 -05001836def guardstart(name):
1837 return mcgen('''
1838
1839#ifndef %(name)s
1840#define %(name)s
1841
1842''',
1843 name=guardname(name))
1844
Eric Blake437db252015-09-29 16:21:02 -06001845
Michael Rothc0afa9c2013-05-10 17:46:00 -05001846def guardend(name):
1847 return mcgen('''
1848
1849#endif /* %(name)s */
1850
1851''',
1852 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001853
Eric Blake437db252015-09-29 16:21:02 -06001854
Markus Armbrustere98859a2015-09-16 13:06:16 +02001855def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001856 ret = mcgen('''
1857
Markus Armbrustere98859a2015-09-16 13:06:16 +02001858const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001859''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001860 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001861 for value in values:
1862 index = c_enum_const(name, value, prefix)
1863 ret += mcgen('''
1864 [%(index)s] = "%(value)s",
1865''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001866 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001867
Eric Blake7fb1cf12015-11-18 01:52:57 -07001868 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001869 ret += mcgen('''
1870 [%(max_index)s] = NULL,
1871};
1872''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001873 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001874 return ret
1875
Eric Blake437db252015-09-29 16:21:02 -06001876
Markus Armbrustere98859a2015-09-16 13:06:16 +02001877def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001878 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001879 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001880
1881 ret = mcgen('''
1882
1883typedef enum %(c_name)s {
1884''',
1885 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001886
1887 i = 0
1888 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001889 ret += mcgen('''
1890 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001891''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001892 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001893 i=i)
1894 i += 1
1895
Markus Armbrustere98859a2015-09-16 13:06:16 +02001896 ret += mcgen('''
1897} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001898''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001899 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001900
Markus Armbrustere98859a2015-09-16 13:06:16 +02001901 ret += mcgen('''
1902
1903extern const char *const %(c_name)s_lookup[];
1904''',
1905 c_name=c_name(name))
1906 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001907
Eric Blake437db252015-09-29 16:21:02 -06001908
Eric Blake48825ca2016-07-13 21:50:19 -06001909def gen_params(arg_type, boxed, extra):
Markus Armbruster03b43672015-09-16 13:06:20 +02001910 if not arg_type:
Eric Blakec8184082016-07-13 21:50:20 -06001911 assert not boxed
Markus Armbruster03b43672015-09-16 13:06:20 +02001912 return extra
Markus Armbruster03b43672015-09-16 13:06:20 +02001913 ret = ''
1914 sep = ''
Eric Blake48825ca2016-07-13 21:50:19 -06001915 if boxed:
Eric Blakec8184082016-07-13 21:50:20 -06001916 ret += '%s arg' % arg_type.c_param_type()
1917 sep = ', '
Eric Blake48825ca2016-07-13 21:50:19 -06001918 else:
1919 assert not arg_type.variants
1920 for memb in arg_type.members:
1921 ret += sep
1922 sep = ', '
1923 if memb.optional:
1924 ret += 'bool has_%s, ' % c_name(memb.name)
1925 ret += '%s %s' % (memb.type.c_param_type(),
1926 c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001927 if extra:
1928 ret += sep + extra
1929 return ret
1930
Eric Blake1f353342015-09-29 16:21:13 -06001931
Markus Armbruster00e4b282015-06-10 10:04:36 +02001932#
1933# Common command line parsing
1934#
1935
Eric Blake437db252015-09-29 16:21:02 -06001936
1937def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001938
1939 try:
1940 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001941 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001942 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001943 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001944 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001945 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001946 sys.exit(1)
1947
1948 output_dir = ""
1949 prefix = ""
1950 do_c = False
1951 do_h = False
1952 extra_opts = []
1953
1954 for oa in opts:
1955 o, a = oa
1956 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001957 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1958 if match.end() != len(a):
1959 print >>sys.stderr, \
1960 "%s: 'funny character '%s' in argument of --prefix" \
1961 % (sys.argv[0], a[match.end()])
1962 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001963 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001964 elif o in ("-o", "--output-dir"):
1965 output_dir = a + "/"
1966 elif o in ("-c", "--source"):
1967 do_c = True
1968 elif o in ("-h", "--header"):
1969 do_h = True
1970 else:
1971 extra_opts.append(oa)
1972
1973 if not do_c and not do_h:
1974 do_c = True
1975 do_h = True
1976
Markus Armbruster16d80f62015-04-02 13:32:16 +02001977 if len(args) != 1:
1978 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001979 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001980 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001981
Markus Armbruster54414042015-06-09 16:22:45 +02001982 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001983
Markus Armbruster00e4b282015-06-10 10:04:36 +02001984#
1985# Generate output files with boilerplate
1986#
1987
Eric Blake437db252015-09-29 16:21:02 -06001988
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001989def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1990 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001991 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001992 c_file = output_dir + prefix + c_file
1993 h_file = output_dir + prefix + h_file
1994
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001995 if output_dir:
1996 try:
1997 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01001998 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001999 if e.errno != errno.EEXIST:
2000 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002001
2002 def maybe_open(really, name, opt):
2003 if really:
2004 return open(name, opt)
2005 else:
2006 import StringIO
2007 return StringIO.StringIO()
2008
2009 fdef = maybe_open(do_c, c_file, 'w')
2010 fdecl = maybe_open(do_h, h_file, 'w')
2011
2012 fdef.write(mcgen('''
2013/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2014%(comment)s
2015''',
Eric Blake437db252015-09-29 16:21:02 -06002016 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002017
2018 fdecl.write(mcgen('''
2019/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2020%(comment)s
2021#ifndef %(guard)s
2022#define %(guard)s
2023
2024''',
Eric Blake437db252015-09-29 16:21:02 -06002025 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002026
2027 return (fdef, fdecl)
2028
Eric Blake437db252015-09-29 16:21:02 -06002029
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002030def close_output(fdef, fdecl):
2031 fdecl.write('''
2032#endif
2033''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002034 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002035 fdef.close()