blob: dd083b703cac8b955d6eb62353db9cf112af2aab [file] [log] [blame]
Michael Roth0f923be2011-07-19 14:50:39 -05001#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
Eric Blakee4083112016-01-29 06:48:41 -07005# Copyright (c) 2013-2016 Red Hat Inc.
Michael Roth0f923be2011-07-19 14:50:39 -05006#
7# Authors:
8# Anthony Liguori <aliguori@us.ibm.com>
Markus Armbrusterc7a3f252013-07-27 17:41:55 +02009# Markus Armbruster <armbru@redhat.com>
Michael Roth0f923be2011-07-19 14:50:39 -050010#
Markus Armbruster678e48a2014-03-01 08:40:34 +010011# This work is licensed under the terms of the GNU GPL, version 2.
12# See the COPYING file in the top-level directory.
Michael Roth0f923be2011-07-19 14:50:39 -050013
Lluís Vilanovaa719a272014-05-07 20:46:15 +020014import re
Michael Roth0f923be2011-07-19 14:50:39 -050015from ordereddict import OrderedDict
Markus Armbruster12f8e1b2015-04-02 14:46:39 +020016import errno
Markus Armbruster2114f5a2015-04-02 13:12:21 +020017import getopt
Lluís Vilanova33aaad52014-05-02 15:52:35 +020018import os
Markus Armbruster2caba362013-07-27 17:41:56 +020019import sys
Markus Armbruster47299262015-05-14 06:50:47 -060020import string
Michael Roth0f923be2011-07-19 14:50:39 -050021
Eric Blakeb52c4b92015-05-04 09:05:00 -060022builtin_types = {
Kevin Wolf69dd62d2013-07-08 16:14:21 +020023 'str': 'QTYPE_QSTRING',
24 'int': 'QTYPE_QINT',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
27 'int8': 'QTYPE_QINT',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
Eric Blakecb17f792015-05-04 09:05:01 -060035 'size': 'QTYPE_QINT',
Eric Blake1310a3d2015-12-01 22:20:46 -070036 'any': None, # any QType possible, actually
Eric Blake7264f5c2015-12-01 22:20:47 -070037 'QType': 'QTYPE_QSTRING',
Kevin Wolf69dd62d2013-07-08 16:14:21 +020038}
39
Markus Armbrusterbc52d032017-03-15 13:56:51 +010040# Are documentation comments required?
41doc_required = False
42
Eric Blake10d4d992015-05-04 09:05:23 -060043# Whitelist of commands allowed to return a non-dictionary
Markus Armbruster1554a8f2017-03-15 13:56:54 +010044returns_whitelist = []
Eric Blake10d4d992015-05-04 09:05:23 -060045
Eric Blake893e1f22015-12-01 22:20:57 -070046# Whitelist of entities allowed to violate case conventions
Markus Armbruster2cfbae32017-03-15 13:56:55 +010047name_case_whitelist = []
Eric Blake893e1f22015-12-01 22:20:57 -070048
Eric Blake4dc2e692015-05-04 09:05:17 -060049enum_types = []
50struct_types = []
51union_types = []
52events = []
53all_names = {}
54
Markus Armbruster00e4b282015-06-10 10:04:36 +020055#
56# Parsing the schema into expressions
57#
58
Eric Blake437db252015-09-29 16:21:02 -060059
Lluís Vilanovaa719a272014-05-07 20:46:15 +020060def error_path(parent):
61 res = ""
62 while parent:
63 res = ("In file included from %s:%d:\n" % (parent['file'],
64 parent['line'])) + res
65 parent = parent['parent']
66 return res
67
Eric Blake437db252015-09-29 16:21:02 -060068
Marc-André Lureau4148c292017-01-13 15:41:25 +010069class QAPIError(Exception):
70 def __init__(self, fname, line, col, incl_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -060071 Exception.__init__(self)
Marc-André Lureau4148c292017-01-13 15:41:25 +010072 self.fname = fname
73 self.line = line
74 self.col = col
75 self.info = incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +020076 self.msg = msg
Marc-André Lureau4148c292017-01-13 15:41:25 +010077
78 def __str__(self):
79 loc = "%s:%d" % (self.fname, self.line)
80 if self.col is not None:
81 loc += ":%s" % self.col
82 return error_path(self.info) + "%s: %s" % (loc, self.msg)
83
84
85class QAPIParseError(QAPIError):
86 def __init__(self, parser, msg):
87 col = 1
88 for ch in parser.src[parser.line_pos:parser.pos]:
Wenchao Xia515b9432014-03-04 18:44:33 -080089 if ch == '\t':
Marc-André Lureau4148c292017-01-13 15:41:25 +010090 col = (col + 7) % 8 + 1
Markus Armbruster2caba362013-07-27 17:41:56 +020091 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +010092 col += 1
93 QAPIError.__init__(self, parser.fname, parser.line, col,
94 parser.incl_info, msg)
Markus Armbruster2caba362013-07-27 17:41:56 +020095
Eric Blake437db252015-09-29 16:21:02 -060096
Marc-André Lureau4148c292017-01-13 15:41:25 +010097class QAPISemError(QAPIError):
98 def __init__(self, info, msg):
99 QAPIError.__init__(self, info['file'], info['line'], None,
100 info['parent'], msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800101
Eric Blake437db252015-09-29 16:21:02 -0600102
Marc-André Lureau3313b612017-01-13 15:41:29 +0100103class QAPIDoc(object):
104 class Section(object):
105 def __init__(self, name=None):
106 # optional section name (argument/member or section name)
107 self.name = name
108 # the list of lines for this section
109 self.content = []
Markus Armbrusterb116fd82017-03-15 13:57:00 +0100110 self.optional = False
Marc-André Lureau3313b612017-01-13 15:41:29 +0100111
112 def append(self, line):
113 self.content.append(line)
114
115 def __repr__(self):
116 return "\n".join(self.content).strip()
117
118 class ArgSection(Section):
119 pass
120
121 def __init__(self, parser, info):
122 # self.parser is used to report errors with QAPIParseError. The
123 # resulting error position depends on the state of the parser.
124 # It happens to be the beginning of the comment. More or less
125 # servicable, but action at a distance.
126 self.parser = parser
127 self.info = info
128 self.symbol = None
129 self.body = QAPIDoc.Section()
130 # dict mapping parameter name to ArgSection
131 self.args = OrderedDict()
132 # a list of Section
133 self.sections = []
134 # the current section
135 self.section = self.body
136 # associated expression (to be set by expression parser)
137 self.expr = None
138
139 def has_section(self, name):
140 """Return True if we have a section with this name."""
141 for i in self.sections:
142 if i.name == name:
143 return True
144 return False
145
146 def append(self, line):
147 """Parse a comment line and add it to the documentation."""
148 line = line[1:]
149 if not line:
150 self._append_freeform(line)
151 return
152
153 if line[0] != ' ':
154 raise QAPIParseError(self.parser, "Missing space after #")
155 line = line[1:]
156
157 # FIXME not nice: things like '# @foo:' and '# @foo: ' aren't
158 # recognized, and get silently treated as ordinary text
159 if self.symbol:
160 self._append_symbol_line(line)
161 elif not self.body.content and line.startswith("@"):
162 if not line.endswith(":"):
163 raise QAPIParseError(self.parser, "Line should end with :")
164 self.symbol = line[1:-1]
165 # FIXME invalid names other than the empty string aren't flagged
166 if not self.symbol:
167 raise QAPIParseError(self.parser, "Invalid name")
168 else:
169 self._append_freeform(line)
170
171 def _append_symbol_line(self, line):
172 name = line.split(' ', 1)[0]
173
174 if name.startswith("@") and name.endswith(":"):
175 line = line[len(name)+1:]
176 self._start_args_section(name[1:-1])
177 elif name in ("Returns:", "Since:",
178 # those are often singular or plural
179 "Note:", "Notes:",
180 "Example:", "Examples:",
181 "TODO:"):
182 line = line[len(name)+1:]
183 self._start_section(name[:-1])
184
185 self._append_freeform(line)
186
187 def _start_args_section(self, name):
188 # FIXME invalid names other than the empty string aren't flagged
189 if not name:
190 raise QAPIParseError(self.parser, "Invalid parameter name")
191 if name in self.args:
192 raise QAPIParseError(self.parser,
193 "'%s' parameter name duplicated" % name)
194 if self.sections:
195 raise QAPIParseError(self.parser,
196 "'@%s:' can't follow '%s' section"
197 % (name, self.sections[0].name))
198 self.section = QAPIDoc.ArgSection(name)
199 self.args[name] = self.section
200
201 def _start_section(self, name=""):
202 if name in ("Returns", "Since") and self.has_section(name):
203 raise QAPIParseError(self.parser,
204 "Duplicated '%s' section" % name)
205 self.section = QAPIDoc.Section(name)
206 self.sections.append(self.section)
207
208 def _append_freeform(self, line):
209 in_arg = isinstance(self.section, QAPIDoc.ArgSection)
210 if (in_arg and self.section.content
211 and not self.section.content[-1]
212 and line and not line[0].isspace()):
213 self._start_section()
214 if (in_arg or not self.section.name
215 or not self.section.name.startswith("Example")):
216 line = line.strip()
217 self.section.append(line)
218
219
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200220class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500221
Eric Blake437db252015-09-29 16:21:02 -0600222 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200223 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200224 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200225 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200226 previously_included.append(abs_fname)
227 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200228 self.src = fp.read()
229 if self.src == '' or self.src[-1] != '\n':
230 self.src += '\n'
231 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800232 self.line = 1
233 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200234 self.exprs = []
Marc-André Lureau3313b612017-01-13 15:41:29 +0100235 self.docs = []
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200236 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500237
Eric Blake437db252015-09-29 16:21:02 -0600238 while self.tok is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100239 info = {'file': fname, 'line': self.line,
240 'parent': self.incl_info}
Marc-André Lureau3313b612017-01-13 15:41:29 +0100241 if self.tok == '#':
242 doc = self.get_doc(info)
243 self.docs.append(doc)
244 continue
245
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200246 expr = self.get_expr(False)
Markus Armbrustere04dea82017-03-15 13:56:50 +0100247 if 'include' in expr:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200248 if len(expr) != 1:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100249 raise QAPISemError(info, "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200250 include = expr["include"]
251 if not isinstance(include, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100252 raise QAPISemError(info,
253 "Value of 'include' must be a string")
Markus Armbrustere04dea82017-03-15 13:56:50 +0100254 self._include(include, info, os.path.dirname(abs_fname),
255 previously_included)
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100256 elif "pragma" in expr:
257 if len(expr) != 1:
258 raise QAPISemError(info, "Invalid 'pragma' directive")
259 pragma = expr['pragma']
260 if not isinstance(pragma, dict):
261 raise QAPISemError(
262 info, "Value of 'pragma' must be a dictionary")
263 for name, value in pragma.iteritems():
264 self._pragma(name, value, info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200265 else:
266 expr_elem = {'expr': expr,
Marc-André Lureau4148c292017-01-13 15:41:25 +0100267 'info': info}
Marc-André Lureau3313b612017-01-13 15:41:29 +0100268 if (self.docs
269 and self.docs[-1].info['file'] == fname
270 and not self.docs[-1].expr):
271 self.docs[-1].expr = expr
272 expr_elem['doc'] = self.docs[-1]
273
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200274 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500275
Markus Armbrustere04dea82017-03-15 13:56:50 +0100276 def _include(self, include, info, base_dir, previously_included):
277 incl_abs_fname = os.path.join(base_dir, include)
278 # catch inclusion cycle
279 inf = info
280 while inf:
281 if incl_abs_fname == os.path.abspath(inf['file']):
282 raise QAPISemError(info, "Inclusion loop for %s" % include)
283 inf = inf['parent']
284
285 # skip multiple include of the same file
286 if incl_abs_fname in previously_included:
287 return
288 try:
289 fobj = open(incl_abs_fname, 'r')
290 except IOError as e:
291 raise QAPISemError(info, '%s: %s' % (e.strerror, include))
292 exprs_include = QAPISchemaParser(fobj, previously_included, info)
293 self.exprs.extend(exprs_include.exprs)
294 self.docs.extend(exprs_include.docs)
295
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100296 def _pragma(self, name, value, info):
Markus Armbruster2cfbae32017-03-15 13:56:55 +0100297 global doc_required, returns_whitelist, name_case_whitelist
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100298 if name == 'doc-required':
299 if not isinstance(value, bool):
300 raise QAPISemError(info,
301 "Pragma 'doc-required' must be boolean")
302 doc_required = value
Markus Armbruster1554a8f2017-03-15 13:56:54 +0100303 elif name == 'returns-whitelist':
304 if (not isinstance(value, list)
305 or any([not isinstance(elt, str) for elt in value])):
306 raise QAPISemError(info,
307 "Pragma returns-whitelist must be"
308 " a list of strings")
309 returns_whitelist = value
Markus Armbruster2cfbae32017-03-15 13:56:55 +0100310 elif name == 'name-case-whitelist':
311 if (not isinstance(value, list)
312 or any([not isinstance(elt, str) for elt in value])):
313 raise QAPISemError(info,
314 "Pragma name-case-whitelist must be"
315 " a list of strings")
316 name_case_whitelist = value
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100317 else:
318 raise QAPISemError(info, "Unknown pragma '%s'" % name)
319
Marc-André Lureau3313b612017-01-13 15:41:29 +0100320 def accept(self, skip_comment=True):
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200321 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200322 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200323 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200324 self.cursor += 1
325 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500326
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200327 if self.tok == '#':
Marc-André Lureau3313b612017-01-13 15:41:29 +0100328 if self.src[self.cursor] == '#':
329 # Start of doc comment
330 skip_comment = False
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200331 self.cursor = self.src.find('\n', self.cursor)
Marc-André Lureau3313b612017-01-13 15:41:29 +0100332 if not skip_comment:
333 self.val = self.src[self.pos:self.cursor]
334 return
Eric Blake8712fa52015-10-26 16:34:41 -0600335 elif self.tok in "{}:,[]":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200336 return
337 elif self.tok == "'":
338 string = ''
339 esc = False
340 while True:
341 ch = self.src[self.cursor]
342 self.cursor += 1
343 if ch == '\n':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100344 raise QAPIParseError(self, 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200345 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600346 if ch == 'b':
347 string += '\b'
348 elif ch == 'f':
349 string += '\f'
350 elif ch == 'n':
351 string += '\n'
352 elif ch == 'r':
353 string += '\r'
354 elif ch == 't':
355 string += '\t'
356 elif ch == 'u':
357 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600358 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600359 ch = self.src[self.cursor]
360 self.cursor += 1
361 if ch not in "0123456789abcdefABCDEF":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100362 raise QAPIParseError(self,
363 '\\u escape needs 4 '
364 'hex digits')
Eric Blakea7f59662015-05-04 09:05:36 -0600365 value = (value << 4) + int(ch, 16)
366 # If Python 2 and 3 didn't disagree so much on
367 # how to handle Unicode, then we could allow
368 # Unicode string defaults. But most of QAPI is
369 # ASCII-only, so we aren't losing much for now.
370 if not value or value > 0x7f:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100371 raise QAPIParseError(self,
372 'For now, \\u escape '
373 'only supports non-zero '
374 'values up to \\u007f')
Eric Blakea7f59662015-05-04 09:05:36 -0600375 string += chr(value)
376 elif ch in "\\/'\"":
377 string += ch
378 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100379 raise QAPIParseError(self,
380 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200381 esc = False
382 elif ch == "\\":
383 esc = True
384 elif ch == "'":
385 self.val = string
386 return
387 else:
388 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200389 elif self.src.startswith("true", self.pos):
390 self.val = True
391 self.cursor += 3
392 return
393 elif self.src.startswith("false", self.pos):
394 self.val = False
395 self.cursor += 4
396 return
397 elif self.src.startswith("null", self.pos):
398 self.val = None
399 self.cursor += 3
400 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200401 elif self.tok == '\n':
402 if self.cursor == len(self.src):
403 self.tok = None
404 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800405 self.line += 1
406 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200407 elif not self.tok.isspace():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100408 raise QAPIParseError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500409
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200410 def get_members(self):
411 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200412 if self.tok == '}':
413 self.accept()
414 return expr
415 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100416 raise QAPIParseError(self, 'Expected string or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200417 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200418 key = self.val
419 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200420 if self.tok != ':':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100421 raise QAPIParseError(self, 'Expected ":"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200422 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800423 if key in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100424 raise QAPIParseError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200425 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200426 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200427 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200428 return expr
429 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100430 raise QAPIParseError(self, 'Expected "," or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200431 self.accept()
432 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100433 raise QAPIParseError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500434
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200435 def get_values(self):
436 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200437 if self.tok == ']':
438 self.accept()
439 return expr
Eric Blake437db252015-09-29 16:21:02 -0600440 if self.tok not in "{['tfn":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100441 raise QAPIParseError(self, 'Expected "{", "[", "]", string, '
442 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200443 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200444 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200445 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200446 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200447 return expr
448 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100449 raise QAPIParseError(self, 'Expected "," or "]"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200450 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500451
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200452 def get_expr(self, nested):
453 if self.tok != '{' and not nested:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100454 raise QAPIParseError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200455 if self.tok == '{':
456 self.accept()
457 expr = self.get_members()
458 elif self.tok == '[':
459 self.accept()
460 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600461 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200462 expr = self.val
463 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200464 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100465 raise QAPIParseError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200466 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200467
Marc-André Lureau3313b612017-01-13 15:41:29 +0100468 def get_doc(self, info):
469 if self.val != '##':
470 raise QAPIParseError(self, "Junk after '##' at start of "
471 "documentation comment")
472
473 doc = QAPIDoc(self, info)
474 self.accept(False)
475 while self.tok == '#':
476 if self.val.startswith('##'):
477 # End of doc comment
478 if self.val != '##':
479 raise QAPIParseError(self, "Junk after '##' at end of "
480 "documentation comment")
481 self.accept()
482 return doc
483 else:
484 doc.append(self.val)
485 self.accept(False)
486
487 raise QAPIParseError(self, "Documentation comment must end with '##'")
488
489
Markus Armbruster00e4b282015-06-10 10:04:36 +0200490#
491# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200492# TODO fold into QAPISchema
493# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200494#
495
Eric Blake437db252015-09-29 16:21:02 -0600496
Eric Blake14f00c62016-03-03 09:16:43 -0700497def find_base_members(base):
Eric Blakeac4338f2016-03-17 16:48:39 -0600498 if isinstance(base, dict):
499 return base
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800500 base_struct_define = find_struct(base)
501 if not base_struct_define:
502 return None
503 return base_struct_define['data']
504
Eric Blake437db252015-09-29 16:21:02 -0600505
Eric Blake811d04f2015-05-04 09:05:10 -0600506# Return the qtype of an alternate branch, or None on error.
507def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600508 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600509 return builtin_types[qapi_type]
510 elif find_struct(qapi_type):
511 return "QTYPE_QDICT"
512 elif find_enum(qapi_type):
513 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600514 elif find_union(qapi_type):
515 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600516 return None
517
Eric Blake437db252015-09-29 16:21:02 -0600518
Wenchao Xiabceae762014-03-06 17:08:56 -0800519# Return the discriminator enum define if discriminator is specified as an
520# enum type, otherwise return None.
521def discriminator_find_enum_define(expr):
522 base = expr.get('base')
523 discriminator = expr.get('discriminator')
524
525 if not (discriminator and base):
526 return None
527
Eric Blake14f00c62016-03-03 09:16:43 -0700528 base_members = find_base_members(base)
529 if not base_members:
Wenchao Xiabceae762014-03-06 17:08:56 -0800530 return None
531
Eric Blake14f00c62016-03-03 09:16:43 -0700532 discriminator_type = base_members.get(discriminator)
Wenchao Xiabceae762014-03-06 17:08:56 -0800533 if not discriminator_type:
534 return None
535
536 return find_enum(discriminator_type)
537
Eric Blake437db252015-09-29 16:21:02 -0600538
Eric Blake59a92fe2015-11-18 01:52:56 -0700539# Names must be letters, numbers, -, and _. They must start with letter,
540# except for downstream extensions which must start with __RFQDN_.
541# Dots are only valid in the downstream extension prefix.
542valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
543 '[a-zA-Z][a-zA-Z0-9_-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600544
545
Marc-André Lureau4148c292017-01-13 15:41:25 +0100546def check_name(info, source, name, allow_optional=False,
Eric Blake437db252015-09-29 16:21:02 -0600547 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600548 global valid_name
549 membername = name
550
551 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100552 raise QAPISemError(info, "%s requires a string name" % source)
Eric Blakec9e0a792015-05-04 09:05:22 -0600553 if name.startswith('*'):
554 membername = name[1:]
555 if not allow_optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100556 raise QAPISemError(info, "%s does not allow optional name '%s'"
557 % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600558 # Enum members can start with a digit, because the generated C
559 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700560 if enum_member and membername[0].isdigit():
561 membername = 'D' + membername
Eric Blake75996972016-03-17 16:48:29 -0600562 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
563 # and 'q_obj_*' implicit type names.
Eric Blake9fb081e2015-10-26 16:34:44 -0600564 if not valid_name.match(membername) or \
565 c_name(membername, False).startswith('q_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100566 raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600567
Eric Blake437db252015-09-29 16:21:02 -0600568
569def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200570 global all_names
571 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200572 # FIXME should reject names that differ only in '_' vs. '.'
573 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200574 if name in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100575 raise QAPISemError(info, "%s '%s' is already defined"
576 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600577 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100578 raise QAPISemError(info, "%s '%s' should not end in '%s'"
579 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200580 all_names[name] = meta
581
Eric Blake437db252015-09-29 16:21:02 -0600582
Markus Armbruster00e4b282015-06-10 10:04:36 +0200583def add_struct(definition, info):
584 global struct_types
585 name = definition['struct']
586 add_name(name, info, 'struct')
587 struct_types.append(definition)
588
Eric Blake437db252015-09-29 16:21:02 -0600589
Markus Armbruster00e4b282015-06-10 10:04:36 +0200590def find_struct(name):
591 global struct_types
592 for struct in struct_types:
593 if struct['struct'] == name:
594 return struct
595 return None
596
Eric Blake437db252015-09-29 16:21:02 -0600597
Markus Armbruster00e4b282015-06-10 10:04:36 +0200598def add_union(definition, info):
599 global union_types
600 name = definition['union']
601 add_name(name, info, 'union')
602 union_types.append(definition)
603
Eric Blake437db252015-09-29 16:21:02 -0600604
Markus Armbruster00e4b282015-06-10 10:04:36 +0200605def find_union(name):
606 global union_types
607 for union in union_types:
608 if union['union'] == name:
609 return union
610 return None
611
Eric Blake437db252015-09-29 16:21:02 -0600612
613def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200614 global enum_types
615 add_name(name, info, 'enum', implicit)
616 enum_types.append({"enum_name": name, "enum_values": enum_values})
617
Eric Blake437db252015-09-29 16:21:02 -0600618
Markus Armbruster00e4b282015-06-10 10:04:36 +0200619def find_enum(name):
620 global enum_types
621 for enum in enum_types:
622 if enum['enum_name'] == name:
623 return enum
624 return None
625
Markus Armbruster00e4b282015-06-10 10:04:36 +0200626
Eric Blake437db252015-09-29 16:21:02 -0600627def is_enum(name):
628 return find_enum(name) is not None
629
630
Marc-André Lureau4148c292017-01-13 15:41:25 +0100631def check_type(info, source, value, allow_array=False,
Eric Blake437db252015-09-29 16:21:02 -0600632 allow_dict=False, allow_optional=False,
633 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600634 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600635
636 if value is None:
637 return
638
Eric Blakedd883c62015-05-04 09:05:21 -0600639 # Check if array type for value is okay
640 if isinstance(value, list):
641 if not allow_array:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100642 raise QAPISemError(info, "%s cannot be an array" % source)
Eric Blakedd883c62015-05-04 09:05:21 -0600643 if len(value) != 1 or not isinstance(value[0], str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100644 raise QAPISemError(info,
645 "%s: array type must contain single type name" %
646 source)
Eric Blakedd883c62015-05-04 09:05:21 -0600647 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600648
649 # Check if type name for value is okay
650 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600651 if value not in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100652 raise QAPISemError(info, "%s uses unknown type '%s'"
653 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600654 if not all_names[value] in allow_metas:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100655 raise QAPISemError(info, "%s cannot use %s type '%s'" %
656 (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600657 return
658
Eric Blakedd883c62015-05-04 09:05:21 -0600659 if not allow_dict:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100660 raise QAPISemError(info, "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200661
662 if not isinstance(value, OrderedDict):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100663 raise QAPISemError(info,
664 "%s should be a dictionary or type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200665
666 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600667 for (key, arg) in value.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100668 check_name(info, "Member of %s" % source, key,
Eric Blakec9e0a792015-05-04 09:05:22 -0600669 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600670 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100671 raise QAPISemError(info, "Member of %s uses reserved name '%s'"
672 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600673 # Todo: allow dictionaries to represent default values of
674 # an optional argument.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100675 check_type(info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200676 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600677 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600678 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600679
Eric Blake437db252015-09-29 16:21:02 -0600680
Marc-André Lureau4148c292017-01-13 15:41:25 +0100681def check_command(expr, info):
Eric Blakedd883c62015-05-04 09:05:21 -0600682 name = expr['command']
Eric Blakec8184082016-07-13 21:50:20 -0600683 boxed = expr.get('boxed', False)
Eric Blake2cbf0992015-05-04 09:05:24 -0600684
Eric Blakec8184082016-07-13 21:50:20 -0600685 args_meta = ['struct']
686 if boxed:
687 args_meta += ['union', 'alternate']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100688 check_type(info, "'data' for command '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600689 expr.get('data'), allow_dict=not boxed, allow_optional=True,
690 allow_metas=args_meta)
Eric Blake10d4d992015-05-04 09:05:23 -0600691 returns_meta = ['union', 'struct']
692 if name in returns_whitelist:
693 returns_meta += ['built-in', 'alternate', 'enum']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100694 check_type(info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200695 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200696 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600697
Eric Blake437db252015-09-29 16:21:02 -0600698
Marc-André Lureau4148c292017-01-13 15:41:25 +0100699def check_event(expr, info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600700 global events
701 name = expr['event']
Eric Blakec8184082016-07-13 21:50:20 -0600702 boxed = expr.get('boxed', False)
Eric Blake4dc2e692015-05-04 09:05:17 -0600703
Eric Blakec8184082016-07-13 21:50:20 -0600704 meta = ['struct']
705 if boxed:
706 meta += ['union', 'alternate']
Eric Blake4dc2e692015-05-04 09:05:17 -0600707 events.append(name)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100708 check_type(info, "'data' for event '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600709 expr.get('data'), allow_dict=not boxed, allow_optional=True,
710 allow_metas=meta)
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200711
Eric Blake437db252015-09-29 16:21:02 -0600712
Marc-André Lureau4148c292017-01-13 15:41:25 +0100713def check_union(expr, info):
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800714 name = expr['union']
715 base = expr.get('base')
716 discriminator = expr.get('discriminator')
717 members = expr['data']
718
Eric Blake811d04f2015-05-04 09:05:10 -0600719 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600720
721 # With no discriminator it is a simple union.
722 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600723 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600724 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600725 if base is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100726 raise QAPISemError(info, "Simple union '%s' must not have a base" %
727 name)
Eric Blake44bd1272015-05-04 09:05:08 -0600728
729 # Else, it's a flat union.
730 else:
Eric Blakeac4338f2016-03-17 16:48:39 -0600731 # The object must have a string or dictionary 'base'.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100732 check_type(info, "'base' for union '%s'" % name,
Eric Blakeac4338f2016-03-17 16:48:39 -0600733 base, allow_dict=True, allow_optional=True,
734 allow_metas=['struct'])
Eric Blake376863e2015-09-29 16:21:07 -0600735 if not base:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100736 raise QAPISemError(info, "Flat union '%s' must have a base"
737 % name)
Eric Blake14f00c62016-03-03 09:16:43 -0700738 base_members = find_base_members(base)
Markus Armbruster48153742017-03-15 13:56:58 +0100739 assert base_members is not None
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800740
Eric Blakec9e0a792015-05-04 09:05:22 -0600741 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600742 # member of the base struct.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100743 check_name(info, "Discriminator of flat union '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600744 discriminator)
Eric Blake14f00c62016-03-03 09:16:43 -0700745 discriminator_type = base_members.get(discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800746 if not discriminator_type:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100747 raise QAPISemError(info,
748 "Discriminator '%s' is not a member of base "
749 "struct '%s'"
750 % (discriminator, base))
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800751 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600752 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800753 # Do not allow string discriminator
754 if not enum_define:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100755 raise QAPISemError(info,
756 "Discriminator '%s' must be of enumeration "
757 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800758
Eric Blake02a57ae2016-02-17 23:48:16 -0700759 # Check every branch; don't allow an empty union
760 if len(members) == 0:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100761 raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800762 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100763 check_name(info, "Member of union '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600764
Eric Blake01cfbaa2015-12-01 22:20:58 -0700765 # Each value must name a known type
Marc-André Lureau4148c292017-01-13 15:41:25 +0100766 check_type(info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200767 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600768
Eric Blake44bd1272015-05-04 09:05:08 -0600769 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700770 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600771 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600772 if key not in enum_define['enum_values']:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100773 raise QAPISemError(info,
774 "Discriminator value '%s' is not found in "
775 "enum '%s'"
776 % (key, enum_define["enum_name"]))
Eric Blake44bd1272015-05-04 09:05:08 -0600777
Eric Blaked0b18232016-07-13 21:50:13 -0600778 # If discriminator is user-defined, ensure all values are covered
779 if enum_define:
780 for value in enum_define['enum_values']:
781 if value not in members.keys():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100782 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
783 % (name, value))
Eric Blaked0b18232016-07-13 21:50:13 -0600784
Eric Blake437db252015-09-29 16:21:02 -0600785
Marc-André Lureau4148c292017-01-13 15:41:25 +0100786def check_alternate(expr, info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600787 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600788 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600789 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600790
Eric Blake02a57ae2016-02-17 23:48:16 -0700791 # Check every branch; require at least two branches
792 if len(members) < 2:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100793 raise QAPISemError(info,
794 "Alternate '%s' should have at least two branches "
795 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600796 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100797 check_name(info, "Member of alternate '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600798
Eric Blake811d04f2015-05-04 09:05:10 -0600799 # Ensure alternates have no type conflicts.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100800 check_type(info, "Member '%s' of alternate '%s'" % (key, name),
Eric Blakedd883c62015-05-04 09:05:21 -0600801 value,
802 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600803 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700804 if not qtype:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100805 raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
806 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600807 if qtype in types_seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100808 raise QAPISemError(info, "Alternate '%s' member '%s' can't "
809 "be distinguished from member '%s'"
810 % (name, key, types_seen[qtype]))
Eric Blake811d04f2015-05-04 09:05:10 -0600811 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800812
Eric Blake437db252015-09-29 16:21:02 -0600813
Marc-André Lureau4148c292017-01-13 15:41:25 +0100814def check_enum(expr, info):
Eric Blakecf393592015-05-04 09:05:04 -0600815 name = expr['enum']
816 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100817 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600818
819 if not isinstance(members, list):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100820 raise QAPISemError(info,
821 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100822 if prefix is not None and not isinstance(prefix, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100823 raise QAPISemError(info,
824 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600825 for member in members:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100826 check_name(info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600827 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600828
Eric Blake437db252015-09-29 16:21:02 -0600829
Marc-André Lureau4148c292017-01-13 15:41:25 +0100830def check_struct(expr, info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600831 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600832 members = expr['data']
833
Marc-André Lureau4148c292017-01-13 15:41:25 +0100834 check_type(info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600835 allow_dict=True, allow_optional=True)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100836 check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600837 allow_metas=['struct'])
838
Eric Blake437db252015-09-29 16:21:02 -0600839
Eric Blake0545f6b2015-05-04 09:05:15 -0600840def check_keys(expr_elem, meta, required, optional=[]):
841 expr = expr_elem['expr']
842 info = expr_elem['info']
843 name = expr[meta]
844 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100845 raise QAPISemError(info, "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600846 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600847 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600848 if key not in required and key not in optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100849 raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
850 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600851 if (key == 'gen' or key == 'success-response') and value is not False:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100852 raise QAPISemError(info,
853 "'%s' of %s '%s' should only use false value"
854 % (key, meta, name))
Eric Blakec8184082016-07-13 21:50:20 -0600855 if key == 'boxed' and value is not True:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100856 raise QAPISemError(info,
857 "'%s' of %s '%s' should only use true value"
858 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600859 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600860 if key not in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100861 raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
862 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600863
Eric Blake437db252015-09-29 16:21:02 -0600864
Markus Armbruster4d076d62015-06-10 08:55:21 +0200865def check_exprs(exprs):
866 global all_names
867
868 # Learn the types and check for valid expression keys
869 for builtin in builtin_types.keys():
870 all_names[builtin] = 'built-in'
871 for expr_elem in exprs:
872 expr = expr_elem['expr']
873 info = expr_elem['info']
Marc-André Lureau3313b612017-01-13 15:41:29 +0100874
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100875 if 'doc' not in expr_elem and doc_required:
Marc-André Lureau3313b612017-01-13 15:41:29 +0100876 raise QAPISemError(info,
877 "Expression missing documentation comment")
878
Eric Blake437db252015-09-29 16:21:02 -0600879 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100880 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200881 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600882 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200883 check_keys(expr_elem, 'union', ['data'],
884 ['base', 'discriminator'])
885 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600886 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200887 check_keys(expr_elem, 'alternate', ['data'])
888 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600889 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200890 check_keys(expr_elem, 'struct', ['data'], ['base'])
891 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600892 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200893 check_keys(expr_elem, 'command', [],
Eric Blakec8184082016-07-13 21:50:20 -0600894 ['data', 'returns', 'gen', 'success-response', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200895 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600896 elif 'event' in expr:
Eric Blakec8184082016-07-13 21:50:20 -0600897 check_keys(expr_elem, 'event', [], ['data', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200898 add_name(expr['event'], info, 'event')
899 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100900 raise QAPISemError(expr_elem['info'],
901 "Expression is missing metatype")
Markus Armbruster4d076d62015-06-10 08:55:21 +0200902
903 # Try again for hidden UnionKind enum
904 for expr_elem in exprs:
905 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600906 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200907 if not discriminator_find_enum_define(expr):
908 add_enum('%sKind' % expr['union'], expr_elem['info'],
909 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600910 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200911 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
912 implicit=True)
913
914 # Validate that exprs make sense
915 for expr_elem in exprs:
916 expr = expr_elem['expr']
917 info = expr_elem['info']
918
Eric Blake437db252015-09-29 16:21:02 -0600919 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200920 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600921 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200922 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600923 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200924 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600925 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200926 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600927 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200928 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600929 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200930 check_event(expr, info)
931 else:
932 assert False, 'unexpected meta type'
933
Markus Armbrusterac882192015-09-16 13:06:05 +0200934 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600935
Markus Armbrusterac882192015-09-16 13:06:05 +0200936
Marc-André Lureau3313b612017-01-13 15:41:29 +0100937def check_freeform_doc(doc):
938 if doc.symbol:
939 raise QAPISemError(doc.info,
940 "Documention for '%s' is not followed"
941 " by the definition" % doc.symbol)
942
943 body = str(doc.body)
944 if re.search(r'@\S+:', body, re.MULTILINE):
945 raise QAPISemError(doc.info,
946 "Free-form documentation block must not contain"
947 " @NAME: sections")
948
949
950def check_definition_doc(doc, expr, info):
951 for i in ('enum', 'union', 'alternate', 'struct', 'command', 'event'):
952 if i in expr:
953 meta = i
954 break
955
956 name = expr[meta]
957 if doc.symbol != name:
958 raise QAPISemError(info, "Definition of '%s' follows documentation"
959 " for '%s'" % (name, doc.symbol))
960 if doc.has_section('Returns') and 'command' not in expr:
961 raise QAPISemError(info, "'Returns:' is only valid for commands")
962
963 if meta == 'union':
964 args = expr.get('base', [])
965 else:
966 args = expr.get('data', [])
967 if isinstance(args, str):
968 return
969 if isinstance(args, dict):
970 args = args.keys()
971 assert isinstance(args, list)
972
973 if (meta == 'alternate'
974 or (meta == 'union' and not expr.get('discriminator'))):
975 args.append('type')
976
977 for arg in args:
978 if arg[0] == '*':
979 opt = True
980 desc = doc.args.get(arg[1:])
981 else:
982 opt = False
983 desc = doc.args.get(arg)
984 if not desc:
985 continue
Markus Armbrusterb116fd82017-03-15 13:57:00 +0100986 desc.optional = opt
Marc-André Lureau3313b612017-01-13 15:41:29 +0100987 desc_opt = "#optional" in str(desc)
988 if desc_opt and not opt:
989 raise QAPISemError(info, "Description has #optional, "
990 "but the declaration doesn't")
991 if not desc_opt and opt:
Marc-André Lureau3313b612017-01-13 15:41:29 +0100992 # TODO either fix the schema and make this an error,
993 # or drop #optional entirely
Markus Armbrusterb116fd82017-03-15 13:57:00 +0100994 pass
Marc-André Lureau3313b612017-01-13 15:41:29 +0100995
996 doc_args = set(doc.args.keys())
997 args = set([name.strip('*') for name in args])
998 if not doc_args.issubset(args):
999 raise QAPISemError(info, "The following documented members are not in "
1000 "the declaration: %s" % ", ".join(doc_args - args))
1001
1002
1003def check_docs(docs):
1004 for doc in docs:
1005 for section in doc.args.values() + doc.sections:
1006 content = str(section)
1007 if not content or content.isspace():
1008 raise QAPISemError(doc.info,
1009 "Empty doc section '%s'" % section.name)
1010
1011 if not doc.expr:
1012 check_freeform_doc(doc)
1013 else:
1014 check_definition_doc(doc, doc.expr, doc.info)
1015
1016 return docs
1017
1018
Markus Armbrusterac882192015-09-16 13:06:05 +02001019#
1020# Schema compiler frontend
1021#
1022
1023class QAPISchemaEntity(object):
1024 def __init__(self, name, info):
1025 assert isinstance(name, str)
1026 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -06001027 # For explicitly defined entities, info points to the (explicit)
1028 # definition. For builtins (and their arrays), info is None.
1029 # For implicitly defined entities, info points to a place that
1030 # triggered the implicit definition (there may be more than one
1031 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +02001032 self.info = info
1033
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001034 def c_name(self):
1035 return c_name(self.name)
1036
Markus Armbrusterac882192015-09-16 13:06:05 +02001037 def check(self, schema):
1038 pass
1039
Eric Blake49823c42015-10-12 22:22:27 -06001040 def is_implicit(self):
1041 return not self.info
1042
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001043 def visit(self, visitor):
1044 pass
1045
1046
1047class QAPISchemaVisitor(object):
1048 def visit_begin(self, schema):
1049 pass
1050
1051 def visit_end(self):
1052 pass
1053
Eric Blake25a0d9c2015-10-12 22:22:21 -06001054 def visit_needed(self, entity):
1055 # Default to visiting everything
1056 return True
1057
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001058 def visit_builtin_type(self, name, info, json_type):
1059 pass
1060
1061 def visit_enum_type(self, name, info, values, prefix):
1062 pass
1063
1064 def visit_array_type(self, name, info, element_type):
1065 pass
1066
1067 def visit_object_type(self, name, info, base, members, variants):
1068 pass
1069
Markus Armbruster39a18152015-09-16 13:06:28 +02001070 def visit_object_type_flat(self, name, info, members, variants):
1071 pass
1072
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001073 def visit_alternate_type(self, name, info, variants):
1074 pass
1075
1076 def visit_command(self, name, info, arg_type, ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001077 gen, success_response, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001078 pass
1079
Eric Blake48825ca2016-07-13 21:50:19 -06001080 def visit_event(self, name, info, arg_type, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001081 pass
1082
Markus Armbrusterac882192015-09-16 13:06:05 +02001083
1084class QAPISchemaType(QAPISchemaEntity):
Eric Blake4040d992016-03-17 16:48:28 -06001085 # Return the C type for common use.
1086 # For the types we commonly box, this is a pointer type.
1087 def c_type(self):
1088 pass
1089
1090 # Return the C type to be used in a parameter list.
1091 def c_param_type(self):
1092 return self.c_type()
1093
1094 # Return the C type to be used where we suppress boxing.
1095 def c_unboxed_type(self):
1096 return self.c_type()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001097
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001098 def json_type(self):
1099 pass
1100
1101 def alternate_qtype(self):
1102 json2qtype = {
1103 'string': 'QTYPE_QSTRING',
1104 'number': 'QTYPE_QFLOAT',
1105 'int': 'QTYPE_QINT',
1106 'boolean': 'QTYPE_QBOOL',
1107 'object': 'QTYPE_QDICT'
1108 }
1109 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +02001110
1111
1112class QAPISchemaBuiltinType(QAPISchemaType):
Eric Blake861877a2016-03-17 16:48:36 -06001113 def __init__(self, name, json_type, c_type):
Markus Armbrusterac882192015-09-16 13:06:05 +02001114 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001115 assert not c_type or isinstance(c_type, str)
1116 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
1117 'value')
1118 self._json_type_name = json_type
1119 self._c_type_name = c_type
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001120
1121 def c_name(self):
1122 return self.name
1123
Eric Blake4040d992016-03-17 16:48:28 -06001124 def c_type(self):
1125 return self._c_type_name
1126
1127 def c_param_type(self):
1128 if self.name == 'str':
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001129 return 'const ' + self._c_type_name
1130 return self._c_type_name
1131
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001132 def json_type(self):
1133 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +02001134
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001135 def visit(self, visitor):
1136 visitor.visit_builtin_type(self.name, self.info, self.json_type())
1137
Markus Armbrusterac882192015-09-16 13:06:05 +02001138
1139class QAPISchemaEnumType(QAPISchemaType):
1140 def __init__(self, name, info, values, prefix):
1141 QAPISchemaType.__init__(self, name, info)
1142 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -07001143 assert isinstance(v, QAPISchemaMember)
1144 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001145 assert prefix is None or isinstance(prefix, str)
1146 self.values = values
1147 self.prefix = prefix
1148
1149 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -07001150 seen = {}
1151 for v in self.values:
1152 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001153
Eric Blake99df5282015-10-12 22:22:32 -06001154 def is_implicit(self):
Markus Armbruster46362112017-03-15 13:57:02 +01001155 # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
1156 return self.name.endswith('Kind') or self.name == 'QType'
Eric Blake99df5282015-10-12 22:22:32 -06001157
Eric Blake4040d992016-03-17 16:48:28 -06001158 def c_type(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001159 return c_name(self.name)
1160
Eric Blake93bda4d2015-12-01 22:20:55 -07001161 def member_names(self):
1162 return [v.name for v in self.values]
1163
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001164 def json_type(self):
1165 return 'string'
1166
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001167 def visit(self, visitor):
1168 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -07001169 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001170
Markus Armbrusterac882192015-09-16 13:06:05 +02001171
1172class QAPISchemaArrayType(QAPISchemaType):
1173 def __init__(self, name, info, element_type):
1174 QAPISchemaType.__init__(self, name, info)
1175 assert isinstance(element_type, str)
1176 self._element_type_name = element_type
1177 self.element_type = None
1178
1179 def check(self, schema):
1180 self.element_type = schema.lookup_type(self._element_type_name)
1181 assert self.element_type
1182
Eric Blake99df5282015-10-12 22:22:32 -06001183 def is_implicit(self):
1184 return True
1185
Eric Blake4040d992016-03-17 16:48:28 -06001186 def c_type(self):
1187 return c_name(self.name) + pointer_suffix
1188
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001189 def json_type(self):
1190 return 'array'
1191
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001192 def visit(self, visitor):
1193 visitor.visit_array_type(self.name, self.info, self.element_type)
1194
Markus Armbrusterac882192015-09-16 13:06:05 +02001195
1196class QAPISchemaObjectType(QAPISchemaType):
1197 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -07001198 # struct has local_members, optional base, and no variants
1199 # flat union has base, variants, and no local_members
1200 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +02001201 QAPISchemaType.__init__(self, name, info)
1202 assert base is None or isinstance(base, str)
1203 for m in local_members:
1204 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -07001205 m.set_owner(name)
1206 if variants is not None:
1207 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1208 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001209 self._base_name = base
1210 self.base = None
1211 self.local_members = local_members
1212 self.variants = variants
1213 self.members = None
1214
1215 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -07001216 if self.members is False: # check for cycles
Marc-André Lureau4148c292017-01-13 15:41:25 +01001217 raise QAPISemError(self.info,
1218 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001219 if self.members:
1220 return
1221 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -07001222 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +02001223 if self._base_name:
1224 self.base = schema.lookup_type(self._base_name)
1225 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +02001226 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001227 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001228 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001229 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001230 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001231 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +02001232 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001233 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001234 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -07001235 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001236
Eric Blake14f00c62016-03-03 09:16:43 -07001237 # Check that the members of this type do not cause duplicate JSON members,
Eric Blake27b60ab2015-11-18 01:52:51 -07001238 # and update seen to track the members seen so far. Report any errors
1239 # on behalf of info, which is not necessarily self.info
1240 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -07001241 assert not self.variants # not implemented
1242 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -07001243 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -07001244
Eric Blake99df5282015-10-12 22:22:32 -06001245 def is_implicit(self):
Eric Blake75996972016-03-17 16:48:29 -06001246 # See QAPISchema._make_implicit_object_type(), as well as
1247 # _def_predefineds()
1248 return self.name.startswith('q_')
Eric Blake99df5282015-10-12 22:22:32 -06001249
Eric Blakeb6167702016-07-13 21:50:16 -06001250 def is_empty(self):
1251 assert self.members is not None
1252 return not self.members and not self.variants
1253
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001254 def c_name(self):
Eric Blakecd50a252016-07-13 21:50:14 -06001255 assert self.name != 'q_empty'
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001256 return QAPISchemaType.c_name(self)
1257
Eric Blake4040d992016-03-17 16:48:28 -06001258 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001259 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -07001260 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001261
Eric Blake4040d992016-03-17 16:48:28 -06001262 def c_unboxed_type(self):
Eric Blake4040d992016-03-17 16:48:28 -06001263 return c_name(self.name)
1264
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001265 def json_type(self):
1266 return 'object'
1267
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001268 def visit(self, visitor):
1269 visitor.visit_object_type(self.name, self.info,
1270 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001271 visitor.visit_object_type_flat(self.name, self.info,
1272 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001273
Markus Armbrusterac882192015-09-16 13:06:05 +02001274
Eric Blaked44f9ac2015-12-01 22:20:54 -07001275class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001276 role = 'member'
1277
Eric Blaked44f9ac2015-12-01 22:20:54 -07001278 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001279 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001280 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001281 self.owner = None
1282
1283 def set_owner(self, name):
1284 assert not self.owner
1285 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001286
Eric Blake27b60ab2015-11-18 01:52:51 -07001287 def check_clash(self, info, seen):
1288 cname = c_name(self.name)
Markus Armbruster2cfbae32017-03-15 13:56:55 +01001289 if cname.lower() != cname and self.owner not in name_case_whitelist:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001290 raise QAPISemError(info,
1291 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001292 if cname in seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001293 raise QAPISemError(info, "%s collides with %s" %
1294 (self.describe(), seen[cname].describe()))
Eric Blake27b60ab2015-11-18 01:52:51 -07001295 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001296
Eric Blake88d4ef82015-11-18 01:52:50 -07001297 def _pretty_owner(self):
1298 owner = self.owner
Eric Blake75996972016-03-17 16:48:29 -06001299 if owner.startswith('q_obj_'):
Eric Blake88d4ef82015-11-18 01:52:50 -07001300 # See QAPISchema._make_implicit_object_type() - reverse the
1301 # mapping there to create a nice human-readable description
Eric Blake75996972016-03-17 16:48:29 -06001302 owner = owner[6:]
Eric Blake88d4ef82015-11-18 01:52:50 -07001303 if owner.endswith('-arg'):
1304 return '(parameter of %s)' % owner[:-4]
Eric Blakeac4338f2016-03-17 16:48:39 -06001305 elif owner.endswith('-base'):
1306 return '(base of %s)' % owner[:-5]
Eric Blake88d4ef82015-11-18 01:52:50 -07001307 else:
1308 assert owner.endswith('-wrapper')
1309 # Unreachable and not implemented
1310 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001311 if owner.endswith('Kind'):
1312 # See QAPISchema._make_implicit_enum_type()
1313 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001314 return '(%s of %s)' % (self.role, owner)
1315
1316 def describe(self):
1317 return "'%s' %s" % (self.name, self._pretty_owner())
1318
Markus Armbrusterac882192015-09-16 13:06:05 +02001319
Eric Blaked44f9ac2015-12-01 22:20:54 -07001320class QAPISchemaObjectTypeMember(QAPISchemaMember):
1321 def __init__(self, name, typ, optional):
1322 QAPISchemaMember.__init__(self, name)
1323 assert isinstance(typ, str)
1324 assert isinstance(optional, bool)
1325 self._type_name = typ
1326 self.type = None
1327 self.optional = optional
1328
1329 def check(self, schema):
1330 assert self.owner
1331 self.type = schema.lookup_type(self._type_name)
1332 assert self.type
1333
1334
Markus Armbrusterac882192015-09-16 13:06:05 +02001335class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001336 def __init__(self, tag_name, tag_member, variants):
1337 # Flat unions pass tag_name but not tag_member.
1338 # Simple unions and alternates pass tag_member but not tag_name.
1339 # After check(), tag_member is always set, and tag_name remains
1340 # a reliable witness of being used by a flat union.
1341 assert bool(tag_member) != bool(tag_name)
1342 assert (isinstance(tag_name, str) or
1343 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001344 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001345 for v in variants:
1346 assert isinstance(v, QAPISchemaObjectTypeVariant)
Eric Blakeda9cb192016-07-13 21:50:15 -06001347 self._tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001348 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001349 self.variants = variants
1350
Eric Blake88d4ef82015-11-18 01:52:50 -07001351 def set_owner(self, name):
1352 for v in self.variants:
1353 v.set_owner(name)
1354
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001355 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001356 if not self.tag_member: # flat union
Eric Blakeda9cb192016-07-13 21:50:15 -06001357 self.tag_member = seen[c_name(self._tag_name)]
1358 assert self._tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001359 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1360 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001361 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001362 # Union names must match enum values; alternate names are
1363 # checked separately. Use 'seen' to tell the two apart.
1364 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001365 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001366 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001367 v.type.check(schema)
1368
Eric Blake27b60ab2015-11-18 01:52:51 -07001369 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001370 for v in self.variants:
1371 # Reset seen map for each variant, since qapi names from one
1372 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001373 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001374 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001375
Eric Blake437db252015-09-29 16:21:02 -06001376
Markus Armbrusterac882192015-09-16 13:06:05 +02001377class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001378 role = 'branch'
1379
Markus Armbrusterac882192015-09-16 13:06:05 +02001380 def __init__(self, name, typ):
1381 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1382
Markus Armbrusterac882192015-09-16 13:06:05 +02001383
1384class QAPISchemaAlternateType(QAPISchemaType):
1385 def __init__(self, name, info, variants):
1386 QAPISchemaType.__init__(self, name, info)
1387 assert isinstance(variants, QAPISchemaObjectTypeVariants)
Eric Blakeda9cb192016-07-13 21:50:15 -06001388 assert variants.tag_member
Eric Blake88d4ef82015-11-18 01:52:50 -07001389 variants.set_owner(name)
1390 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001391 self.variants = variants
1392
1393 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001394 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001395 # Not calling self.variants.check_clash(), because there's nothing
1396 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001397 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001398 # Alternate branch names have no relation to the tag enum values;
1399 # so we have to check for potential name collisions ourselves.
1400 seen = {}
1401 for v in self.variants.variants:
1402 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001403
Eric Blake4040d992016-03-17 16:48:28 -06001404 def c_type(self):
1405 return c_name(self.name) + pointer_suffix
1406
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001407 def json_type(self):
1408 return 'value'
1409
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001410 def visit(self, visitor):
1411 visitor.visit_alternate_type(self.name, self.info, self.variants)
1412
Eric Blakec8184082016-07-13 21:50:20 -06001413 def is_empty(self):
1414 return False
1415
Markus Armbrusterac882192015-09-16 13:06:05 +02001416
1417class QAPISchemaCommand(QAPISchemaEntity):
Eric Blake48825ca2016-07-13 21:50:19 -06001418 def __init__(self, name, info, arg_type, ret_type, gen, success_response,
1419 boxed):
Markus Armbrusterac882192015-09-16 13:06:05 +02001420 QAPISchemaEntity.__init__(self, name, info)
1421 assert not arg_type or isinstance(arg_type, str)
1422 assert not ret_type or isinstance(ret_type, str)
1423 self._arg_type_name = arg_type
1424 self.arg_type = None
1425 self._ret_type_name = ret_type
1426 self.ret_type = None
1427 self.gen = gen
1428 self.success_response = success_response
Eric Blake48825ca2016-07-13 21:50:19 -06001429 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001430
1431 def check(self, schema):
1432 if self._arg_type_name:
1433 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001434 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1435 isinstance(self.arg_type, QAPISchemaAlternateType))
1436 self.arg_type.check(schema)
1437 if self.boxed:
1438 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001439 raise QAPISemError(self.info,
1440 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001441 else:
1442 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1443 assert not self.arg_type.variants
1444 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001445 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001446 if self._ret_type_name:
1447 self.ret_type = schema.lookup_type(self._ret_type_name)
1448 assert isinstance(self.ret_type, QAPISchemaType)
1449
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001450 def visit(self, visitor):
1451 visitor.visit_command(self.name, self.info,
1452 self.arg_type, self.ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001453 self.gen, self.success_response, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001454
Markus Armbrusterac882192015-09-16 13:06:05 +02001455
1456class QAPISchemaEvent(QAPISchemaEntity):
Eric Blake48825ca2016-07-13 21:50:19 -06001457 def __init__(self, name, info, arg_type, boxed):
Markus Armbrusterac882192015-09-16 13:06:05 +02001458 QAPISchemaEntity.__init__(self, name, info)
1459 assert not arg_type or isinstance(arg_type, str)
1460 self._arg_type_name = arg_type
1461 self.arg_type = None
Eric Blake48825ca2016-07-13 21:50:19 -06001462 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001463
1464 def check(self, schema):
1465 if self._arg_type_name:
1466 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001467 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1468 isinstance(self.arg_type, QAPISchemaAlternateType))
1469 self.arg_type.check(schema)
1470 if self.boxed:
1471 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001472 raise QAPISemError(self.info,
1473 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001474 else:
1475 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1476 assert not self.arg_type.variants
1477 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001478 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001479
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001480 def visit(self, visitor):
Eric Blake48825ca2016-07-13 21:50:19 -06001481 visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001482
Markus Armbrusterac882192015-09-16 13:06:05 +02001483
1484class QAPISchema(object):
1485 def __init__(self, fname):
1486 try:
Marc-André Lureau3313b612017-01-13 15:41:29 +01001487 parser = QAPISchemaParser(open(fname, "r"))
1488 self.exprs = check_exprs(parser.exprs)
1489 self.docs = check_docs(parser.docs)
Eric Blake7618b912015-10-12 22:22:22 -06001490 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001491 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001492 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001493 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001494 self._def_exprs()
1495 self.check()
Marc-André Lureau4148c292017-01-13 15:41:25 +01001496 except QAPIError as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001497 print >>sys.stderr, err
1498 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001499
Markus Armbrusterac882192015-09-16 13:06:05 +02001500 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001501 # Only the predefined types are allowed to not have info
1502 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001503 assert ent.name not in self._entity_dict
1504 self._entity_dict[ent.name] = ent
1505
1506 def lookup_entity(self, name, typ=None):
1507 ent = self._entity_dict.get(name)
1508 if typ and not isinstance(ent, typ):
1509 return None
1510 return ent
1511
1512 def lookup_type(self, name):
1513 return self.lookup_entity(name, QAPISchemaType)
1514
Eric Blake861877a2016-03-17 16:48:36 -06001515 def _def_builtin_type(self, name, json_type, c_type):
1516 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001517 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1518 # qapi-types.h from a single .c, all arrays of builtins must be
1519 # declared in the first file whether or not they are used. Nicer
1520 # would be to use lazy instantiation, while figuring out how to
1521 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001522 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001523
1524 def _def_predefineds(self):
Eric Blake861877a2016-03-17 16:48:36 -06001525 for t in [('str', 'string', 'char' + pointer_suffix),
1526 ('number', 'number', 'double'),
1527 ('int', 'int', 'int64_t'),
1528 ('int8', 'int', 'int8_t'),
1529 ('int16', 'int', 'int16_t'),
1530 ('int32', 'int', 'int32_t'),
1531 ('int64', 'int', 'int64_t'),
1532 ('uint8', 'int', 'uint8_t'),
1533 ('uint16', 'int', 'uint16_t'),
1534 ('uint32', 'int', 'uint32_t'),
1535 ('uint64', 'int', 'uint64_t'),
1536 ('size', 'int', 'uint64_t'),
1537 ('bool', 'boolean', 'bool'),
1538 ('any', 'value', 'QObject' + pointer_suffix)]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001539 self._def_builtin_type(*t)
Eric Blake75996972016-03-17 16:48:29 -06001540 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1541 None, [], None)
Markus Armbruster39a18152015-09-16 13:06:28 +02001542 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001543 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1544 'qstring', 'qdict', 'qlist',
1545 'qfloat', 'qbool'])
1546 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001547 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001548
Eric Blake93bda4d2015-12-01 22:20:55 -07001549 def _make_enum_members(self, values):
1550 return [QAPISchemaMember(v) for v in values]
1551
Eric Blake99df5282015-10-12 22:22:32 -06001552 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001553 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001554 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001555 self._def_entity(QAPISchemaEnumType(
1556 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001557 return name
1558
Eric Blake99df5282015-10-12 22:22:32 -06001559 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001560 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001561 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001562 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001563 return name
1564
Eric Blake99df5282015-10-12 22:22:32 -06001565 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001566 if not members:
1567 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001568 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake75996972016-03-17 16:48:29 -06001569 name = 'q_obj_%s-%s' % (name, role)
Markus Armbrusterac882192015-09-16 13:06:05 +02001570 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001571 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001572 members, None))
1573 return name
1574
1575 def _def_enum_type(self, expr, info):
1576 name = expr['enum']
1577 data = expr['data']
1578 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001579 self._def_entity(QAPISchemaEnumType(
1580 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001581
Eric Blake99df5282015-10-12 22:22:32 -06001582 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001583 optional = False
1584 if name.startswith('*'):
1585 name = name[1:]
1586 optional = True
1587 if isinstance(typ, list):
1588 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001589 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001590 return QAPISchemaObjectTypeMember(name, typ, optional)
1591
Eric Blake99df5282015-10-12 22:22:32 -06001592 def _make_members(self, data, info):
1593 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001594 for (key, value) in data.iteritems()]
1595
1596 def _def_struct_type(self, expr, info):
1597 name = expr['struct']
1598 base = expr.get('base')
1599 data = expr['data']
1600 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001601 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001602 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001603
1604 def _make_variant(self, case, typ):
1605 return QAPISchemaObjectTypeVariant(case, typ)
1606
Eric Blake99df5282015-10-12 22:22:32 -06001607 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001608 if isinstance(typ, list):
1609 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001610 typ = self._make_array_type(typ[0], info)
1611 typ = self._make_implicit_object_type(
1612 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001613 return QAPISchemaObjectTypeVariant(case, typ)
1614
Markus Armbrusterac882192015-09-16 13:06:05 +02001615 def _def_union_type(self, expr, info):
1616 name = expr['union']
1617 data = expr['data']
1618 base = expr.get('base')
1619 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001620 tag_member = None
Eric Blakeac4338f2016-03-17 16:48:39 -06001621 if isinstance(base, dict):
1622 base = (self._make_implicit_object_type(
1623 name, info, 'base', self._make_members(base, info)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001624 if tag_name:
1625 variants = [self._make_variant(key, value)
1626 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001627 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001628 else:
Eric Blake99df5282015-10-12 22:22:32 -06001629 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001630 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001631 typ = self._make_implicit_enum_type(name, info,
1632 [v.name for v in variants])
1633 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001634 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001635 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001636 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001637 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001638 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001639 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001640
1641 def _def_alternate_type(self, expr, info):
1642 name = expr['alternate']
1643 data = expr['data']
1644 variants = [self._make_variant(key, value)
1645 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001646 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001647 self._def_entity(
1648 QAPISchemaAlternateType(name, info,
1649 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001650 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001651 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001652
1653 def _def_command(self, expr, info):
1654 name = expr['command']
1655 data = expr.get('data')
1656 rets = expr.get('returns')
1657 gen = expr.get('gen', True)
1658 success_response = expr.get('success-response', True)
Eric Blake48825ca2016-07-13 21:50:19 -06001659 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001660 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001661 data = self._make_implicit_object_type(
1662 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001663 if isinstance(rets, list):
1664 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001665 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001666 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
Eric Blake48825ca2016-07-13 21:50:19 -06001667 success_response, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001668
1669 def _def_event(self, expr, info):
1670 name = expr['event']
1671 data = expr.get('data')
Eric Blake48825ca2016-07-13 21:50:19 -06001672 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001673 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001674 data = self._make_implicit_object_type(
1675 name, info, 'arg', self._make_members(data, info))
Eric Blake48825ca2016-07-13 21:50:19 -06001676 self._def_entity(QAPISchemaEvent(name, info, data, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001677
1678 def _def_exprs(self):
1679 for expr_elem in self.exprs:
1680 expr = expr_elem['expr']
1681 info = expr_elem['info']
1682 if 'enum' in expr:
1683 self._def_enum_type(expr, info)
1684 elif 'struct' in expr:
1685 self._def_struct_type(expr, info)
1686 elif 'union' in expr:
1687 self._def_union_type(expr, info)
1688 elif 'alternate' in expr:
1689 self._def_alternate_type(expr, info)
1690 elif 'command' in expr:
1691 self._def_command(expr, info)
1692 elif 'event' in expr:
1693 self._def_event(expr, info)
1694 else:
1695 assert False
1696
1697 def check(self):
1698 for ent in self._entity_dict.values():
1699 ent.check(self)
1700
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001701 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001702 visitor.visit_begin(self)
1703 for (name, entity) in sorted(self._entity_dict.items()):
1704 if visitor.visit_needed(entity):
1705 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001706 visitor.visit_end()
1707
Markus Armbruster2caba362013-07-27 17:41:56 +02001708
Markus Armbruster00e4b282015-06-10 10:04:36 +02001709#
1710# Code generation helpers
1711#
1712
Michael Roth0f923be2011-07-19 14:50:39 -05001713def camel_case(name):
1714 new_name = ''
1715 first = True
1716 for ch in name:
1717 if ch in ['_', '-']:
1718 first = True
1719 elif first:
1720 new_name += ch.upper()
1721 first = False
1722 else:
1723 new_name += ch.lower()
1724 return new_name
1725
Eric Blake437db252015-09-29 16:21:02 -06001726
Markus Armbruster849bc532015-05-14 06:50:53 -06001727# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1728# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1729# ENUM24_Name -> ENUM24_NAME
1730def camel_to_upper(value):
1731 c_fun_str = c_name(value, False)
1732 if value.isupper():
1733 return c_fun_str
1734
1735 new_name = ''
1736 l = len(c_fun_str)
1737 for i in range(l):
1738 c = c_fun_str[i]
1739 # When c is upper and no "_" appears before, do more checks
1740 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001741 if i < l - 1 and c_fun_str[i + 1].islower():
1742 new_name += '_'
1743 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001744 new_name += '_'
1745 new_name += c
1746 return new_name.lstrip('_').upper()
1747
Eric Blake437db252015-09-29 16:21:02 -06001748
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001749def c_enum_const(type_name, const_name, prefix=None):
1750 if prefix is not None:
1751 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001752 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001753
Eric Blake18df5152015-05-14 06:50:48 -06001754c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001755
Eric Blake437db252015-09-29 16:21:02 -06001756
Eric Blakec6405b52015-05-14 06:50:55 -06001757# Map @name to a valid C identifier.
1758# If @protect, avoid returning certain ticklish identifiers (like
1759# C keywords) by prepending "q_".
1760#
1761# Used for converting 'name' from a 'name':'type' qapi definition
1762# into a generated struct member, as well as converting type names
1763# into substrings of a generated C function name.
1764# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1765# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001766def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001767 # ANSI X3J11/88-090, 3.1.1
1768 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001769 'default', 'do', 'double', 'else', 'enum', 'extern',
1770 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1771 'return', 'short', 'signed', 'sizeof', 'static',
1772 'struct', 'switch', 'typedef', 'union', 'unsigned',
1773 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001774 # ISO/IEC 9899:1999, 6.4.1
1775 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1776 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001777 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1778 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001779 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1780 # excluding _.*
1781 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001782 # C++ ISO/IEC 14882:2003 2.11
1783 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1784 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1785 'namespace', 'new', 'operator', 'private', 'protected',
1786 'public', 'reinterpret_cast', 'static_cast', 'template',
1787 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1788 'using', 'virtual', 'wchar_t',
1789 # alternative representations
1790 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1791 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001792 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001793 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001794 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001795 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1796 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001797 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001798 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001799
Amos Kong05dfb262014-06-10 19:25:53 +08001800eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001801pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001802
Eric Blake437db252015-09-29 16:21:02 -06001803
Michael Roth0f923be2011-07-19 14:50:39 -05001804def genindent(count):
1805 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001806 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001807 ret += " "
1808 return ret
1809
1810indent_level = 0
1811
Eric Blake437db252015-09-29 16:21:02 -06001812
Michael Roth0f923be2011-07-19 14:50:39 -05001813def push_indent(indent_amount=4):
1814 global indent_level
1815 indent_level += indent_amount
1816
Eric Blake437db252015-09-29 16:21:02 -06001817
Michael Roth0f923be2011-07-19 14:50:39 -05001818def pop_indent(indent_amount=4):
1819 global indent_level
1820 indent_level -= indent_amount
1821
Eric Blake437db252015-09-29 16:21:02 -06001822
Markus Armbruster77e703b2015-06-24 19:27:32 +02001823# Generate @code with @kwds interpolated.
1824# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001825def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001826 raw = code % kwds
1827 if indent_level:
1828 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001829 # re.subn() lacks flags support before Python 2.7, use re.compile()
1830 raw = re.subn(re.compile("^.", re.MULTILINE),
1831 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001832 raw = raw[0]
1833 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001834
Eric Blake437db252015-09-29 16:21:02 -06001835
Michael Roth0f923be2011-07-19 14:50:39 -05001836def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001837 if code[0] == '\n':
1838 code = code[1:]
1839 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001840
Michael Roth0f923be2011-07-19 14:50:39 -05001841
1842def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001843 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001844
Eric Blake437db252015-09-29 16:21:02 -06001845
Michael Rothc0afa9c2013-05-10 17:46:00 -05001846def guardstart(name):
1847 return mcgen('''
1848
1849#ifndef %(name)s
1850#define %(name)s
1851
1852''',
1853 name=guardname(name))
1854
Eric Blake437db252015-09-29 16:21:02 -06001855
Michael Rothc0afa9c2013-05-10 17:46:00 -05001856def guardend(name):
1857 return mcgen('''
1858
1859#endif /* %(name)s */
1860
1861''',
1862 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001863
Eric Blake437db252015-09-29 16:21:02 -06001864
Markus Armbrustere98859a2015-09-16 13:06:16 +02001865def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001866 ret = mcgen('''
1867
Markus Armbrustere98859a2015-09-16 13:06:16 +02001868const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001869''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001870 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001871 for value in values:
1872 index = c_enum_const(name, value, prefix)
1873 ret += mcgen('''
1874 [%(index)s] = "%(value)s",
1875''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001876 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001877
Eric Blake7fb1cf12015-11-18 01:52:57 -07001878 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001879 ret += mcgen('''
1880 [%(max_index)s] = NULL,
1881};
1882''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001883 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001884 return ret
1885
Eric Blake437db252015-09-29 16:21:02 -06001886
Markus Armbrustere98859a2015-09-16 13:06:16 +02001887def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001888 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001889 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001890
1891 ret = mcgen('''
1892
1893typedef enum %(c_name)s {
1894''',
1895 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001896
1897 i = 0
1898 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001899 ret += mcgen('''
1900 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001901''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001902 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001903 i=i)
1904 i += 1
1905
Markus Armbrustere98859a2015-09-16 13:06:16 +02001906 ret += mcgen('''
1907} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001908''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001909 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001910
Markus Armbrustere98859a2015-09-16 13:06:16 +02001911 ret += mcgen('''
1912
1913extern const char *const %(c_name)s_lookup[];
1914''',
1915 c_name=c_name(name))
1916 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001917
Eric Blake437db252015-09-29 16:21:02 -06001918
Eric Blake48825ca2016-07-13 21:50:19 -06001919def gen_params(arg_type, boxed, extra):
Markus Armbruster03b43672015-09-16 13:06:20 +02001920 if not arg_type:
Eric Blakec8184082016-07-13 21:50:20 -06001921 assert not boxed
Markus Armbruster03b43672015-09-16 13:06:20 +02001922 return extra
Markus Armbruster03b43672015-09-16 13:06:20 +02001923 ret = ''
1924 sep = ''
Eric Blake48825ca2016-07-13 21:50:19 -06001925 if boxed:
Eric Blakec8184082016-07-13 21:50:20 -06001926 ret += '%s arg' % arg_type.c_param_type()
1927 sep = ', '
Eric Blake48825ca2016-07-13 21:50:19 -06001928 else:
1929 assert not arg_type.variants
1930 for memb in arg_type.members:
1931 ret += sep
1932 sep = ', '
1933 if memb.optional:
1934 ret += 'bool has_%s, ' % c_name(memb.name)
1935 ret += '%s %s' % (memb.type.c_param_type(),
1936 c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001937 if extra:
1938 ret += sep + extra
1939 return ret
1940
Eric Blake1f353342015-09-29 16:21:13 -06001941
Markus Armbruster00e4b282015-06-10 10:04:36 +02001942#
1943# Common command line parsing
1944#
1945
Eric Blake437db252015-09-29 16:21:02 -06001946
1947def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001948
1949 try:
1950 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001951 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001952 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001953 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001954 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001955 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001956 sys.exit(1)
1957
1958 output_dir = ""
1959 prefix = ""
1960 do_c = False
1961 do_h = False
1962 extra_opts = []
1963
1964 for oa in opts:
1965 o, a = oa
1966 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001967 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1968 if match.end() != len(a):
1969 print >>sys.stderr, \
1970 "%s: 'funny character '%s' in argument of --prefix" \
1971 % (sys.argv[0], a[match.end()])
1972 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001973 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001974 elif o in ("-o", "--output-dir"):
1975 output_dir = a + "/"
1976 elif o in ("-c", "--source"):
1977 do_c = True
1978 elif o in ("-h", "--header"):
1979 do_h = True
1980 else:
1981 extra_opts.append(oa)
1982
1983 if not do_c and not do_h:
1984 do_c = True
1985 do_h = True
1986
Markus Armbruster16d80f62015-04-02 13:32:16 +02001987 if len(args) != 1:
1988 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001989 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001990 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001991
Markus Armbruster54414042015-06-09 16:22:45 +02001992 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001993
Markus Armbruster00e4b282015-06-10 10:04:36 +02001994#
1995# Generate output files with boilerplate
1996#
1997
Eric Blake437db252015-09-29 16:21:02 -06001998
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001999def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
2000 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02002001 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002002 c_file = output_dir + prefix + c_file
2003 h_file = output_dir + prefix + h_file
2004
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02002005 if output_dir:
2006 try:
2007 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01002008 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02002009 if e.errno != errno.EEXIST:
2010 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002011
2012 def maybe_open(really, name, opt):
2013 if really:
2014 return open(name, opt)
2015 else:
2016 import StringIO
2017 return StringIO.StringIO()
2018
2019 fdef = maybe_open(do_c, c_file, 'w')
2020 fdecl = maybe_open(do_h, h_file, 'w')
2021
2022 fdef.write(mcgen('''
2023/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2024%(comment)s
2025''',
Eric Blake437db252015-09-29 16:21:02 -06002026 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002027
2028 fdecl.write(mcgen('''
2029/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2030%(comment)s
2031#ifndef %(guard)s
2032#define %(guard)s
2033
2034''',
Eric Blake437db252015-09-29 16:21:02 -06002035 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002036
2037 return (fdef, fdecl)
2038
Eric Blake437db252015-09-29 16:21:02 -06002039
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002040def close_output(fdef, fdecl):
2041 fdecl.write('''
2042#endif
2043''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002044 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002045 fdef.close()