blob: 9a1d830f2fb7648a9aec3662d0ad895cff73998c [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):
Markus Armbrusteref801a92017-03-15 13:57:08 +010061 res = ''
Lluís Vilanovaa719a272014-05-07 20:46:15 +020062 while parent:
Markus Armbrusteref801a92017-03-15 13:57:08 +010063 res = ('In file included from %s:%d:\n' % (parent['file'],
Lluís Vilanovaa719a272014-05-07 20:46:15 +020064 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):
Markus Armbrusteref801a92017-03-15 13:57:08 +010079 loc = '%s:%d' % (self.fname, self.line)
Marc-André Lureau4148c292017-01-13 15:41:25 +010080 if self.col is not None:
Markus Armbrusteref801a92017-03-15 13:57:08 +010081 loc += ':%s' % self.col
82 return error_path(self.info) + '%s: %s' % (loc, self.msg)
Marc-André Lureau4148c292017-01-13 15:41:25 +010083
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):
Markus Armbrusteref801a92017-03-15 13:57:08 +0100116 return '\n'.join(self.content).strip()
Marc-André Lureau3313b612017-01-13 15:41:29 +0100117
118 class ArgSection(Section):
Markus Armbruster069fb5b2017-03-15 13:57:03 +0100119 def __init__(self, name):
120 QAPIDoc.Section.__init__(self, name)
121 self.member = None
122
123 def connect(self, member):
124 self.member = member
Marc-André Lureau3313b612017-01-13 15:41:29 +0100125
126 def __init__(self, parser, info):
127 # self.parser is used to report errors with QAPIParseError. The
128 # resulting error position depends on the state of the parser.
129 # It happens to be the beginning of the comment. More or less
130 # servicable, but action at a distance.
131 self.parser = parser
132 self.info = info
133 self.symbol = None
134 self.body = QAPIDoc.Section()
135 # dict mapping parameter name to ArgSection
136 self.args = OrderedDict()
137 # a list of Section
138 self.sections = []
139 # the current section
140 self.section = self.body
141 # associated expression (to be set by expression parser)
142 self.expr = None
143
144 def has_section(self, name):
145 """Return True if we have a section with this name."""
146 for i in self.sections:
147 if i.name == name:
148 return True
149 return False
150
151 def append(self, line):
152 """Parse a comment line and add it to the documentation."""
153 line = line[1:]
154 if not line:
155 self._append_freeform(line)
156 return
157
158 if line[0] != ' ':
159 raise QAPIParseError(self.parser, "Missing space after #")
160 line = line[1:]
161
162 # FIXME not nice: things like '# @foo:' and '# @foo: ' aren't
163 # recognized, and get silently treated as ordinary text
164 if self.symbol:
165 self._append_symbol_line(line)
Markus Armbrusteref801a92017-03-15 13:57:08 +0100166 elif not self.body.content and line.startswith('@'):
167 if not line.endswith(':'):
Marc-André Lureau3313b612017-01-13 15:41:29 +0100168 raise QAPIParseError(self.parser, "Line should end with :")
169 self.symbol = line[1:-1]
170 # FIXME invalid names other than the empty string aren't flagged
171 if not self.symbol:
172 raise QAPIParseError(self.parser, "Invalid name")
173 else:
174 self._append_freeform(line)
175
176 def _append_symbol_line(self, line):
177 name = line.split(' ', 1)[0]
178
Markus Armbrusteref801a92017-03-15 13:57:08 +0100179 if name.startswith('@') and name.endswith(':'):
Marc-André Lureau3313b612017-01-13 15:41:29 +0100180 line = line[len(name)+1:]
181 self._start_args_section(name[1:-1])
Markus Armbrusteref801a92017-03-15 13:57:08 +0100182 elif name in ('Returns:', 'Since:',
Marc-André Lureau3313b612017-01-13 15:41:29 +0100183 # those are often singular or plural
Markus Armbrusteref801a92017-03-15 13:57:08 +0100184 'Note:', 'Notes:',
185 'Example:', 'Examples:',
186 'TODO:'):
Marc-André Lureau3313b612017-01-13 15:41:29 +0100187 line = line[len(name)+1:]
188 self._start_section(name[:-1])
189
190 self._append_freeform(line)
191
192 def _start_args_section(self, name):
193 # FIXME invalid names other than the empty string aren't flagged
194 if not name:
195 raise QAPIParseError(self.parser, "Invalid parameter name")
196 if name in self.args:
197 raise QAPIParseError(self.parser,
198 "'%s' parameter name duplicated" % name)
199 if self.sections:
200 raise QAPIParseError(self.parser,
201 "'@%s:' can't follow '%s' section"
202 % (name, self.sections[0].name))
203 self.section = QAPIDoc.ArgSection(name)
204 self.args[name] = self.section
205
Markus Armbrusteref801a92017-03-15 13:57:08 +0100206 def _start_section(self, name=''):
207 if name in ('Returns', 'Since') and self.has_section(name):
Marc-André Lureau3313b612017-01-13 15:41:29 +0100208 raise QAPIParseError(self.parser,
209 "Duplicated '%s' section" % name)
210 self.section = QAPIDoc.Section(name)
211 self.sections.append(self.section)
212
213 def _append_freeform(self, line):
214 in_arg = isinstance(self.section, QAPIDoc.ArgSection)
215 if (in_arg and self.section.content
216 and not self.section.content[-1]
217 and line and not line[0].isspace()):
218 self._start_section()
219 if (in_arg or not self.section.name
Markus Armbrusteref801a92017-03-15 13:57:08 +0100220 or not self.section.name.startswith('Example')):
Marc-André Lureau3313b612017-01-13 15:41:29 +0100221 line = line.strip()
Markus Armbruster1d8bda12017-03-15 13:57:06 +0100222 # TODO Drop this once the dust has settled
223 if (isinstance(self.section, QAPIDoc.ArgSection)
224 and '#optional' in line):
225 raise QAPISemError(self.info, "Please drop the #optional tag")
Marc-André Lureau3313b612017-01-13 15:41:29 +0100226 self.section.append(line)
227
Markus Armbruster069fb5b2017-03-15 13:57:03 +0100228 def connect_member(self, member):
229 if member.name not in self.args:
230 # Undocumented TODO outlaw
Markus Armbruster860e8772017-03-15 13:57:04 +0100231 self.args[member.name] = QAPIDoc.ArgSection(member.name)
232 self.args[member.name].connect(member)
Markus Armbruster069fb5b2017-03-15 13:57:03 +0100233
Marc-André Lureau3313b612017-01-13 15:41:29 +0100234
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200235class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500236
Eric Blake437db252015-09-29 16:21:02 -0600237 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200238 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200239 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200240 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200241 previously_included.append(abs_fname)
242 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200243 self.src = fp.read()
244 if self.src == '' or self.src[-1] != '\n':
245 self.src += '\n'
246 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800247 self.line = 1
248 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200249 self.exprs = []
Marc-André Lureau3313b612017-01-13 15:41:29 +0100250 self.docs = []
Markus Armbrustere7823a22017-03-15 13:57:20 +0100251 self.cur_doc = None
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200252 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500253
Eric Blake437db252015-09-29 16:21:02 -0600254 while self.tok is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100255 info = {'file': fname, 'line': self.line,
256 'parent': self.incl_info}
Marc-André Lureau3313b612017-01-13 15:41:29 +0100257 if self.tok == '#':
Markus Armbrustere7823a22017-03-15 13:57:20 +0100258 self.reject_expr_doc()
259 self.cur_doc = self.get_doc(info)
260 self.docs.append(self.cur_doc)
Marc-André Lureau3313b612017-01-13 15:41:29 +0100261 continue
262
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200263 expr = self.get_expr(False)
Markus Armbrustere04dea82017-03-15 13:56:50 +0100264 if 'include' in expr:
Markus Armbrustere7823a22017-03-15 13:57:20 +0100265 self.reject_expr_doc()
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200266 if len(expr) != 1:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100267 raise QAPISemError(info, "Invalid 'include' directive")
Markus Armbrusteref801a92017-03-15 13:57:08 +0100268 include = expr['include']
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200269 if not isinstance(include, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100270 raise QAPISemError(info,
271 "Value of 'include' must be a string")
Markus Armbrustere04dea82017-03-15 13:56:50 +0100272 self._include(include, info, os.path.dirname(abs_fname),
273 previously_included)
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100274 elif "pragma" in expr:
Markus Armbrustere7823a22017-03-15 13:57:20 +0100275 self.reject_expr_doc()
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100276 if len(expr) != 1:
277 raise QAPISemError(info, "Invalid 'pragma' directive")
278 pragma = expr['pragma']
279 if not isinstance(pragma, dict):
280 raise QAPISemError(
281 info, "Value of 'pragma' must be a dictionary")
282 for name, value in pragma.iteritems():
283 self._pragma(name, value, info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200284 else:
285 expr_elem = {'expr': expr,
Marc-André Lureau4148c292017-01-13 15:41:25 +0100286 'info': info}
Markus Armbrustere7823a22017-03-15 13:57:20 +0100287 if self.cur_doc:
288 if not self.cur_doc.symbol:
289 raise QAPISemError(
290 self.cur_doc.info,
291 "Expression documentation required")
292 self.cur_doc.expr = expr
293 expr_elem['doc'] = self.cur_doc
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200294 self.exprs.append(expr_elem)
Markus Armbrustere7823a22017-03-15 13:57:20 +0100295 self.cur_doc = None
296 self.reject_expr_doc()
297
298 def reject_expr_doc(self):
299 if self.cur_doc and self.cur_doc.symbol:
300 raise QAPISemError(
301 self.cur_doc.info,
302 "Documentation for '%s' is not followed by the definition"
303 % self.cur_doc.symbol)
Michael Roth0f923be2011-07-19 14:50:39 -0500304
Markus Armbrustere04dea82017-03-15 13:56:50 +0100305 def _include(self, include, info, base_dir, previously_included):
306 incl_abs_fname = os.path.join(base_dir, include)
307 # catch inclusion cycle
308 inf = info
309 while inf:
310 if incl_abs_fname == os.path.abspath(inf['file']):
311 raise QAPISemError(info, "Inclusion loop for %s" % include)
312 inf = inf['parent']
313
314 # skip multiple include of the same file
315 if incl_abs_fname in previously_included:
316 return
317 try:
318 fobj = open(incl_abs_fname, 'r')
319 except IOError as e:
320 raise QAPISemError(info, '%s: %s' % (e.strerror, include))
321 exprs_include = QAPISchemaParser(fobj, previously_included, info)
322 self.exprs.extend(exprs_include.exprs)
323 self.docs.extend(exprs_include.docs)
324
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100325 def _pragma(self, name, value, info):
Markus Armbruster2cfbae32017-03-15 13:56:55 +0100326 global doc_required, returns_whitelist, name_case_whitelist
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100327 if name == 'doc-required':
328 if not isinstance(value, bool):
329 raise QAPISemError(info,
330 "Pragma 'doc-required' must be boolean")
331 doc_required = value
Markus Armbruster1554a8f2017-03-15 13:56:54 +0100332 elif name == 'returns-whitelist':
333 if (not isinstance(value, list)
334 or any([not isinstance(elt, str) for elt in value])):
335 raise QAPISemError(info,
336 "Pragma returns-whitelist must be"
337 " a list of strings")
338 returns_whitelist = value
Markus Armbruster2cfbae32017-03-15 13:56:55 +0100339 elif name == 'name-case-whitelist':
340 if (not isinstance(value, list)
341 or any([not isinstance(elt, str) for elt in value])):
342 raise QAPISemError(info,
343 "Pragma name-case-whitelist must be"
344 " a list of strings")
345 name_case_whitelist = value
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100346 else:
347 raise QAPISemError(info, "Unknown pragma '%s'" % name)
348
Marc-André Lureau3313b612017-01-13 15:41:29 +0100349 def accept(self, skip_comment=True):
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200350 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200351 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200352 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200353 self.cursor += 1
354 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500355
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200356 if self.tok == '#':
Marc-André Lureau3313b612017-01-13 15:41:29 +0100357 if self.src[self.cursor] == '#':
358 # Start of doc comment
359 skip_comment = False
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200360 self.cursor = self.src.find('\n', self.cursor)
Marc-André Lureau3313b612017-01-13 15:41:29 +0100361 if not skip_comment:
362 self.val = self.src[self.pos:self.cursor]
363 return
Markus Armbrusteref801a92017-03-15 13:57:08 +0100364 elif self.tok in '{}:,[]':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200365 return
366 elif self.tok == "'":
367 string = ''
368 esc = False
369 while True:
370 ch = self.src[self.cursor]
371 self.cursor += 1
372 if ch == '\n':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100373 raise QAPIParseError(self, 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200374 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600375 if ch == 'b':
376 string += '\b'
377 elif ch == 'f':
378 string += '\f'
379 elif ch == 'n':
380 string += '\n'
381 elif ch == 'r':
382 string += '\r'
383 elif ch == 't':
384 string += '\t'
385 elif ch == 'u':
386 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600387 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600388 ch = self.src[self.cursor]
389 self.cursor += 1
Markus Armbrusteref801a92017-03-15 13:57:08 +0100390 if ch not in '0123456789abcdefABCDEF':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100391 raise QAPIParseError(self,
392 '\\u escape needs 4 '
393 'hex digits')
Eric Blakea7f59662015-05-04 09:05:36 -0600394 value = (value << 4) + int(ch, 16)
395 # If Python 2 and 3 didn't disagree so much on
396 # how to handle Unicode, then we could allow
397 # Unicode string defaults. But most of QAPI is
398 # ASCII-only, so we aren't losing much for now.
399 if not value or value > 0x7f:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100400 raise QAPIParseError(self,
401 'For now, \\u escape '
402 'only supports non-zero '
403 'values up to \\u007f')
Eric Blakea7f59662015-05-04 09:05:36 -0600404 string += chr(value)
Markus Armbrusteref801a92017-03-15 13:57:08 +0100405 elif ch in '\\/\'"':
Eric Blakea7f59662015-05-04 09:05:36 -0600406 string += ch
407 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100408 raise QAPIParseError(self,
409 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200410 esc = False
Markus Armbrusteref801a92017-03-15 13:57:08 +0100411 elif ch == '\\':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200412 esc = True
413 elif ch == "'":
414 self.val = string
415 return
416 else:
417 string += ch
Markus Armbrusteref801a92017-03-15 13:57:08 +0100418 elif self.src.startswith('true', self.pos):
Markus Armbrustere565d932015-06-10 08:24:58 +0200419 self.val = True
420 self.cursor += 3
421 return
Markus Armbrusteref801a92017-03-15 13:57:08 +0100422 elif self.src.startswith('false', self.pos):
Markus Armbrustere565d932015-06-10 08:24:58 +0200423 self.val = False
424 self.cursor += 4
425 return
Markus Armbrusteref801a92017-03-15 13:57:08 +0100426 elif self.src.startswith('null', self.pos):
Markus Armbrustere565d932015-06-10 08:24:58 +0200427 self.val = None
428 self.cursor += 3
429 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200430 elif self.tok == '\n':
431 if self.cursor == len(self.src):
432 self.tok = None
433 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800434 self.line += 1
435 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200436 elif not self.tok.isspace():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100437 raise QAPIParseError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500438
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200439 def get_members(self):
440 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200441 if self.tok == '}':
442 self.accept()
443 return expr
444 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100445 raise QAPIParseError(self, 'Expected string or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200446 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200447 key = self.val
448 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200449 if self.tok != ':':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100450 raise QAPIParseError(self, 'Expected ":"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200451 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800452 if key in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100453 raise QAPIParseError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200454 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200455 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200456 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200457 return expr
458 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100459 raise QAPIParseError(self, 'Expected "," or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200460 self.accept()
461 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100462 raise QAPIParseError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500463
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200464 def get_values(self):
465 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200466 if self.tok == ']':
467 self.accept()
468 return expr
Eric Blake437db252015-09-29 16:21:02 -0600469 if self.tok not in "{['tfn":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100470 raise QAPIParseError(self, 'Expected "{", "[", "]", string, '
471 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200472 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200473 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200474 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200475 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200476 return expr
477 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100478 raise QAPIParseError(self, 'Expected "," or "]"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200479 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500480
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200481 def get_expr(self, nested):
482 if self.tok != '{' and not nested:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100483 raise QAPIParseError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200484 if self.tok == '{':
485 self.accept()
486 expr = self.get_members()
487 elif self.tok == '[':
488 self.accept()
489 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600490 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200491 expr = self.val
492 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200493 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100494 raise QAPIParseError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200495 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200496
Marc-André Lureau3313b612017-01-13 15:41:29 +0100497 def get_doc(self, info):
498 if self.val != '##':
499 raise QAPIParseError(self, "Junk after '##' at start of "
500 "documentation comment")
501
502 doc = QAPIDoc(self, info)
503 self.accept(False)
504 while self.tok == '#':
505 if self.val.startswith('##'):
506 # End of doc comment
507 if self.val != '##':
508 raise QAPIParseError(self, "Junk after '##' at end of "
509 "documentation comment")
510 self.accept()
511 return doc
512 else:
513 doc.append(self.val)
514 self.accept(False)
515
516 raise QAPIParseError(self, "Documentation comment must end with '##'")
517
518
Markus Armbruster00e4b282015-06-10 10:04:36 +0200519#
520# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200521# TODO fold into QAPISchema
522# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200523#
524
Eric Blake437db252015-09-29 16:21:02 -0600525
Eric Blake14f00c62016-03-03 09:16:43 -0700526def find_base_members(base):
Eric Blakeac4338f2016-03-17 16:48:39 -0600527 if isinstance(base, dict):
528 return base
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800529 base_struct_define = find_struct(base)
530 if not base_struct_define:
531 return None
532 return base_struct_define['data']
533
Eric Blake437db252015-09-29 16:21:02 -0600534
Eric Blake811d04f2015-05-04 09:05:10 -0600535# Return the qtype of an alternate branch, or None on error.
536def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600537 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600538 return builtin_types[qapi_type]
539 elif find_struct(qapi_type):
Markus Armbrusteref801a92017-03-15 13:57:08 +0100540 return 'QTYPE_QDICT'
Eric Blake44bd1272015-05-04 09:05:08 -0600541 elif find_enum(qapi_type):
Markus Armbrusteref801a92017-03-15 13:57:08 +0100542 return 'QTYPE_QSTRING'
Eric Blake811d04f2015-05-04 09:05:10 -0600543 elif find_union(qapi_type):
Markus Armbrusteref801a92017-03-15 13:57:08 +0100544 return 'QTYPE_QDICT'
Eric Blake44bd1272015-05-04 09:05:08 -0600545 return None
546
Eric Blake437db252015-09-29 16:21:02 -0600547
Wenchao Xiabceae762014-03-06 17:08:56 -0800548# Return the discriminator enum define if discriminator is specified as an
549# enum type, otherwise return None.
550def discriminator_find_enum_define(expr):
551 base = expr.get('base')
552 discriminator = expr.get('discriminator')
553
554 if not (discriminator and base):
555 return None
556
Eric Blake14f00c62016-03-03 09:16:43 -0700557 base_members = find_base_members(base)
558 if not base_members:
Wenchao Xiabceae762014-03-06 17:08:56 -0800559 return None
560
Eric Blake14f00c62016-03-03 09:16:43 -0700561 discriminator_type = base_members.get(discriminator)
Wenchao Xiabceae762014-03-06 17:08:56 -0800562 if not discriminator_type:
563 return None
564
565 return find_enum(discriminator_type)
566
Eric Blake437db252015-09-29 16:21:02 -0600567
Eric Blake59a92fe2015-11-18 01:52:56 -0700568# Names must be letters, numbers, -, and _. They must start with letter,
569# except for downstream extensions which must start with __RFQDN_.
570# Dots are only valid in the downstream extension prefix.
Markus Armbruster0fe675a2017-03-15 13:57:07 +0100571valid_name = re.compile(r'^(__[a-zA-Z0-9.-]+_)?'
Eric Blake59a92fe2015-11-18 01:52:56 -0700572 '[a-zA-Z][a-zA-Z0-9_-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600573
574
Marc-André Lureau4148c292017-01-13 15:41:25 +0100575def check_name(info, source, name, allow_optional=False,
Eric Blake437db252015-09-29 16:21:02 -0600576 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600577 global valid_name
578 membername = name
579
580 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100581 raise QAPISemError(info, "%s requires a string name" % source)
Eric Blakec9e0a792015-05-04 09:05:22 -0600582 if name.startswith('*'):
583 membername = name[1:]
584 if not allow_optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100585 raise QAPISemError(info, "%s does not allow optional name '%s'"
586 % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600587 # Enum members can start with a digit, because the generated C
588 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700589 if enum_member and membername[0].isdigit():
590 membername = 'D' + membername
Eric Blake75996972016-03-17 16:48:29 -0600591 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
592 # and 'q_obj_*' implicit type names.
Eric Blake9fb081e2015-10-26 16:34:44 -0600593 if not valid_name.match(membername) or \
594 c_name(membername, False).startswith('q_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100595 raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600596
Eric Blake437db252015-09-29 16:21:02 -0600597
598def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200599 global all_names
600 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200601 # FIXME should reject names that differ only in '_' vs. '.'
602 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200603 if name in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100604 raise QAPISemError(info, "%s '%s' is already defined"
605 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600606 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100607 raise QAPISemError(info, "%s '%s' should not end in '%s'"
608 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200609 all_names[name] = meta
610
Eric Blake437db252015-09-29 16:21:02 -0600611
Markus Armbruster00e4b282015-06-10 10:04:36 +0200612def add_struct(definition, info):
613 global struct_types
614 name = definition['struct']
615 add_name(name, info, 'struct')
616 struct_types.append(definition)
617
Eric Blake437db252015-09-29 16:21:02 -0600618
Markus Armbruster00e4b282015-06-10 10:04:36 +0200619def find_struct(name):
620 global struct_types
621 for struct in struct_types:
622 if struct['struct'] == name:
623 return struct
624 return None
625
Eric Blake437db252015-09-29 16:21:02 -0600626
Markus Armbruster00e4b282015-06-10 10:04:36 +0200627def add_union(definition, info):
628 global union_types
629 name = definition['union']
630 add_name(name, info, 'union')
631 union_types.append(definition)
632
Eric Blake437db252015-09-29 16:21:02 -0600633
Markus Armbruster00e4b282015-06-10 10:04:36 +0200634def find_union(name):
635 global union_types
636 for union in union_types:
637 if union['union'] == name:
638 return union
639 return None
640
Eric Blake437db252015-09-29 16:21:02 -0600641
642def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200643 global enum_types
644 add_name(name, info, 'enum', implicit)
Markus Armbrusteref801a92017-03-15 13:57:08 +0100645 enum_types.append({'enum_name': name, 'enum_values': enum_values})
Markus Armbruster00e4b282015-06-10 10:04:36 +0200646
Eric Blake437db252015-09-29 16:21:02 -0600647
Markus Armbruster00e4b282015-06-10 10:04:36 +0200648def find_enum(name):
649 global enum_types
650 for enum in enum_types:
651 if enum['enum_name'] == name:
652 return enum
653 return None
654
Markus Armbruster00e4b282015-06-10 10:04:36 +0200655
Eric Blake437db252015-09-29 16:21:02 -0600656def is_enum(name):
657 return find_enum(name) is not None
658
659
Marc-André Lureau4148c292017-01-13 15:41:25 +0100660def check_type(info, source, value, allow_array=False,
Eric Blake437db252015-09-29 16:21:02 -0600661 allow_dict=False, allow_optional=False,
662 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600663 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600664
665 if value is None:
666 return
667
Eric Blakedd883c62015-05-04 09:05:21 -0600668 # Check if array type for value is okay
669 if isinstance(value, list):
670 if not allow_array:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100671 raise QAPISemError(info, "%s cannot be an array" % source)
Eric Blakedd883c62015-05-04 09:05:21 -0600672 if len(value) != 1 or not isinstance(value[0], str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100673 raise QAPISemError(info,
674 "%s: array type must contain single type name" %
675 source)
Eric Blakedd883c62015-05-04 09:05:21 -0600676 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600677
678 # Check if type name for value is okay
679 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600680 if value not in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100681 raise QAPISemError(info, "%s uses unknown type '%s'"
682 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600683 if not all_names[value] in allow_metas:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100684 raise QAPISemError(info, "%s cannot use %s type '%s'" %
685 (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600686 return
687
Eric Blakedd883c62015-05-04 09:05:21 -0600688 if not allow_dict:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100689 raise QAPISemError(info, "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200690
691 if not isinstance(value, OrderedDict):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100692 raise QAPISemError(info,
693 "%s should be a dictionary or type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200694
695 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600696 for (key, arg) in value.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100697 check_name(info, "Member of %s" % source, key,
Eric Blakec9e0a792015-05-04 09:05:22 -0600698 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600699 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100700 raise QAPISemError(info, "Member of %s uses reserved name '%s'"
701 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600702 # Todo: allow dictionaries to represent default values of
703 # an optional argument.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100704 check_type(info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200705 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600706 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600707 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600708
Eric Blake437db252015-09-29 16:21:02 -0600709
Marc-André Lureau4148c292017-01-13 15:41:25 +0100710def check_command(expr, info):
Eric Blakedd883c62015-05-04 09:05:21 -0600711 name = expr['command']
Eric Blakec8184082016-07-13 21:50:20 -0600712 boxed = expr.get('boxed', False)
Eric Blake2cbf0992015-05-04 09:05:24 -0600713
Eric Blakec8184082016-07-13 21:50:20 -0600714 args_meta = ['struct']
715 if boxed:
716 args_meta += ['union', 'alternate']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100717 check_type(info, "'data' for command '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600718 expr.get('data'), allow_dict=not boxed, allow_optional=True,
719 allow_metas=args_meta)
Eric Blake10d4d992015-05-04 09:05:23 -0600720 returns_meta = ['union', 'struct']
721 if name in returns_whitelist:
722 returns_meta += ['built-in', 'alternate', 'enum']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100723 check_type(info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200724 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200725 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600726
Eric Blake437db252015-09-29 16:21:02 -0600727
Marc-André Lureau4148c292017-01-13 15:41:25 +0100728def check_event(expr, info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600729 global events
730 name = expr['event']
Eric Blakec8184082016-07-13 21:50:20 -0600731 boxed = expr.get('boxed', False)
Eric Blake4dc2e692015-05-04 09:05:17 -0600732
Eric Blakec8184082016-07-13 21:50:20 -0600733 meta = ['struct']
734 if boxed:
735 meta += ['union', 'alternate']
Eric Blake4dc2e692015-05-04 09:05:17 -0600736 events.append(name)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100737 check_type(info, "'data' for event '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600738 expr.get('data'), allow_dict=not boxed, allow_optional=True,
739 allow_metas=meta)
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200740
Eric Blake437db252015-09-29 16:21:02 -0600741
Marc-André Lureau4148c292017-01-13 15:41:25 +0100742def check_union(expr, info):
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800743 name = expr['union']
744 base = expr.get('base')
745 discriminator = expr.get('discriminator')
746 members = expr['data']
747
Eric Blake811d04f2015-05-04 09:05:10 -0600748 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600749
750 # With no discriminator it is a simple union.
751 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600752 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600753 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600754 if base is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100755 raise QAPISemError(info, "Simple union '%s' must not have a base" %
756 name)
Eric Blake44bd1272015-05-04 09:05:08 -0600757
758 # Else, it's a flat union.
759 else:
Eric Blakeac4338f2016-03-17 16:48:39 -0600760 # The object must have a string or dictionary 'base'.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100761 check_type(info, "'base' for union '%s'" % name,
Eric Blakeac4338f2016-03-17 16:48:39 -0600762 base, allow_dict=True, allow_optional=True,
763 allow_metas=['struct'])
Eric Blake376863e2015-09-29 16:21:07 -0600764 if not base:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100765 raise QAPISemError(info, "Flat union '%s' must have a base"
766 % name)
Eric Blake14f00c62016-03-03 09:16:43 -0700767 base_members = find_base_members(base)
Markus Armbruster48153742017-03-15 13:56:58 +0100768 assert base_members is not None
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800769
Eric Blakec9e0a792015-05-04 09:05:22 -0600770 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600771 # member of the base struct.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100772 check_name(info, "Discriminator of flat union '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600773 discriminator)
Eric Blake14f00c62016-03-03 09:16:43 -0700774 discriminator_type = base_members.get(discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800775 if not discriminator_type:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100776 raise QAPISemError(info,
777 "Discriminator '%s' is not a member of base "
778 "struct '%s'"
779 % (discriminator, base))
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800780 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600781 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800782 # Do not allow string discriminator
783 if not enum_define:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100784 raise QAPISemError(info,
785 "Discriminator '%s' must be of enumeration "
786 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800787
Eric Blake02a57ae2016-02-17 23:48:16 -0700788 # Check every branch; don't allow an empty union
789 if len(members) == 0:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100790 raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800791 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100792 check_name(info, "Member of union '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600793
Eric Blake01cfbaa2015-12-01 22:20:58 -0700794 # Each value must name a known type
Marc-André Lureau4148c292017-01-13 15:41:25 +0100795 check_type(info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200796 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600797
Eric Blake44bd1272015-05-04 09:05:08 -0600798 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700799 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600800 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600801 if key not in enum_define['enum_values']:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100802 raise QAPISemError(info,
803 "Discriminator value '%s' is not found in "
804 "enum '%s'"
Markus Armbrusteref801a92017-03-15 13:57:08 +0100805 % (key, enum_define['enum_name']))
Eric Blake44bd1272015-05-04 09:05:08 -0600806
Eric Blaked0b18232016-07-13 21:50:13 -0600807 # If discriminator is user-defined, ensure all values are covered
808 if enum_define:
809 for value in enum_define['enum_values']:
810 if value not in members.keys():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100811 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
812 % (name, value))
Eric Blaked0b18232016-07-13 21:50:13 -0600813
Eric Blake437db252015-09-29 16:21:02 -0600814
Marc-André Lureau4148c292017-01-13 15:41:25 +0100815def check_alternate(expr, info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600816 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600817 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600818 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600819
Eric Blake02a57ae2016-02-17 23:48:16 -0700820 # Check every branch; require at least two branches
821 if len(members) < 2:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100822 raise QAPISemError(info,
823 "Alternate '%s' should have at least two branches "
824 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600825 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100826 check_name(info, "Member of alternate '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600827
Eric Blake811d04f2015-05-04 09:05:10 -0600828 # Ensure alternates have no type conflicts.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100829 check_type(info, "Member '%s' of alternate '%s'" % (key, name),
Eric Blakedd883c62015-05-04 09:05:21 -0600830 value,
831 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600832 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700833 if not qtype:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100834 raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
835 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600836 if qtype in types_seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100837 raise QAPISemError(info, "Alternate '%s' member '%s' can't "
838 "be distinguished from member '%s'"
839 % (name, key, types_seen[qtype]))
Eric Blake811d04f2015-05-04 09:05:10 -0600840 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800841
Eric Blake437db252015-09-29 16:21:02 -0600842
Marc-André Lureau4148c292017-01-13 15:41:25 +0100843def check_enum(expr, info):
Eric Blakecf393592015-05-04 09:05:04 -0600844 name = expr['enum']
845 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100846 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600847
848 if not isinstance(members, list):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100849 raise QAPISemError(info,
850 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100851 if prefix is not None and not isinstance(prefix, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100852 raise QAPISemError(info,
853 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600854 for member in members:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100855 check_name(info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600856 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600857
Eric Blake437db252015-09-29 16:21:02 -0600858
Marc-André Lureau4148c292017-01-13 15:41:25 +0100859def check_struct(expr, info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600860 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600861 members = expr['data']
862
Marc-André Lureau4148c292017-01-13 15:41:25 +0100863 check_type(info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600864 allow_dict=True, allow_optional=True)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100865 check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600866 allow_metas=['struct'])
867
Eric Blake437db252015-09-29 16:21:02 -0600868
Eric Blake0545f6b2015-05-04 09:05:15 -0600869def check_keys(expr_elem, meta, required, optional=[]):
870 expr = expr_elem['expr']
871 info = expr_elem['info']
872 name = expr[meta]
873 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100874 raise QAPISemError(info, "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600875 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600876 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600877 if key not in required and key not in optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100878 raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
879 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600880 if (key == 'gen' or key == 'success-response') and value is not False:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100881 raise QAPISemError(info,
882 "'%s' of %s '%s' should only use false value"
883 % (key, meta, name))
Eric Blakec8184082016-07-13 21:50:20 -0600884 if key == 'boxed' and value is not True:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100885 raise QAPISemError(info,
886 "'%s' of %s '%s' should only use true value"
887 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600888 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600889 if key not in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100890 raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
891 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600892
Eric Blake437db252015-09-29 16:21:02 -0600893
Markus Armbruster4d076d62015-06-10 08:55:21 +0200894def check_exprs(exprs):
895 global all_names
896
Markus Armbruster79470162017-03-15 13:57:21 +0100897 # Populate name table with names of built-in types
Markus Armbruster4d076d62015-06-10 08:55:21 +0200898 for builtin in builtin_types.keys():
899 all_names[builtin] = 'built-in'
Markus Armbruster79470162017-03-15 13:57:21 +0100900
901 # Learn the types and check for valid expression keys
Markus Armbruster4d076d62015-06-10 08:55:21 +0200902 for expr_elem in exprs:
903 expr = expr_elem['expr']
904 info = expr_elem['info']
Markus Armbruster79470162017-03-15 13:57:21 +0100905 doc = expr_elem.get('doc')
Marc-André Lureau3313b612017-01-13 15:41:29 +0100906
Markus Armbruster79470162017-03-15 13:57:21 +0100907 if not doc and doc_required:
Marc-André Lureau3313b612017-01-13 15:41:29 +0100908 raise QAPISemError(info,
909 "Expression missing documentation comment")
910
Eric Blake437db252015-09-29 16:21:02 -0600911 if 'enum' in expr:
Markus Armbruster79470162017-03-15 13:57:21 +0100912 name = expr['enum']
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100913 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster79470162017-03-15 13:57:21 +0100914 add_enum(name, info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600915 elif 'union' in expr:
Markus Armbruster79470162017-03-15 13:57:21 +0100916 name = expr['union']
Markus Armbruster4d076d62015-06-10 08:55:21 +0200917 check_keys(expr_elem, 'union', ['data'],
918 ['base', 'discriminator'])
919 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600920 elif 'alternate' in expr:
Markus Armbruster79470162017-03-15 13:57:21 +0100921 name = expr['alternate']
Markus Armbruster4d076d62015-06-10 08:55:21 +0200922 check_keys(expr_elem, 'alternate', ['data'])
Markus Armbruster79470162017-03-15 13:57:21 +0100923 add_name(name, info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600924 elif 'struct' in expr:
Markus Armbruster79470162017-03-15 13:57:21 +0100925 name = expr['struct']
Markus Armbruster4d076d62015-06-10 08:55:21 +0200926 check_keys(expr_elem, 'struct', ['data'], ['base'])
927 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600928 elif 'command' in expr:
Markus Armbruster79470162017-03-15 13:57:21 +0100929 name = expr['command']
Markus Armbruster4d076d62015-06-10 08:55:21 +0200930 check_keys(expr_elem, 'command', [],
Eric Blakec8184082016-07-13 21:50:20 -0600931 ['data', 'returns', 'gen', 'success-response', 'boxed'])
Markus Armbruster79470162017-03-15 13:57:21 +0100932 add_name(name, info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600933 elif 'event' in expr:
Markus Armbruster79470162017-03-15 13:57:21 +0100934 name = expr['event']
Eric Blakec8184082016-07-13 21:50:20 -0600935 check_keys(expr_elem, 'event', [], ['data', 'boxed'])
Markus Armbruster79470162017-03-15 13:57:21 +0100936 add_name(name, info, 'event')
Markus Armbruster4d076d62015-06-10 08:55:21 +0200937 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100938 raise QAPISemError(expr_elem['info'],
939 "Expression is missing metatype")
Markus Armbruster79470162017-03-15 13:57:21 +0100940 if doc and doc.symbol != name:
941 raise QAPISemError(info, "Definition of '%s' follows documentation"
942 " for '%s'" % (name, doc.symbol))
Markus Armbruster4d076d62015-06-10 08:55:21 +0200943
944 # Try again for hidden UnionKind enum
945 for expr_elem in exprs:
946 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600947 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200948 if not discriminator_find_enum_define(expr):
949 add_enum('%sKind' % expr['union'], expr_elem['info'],
950 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600951 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200952 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
953 implicit=True)
954
955 # Validate that exprs make sense
956 for expr_elem in exprs:
957 expr = expr_elem['expr']
958 info = expr_elem['info']
959
Eric Blake437db252015-09-29 16:21:02 -0600960 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200961 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600962 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200963 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600964 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200965 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600966 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200967 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600968 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200969 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600970 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200971 check_event(expr, info)
972 else:
973 assert False, 'unexpected meta type'
974
Markus Armbrusterac882192015-09-16 13:06:05 +0200975 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600976
Markus Armbrusterac882192015-09-16 13:06:05 +0200977
Marc-André Lureau3313b612017-01-13 15:41:29 +0100978def check_freeform_doc(doc):
Marc-André Lureau3313b612017-01-13 15:41:29 +0100979 body = str(doc.body)
980 if re.search(r'@\S+:', body, re.MULTILINE):
981 raise QAPISemError(doc.info,
982 "Free-form documentation block must not contain"
983 " @NAME: sections")
984
985
986def check_definition_doc(doc, expr, info):
987 for i in ('enum', 'union', 'alternate', 'struct', 'command', 'event'):
988 if i in expr:
989 meta = i
990 break
991
Marc-André Lureau3313b612017-01-13 15:41:29 +0100992 if doc.has_section('Returns') and 'command' not in expr:
993 raise QAPISemError(info, "'Returns:' is only valid for commands")
994
995 if meta == 'union':
996 args = expr.get('base', [])
997 else:
998 args = expr.get('data', [])
999 if isinstance(args, str):
1000 return
1001 if isinstance(args, dict):
1002 args = args.keys()
1003 assert isinstance(args, list)
1004
1005 if (meta == 'alternate'
1006 or (meta == 'union' and not expr.get('discriminator'))):
1007 args.append('type')
1008
Marc-André Lureau3313b612017-01-13 15:41:29 +01001009 doc_args = set(doc.args.keys())
1010 args = set([name.strip('*') for name in args])
1011 if not doc_args.issubset(args):
1012 raise QAPISemError(info, "The following documented members are not in "
Markus Armbrusteref801a92017-03-15 13:57:08 +01001013 "the declaration: %s" % ', '.join(doc_args - args))
Marc-André Lureau3313b612017-01-13 15:41:29 +01001014
1015
1016def check_docs(docs):
1017 for doc in docs:
1018 for section in doc.args.values() + doc.sections:
1019 content = str(section)
1020 if not content or content.isspace():
1021 raise QAPISemError(doc.info,
1022 "Empty doc section '%s'" % section.name)
1023
1024 if not doc.expr:
1025 check_freeform_doc(doc)
1026 else:
1027 check_definition_doc(doc, doc.expr, doc.info)
1028
1029 return docs
1030
1031
Markus Armbrusterac882192015-09-16 13:06:05 +02001032#
1033# Schema compiler frontend
1034#
1035
1036class QAPISchemaEntity(object):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001037 def __init__(self, name, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001038 assert isinstance(name, str)
1039 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -06001040 # For explicitly defined entities, info points to the (explicit)
1041 # definition. For builtins (and their arrays), info is None.
1042 # For implicitly defined entities, info points to a place that
1043 # triggered the implicit definition (there may be more than one
1044 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +02001045 self.info = info
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001046 self.doc = doc
Markus Armbrusterac882192015-09-16 13:06:05 +02001047
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001048 def c_name(self):
1049 return c_name(self.name)
1050
Markus Armbrusterac882192015-09-16 13:06:05 +02001051 def check(self, schema):
1052 pass
1053
Eric Blake49823c42015-10-12 22:22:27 -06001054 def is_implicit(self):
1055 return not self.info
1056
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001057 def visit(self, visitor):
1058 pass
1059
1060
1061class QAPISchemaVisitor(object):
1062 def visit_begin(self, schema):
1063 pass
1064
1065 def visit_end(self):
1066 pass
1067
Eric Blake25a0d9c2015-10-12 22:22:21 -06001068 def visit_needed(self, entity):
1069 # Default to visiting everything
1070 return True
1071
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001072 def visit_builtin_type(self, name, info, json_type):
1073 pass
1074
1075 def visit_enum_type(self, name, info, values, prefix):
1076 pass
1077
1078 def visit_array_type(self, name, info, element_type):
1079 pass
1080
1081 def visit_object_type(self, name, info, base, members, variants):
1082 pass
1083
Markus Armbruster39a18152015-09-16 13:06:28 +02001084 def visit_object_type_flat(self, name, info, members, variants):
1085 pass
1086
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001087 def visit_alternate_type(self, name, info, variants):
1088 pass
1089
1090 def visit_command(self, name, info, arg_type, ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001091 gen, success_response, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001092 pass
1093
Eric Blake48825ca2016-07-13 21:50:19 -06001094 def visit_event(self, name, info, arg_type, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001095 pass
1096
Markus Armbrusterac882192015-09-16 13:06:05 +02001097
1098class QAPISchemaType(QAPISchemaEntity):
Eric Blake4040d992016-03-17 16:48:28 -06001099 # Return the C type for common use.
1100 # For the types we commonly box, this is a pointer type.
1101 def c_type(self):
1102 pass
1103
1104 # Return the C type to be used in a parameter list.
1105 def c_param_type(self):
1106 return self.c_type()
1107
1108 # Return the C type to be used where we suppress boxing.
1109 def c_unboxed_type(self):
1110 return self.c_type()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001111
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001112 def json_type(self):
1113 pass
1114
1115 def alternate_qtype(self):
1116 json2qtype = {
1117 'string': 'QTYPE_QSTRING',
1118 'number': 'QTYPE_QFLOAT',
1119 'int': 'QTYPE_QINT',
1120 'boolean': 'QTYPE_QBOOL',
1121 'object': 'QTYPE_QDICT'
1122 }
1123 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +02001124
Markus Armbruster691e0312017-03-15 13:57:14 +01001125 def doc_type(self):
1126 if self.is_implicit():
1127 return None
1128 return self.name
1129
Markus Armbrusterac882192015-09-16 13:06:05 +02001130
1131class QAPISchemaBuiltinType(QAPISchemaType):
Eric Blake861877a2016-03-17 16:48:36 -06001132 def __init__(self, name, json_type, c_type):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001133 QAPISchemaType.__init__(self, name, None, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001134 assert not c_type or isinstance(c_type, str)
1135 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
1136 'value')
1137 self._json_type_name = json_type
1138 self._c_type_name = c_type
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001139
1140 def c_name(self):
1141 return self.name
1142
Eric Blake4040d992016-03-17 16:48:28 -06001143 def c_type(self):
1144 return self._c_type_name
1145
1146 def c_param_type(self):
1147 if self.name == 'str':
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001148 return 'const ' + self._c_type_name
1149 return self._c_type_name
1150
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001151 def json_type(self):
1152 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +02001153
Markus Armbruster691e0312017-03-15 13:57:14 +01001154 def doc_type(self):
1155 return self.json_type()
1156
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001157 def visit(self, visitor):
1158 visitor.visit_builtin_type(self.name, self.info, self.json_type())
1159
Markus Armbrusterac882192015-09-16 13:06:05 +02001160
1161class QAPISchemaEnumType(QAPISchemaType):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001162 def __init__(self, name, info, doc, values, prefix):
1163 QAPISchemaType.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001164 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -07001165 assert isinstance(v, QAPISchemaMember)
1166 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001167 assert prefix is None or isinstance(prefix, str)
1168 self.values = values
1169 self.prefix = prefix
1170
1171 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -07001172 seen = {}
1173 for v in self.values:
1174 v.check_clash(self.info, seen)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001175 if self.doc:
1176 self.doc.connect_member(v)
Markus Armbrusterac882192015-09-16 13:06:05 +02001177
Eric Blake99df5282015-10-12 22:22:32 -06001178 def is_implicit(self):
Markus Armbruster46362112017-03-15 13:57:02 +01001179 # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
1180 return self.name.endswith('Kind') or self.name == 'QType'
Eric Blake99df5282015-10-12 22:22:32 -06001181
Eric Blake4040d992016-03-17 16:48:28 -06001182 def c_type(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001183 return c_name(self.name)
1184
Eric Blake93bda4d2015-12-01 22:20:55 -07001185 def member_names(self):
1186 return [v.name for v in self.values]
1187
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001188 def json_type(self):
1189 return 'string'
1190
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001191 def visit(self, visitor):
1192 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -07001193 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001194
Markus Armbrusterac882192015-09-16 13:06:05 +02001195
1196class QAPISchemaArrayType(QAPISchemaType):
1197 def __init__(self, name, info, element_type):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001198 QAPISchemaType.__init__(self, name, info, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001199 assert isinstance(element_type, str)
1200 self._element_type_name = element_type
1201 self.element_type = None
1202
1203 def check(self, schema):
1204 self.element_type = schema.lookup_type(self._element_type_name)
1205 assert self.element_type
1206
Eric Blake99df5282015-10-12 22:22:32 -06001207 def is_implicit(self):
1208 return True
1209
Eric Blake4040d992016-03-17 16:48:28 -06001210 def c_type(self):
1211 return c_name(self.name) + pointer_suffix
1212
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001213 def json_type(self):
1214 return 'array'
1215
Markus Armbruster691e0312017-03-15 13:57:14 +01001216 def doc_type(self):
1217 elt_doc_type = self.element_type.doc_type()
1218 if not elt_doc_type:
1219 return None
1220 return 'array of ' + elt_doc_type
1221
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001222 def visit(self, visitor):
1223 visitor.visit_array_type(self.name, self.info, self.element_type)
1224
Markus Armbrusterac882192015-09-16 13:06:05 +02001225
1226class QAPISchemaObjectType(QAPISchemaType):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001227 def __init__(self, name, info, doc, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -07001228 # struct has local_members, optional base, and no variants
1229 # flat union has base, variants, and no local_members
1230 # simple union has local_members, variants, and no base
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001231 QAPISchemaType.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001232 assert base is None or isinstance(base, str)
1233 for m in local_members:
1234 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -07001235 m.set_owner(name)
1236 if variants is not None:
1237 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1238 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001239 self._base_name = base
1240 self.base = None
1241 self.local_members = local_members
1242 self.variants = variants
1243 self.members = None
1244
1245 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -07001246 if self.members is False: # check for cycles
Marc-André Lureau4148c292017-01-13 15:41:25 +01001247 raise QAPISemError(self.info,
1248 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001249 if self.members:
1250 return
1251 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -07001252 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +02001253 if self._base_name:
1254 self.base = schema.lookup_type(self._base_name)
1255 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +02001256 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001257 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001258 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001259 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001260 m.check_clash(self.info, seen)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001261 if self.doc:
1262 self.doc.connect_member(m)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001263 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +02001264 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001265 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001266 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -07001267 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001268
Eric Blake14f00c62016-03-03 09:16:43 -07001269 # Check that the members of this type do not cause duplicate JSON members,
Eric Blake27b60ab2015-11-18 01:52:51 -07001270 # and update seen to track the members seen so far. Report any errors
1271 # on behalf of info, which is not necessarily self.info
1272 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -07001273 assert not self.variants # not implemented
1274 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -07001275 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -07001276
Eric Blake99df5282015-10-12 22:22:32 -06001277 def is_implicit(self):
Eric Blake75996972016-03-17 16:48:29 -06001278 # See QAPISchema._make_implicit_object_type(), as well as
1279 # _def_predefineds()
1280 return self.name.startswith('q_')
Eric Blake99df5282015-10-12 22:22:32 -06001281
Eric Blakeb6167702016-07-13 21:50:16 -06001282 def is_empty(self):
1283 assert self.members is not None
1284 return not self.members and not self.variants
1285
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001286 def c_name(self):
Eric Blakecd50a252016-07-13 21:50:14 -06001287 assert self.name != 'q_empty'
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001288 return QAPISchemaType.c_name(self)
1289
Eric Blake4040d992016-03-17 16:48:28 -06001290 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001291 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -07001292 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001293
Eric Blake4040d992016-03-17 16:48:28 -06001294 def c_unboxed_type(self):
Eric Blake4040d992016-03-17 16:48:28 -06001295 return c_name(self.name)
1296
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001297 def json_type(self):
1298 return 'object'
1299
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001300 def visit(self, visitor):
1301 visitor.visit_object_type(self.name, self.info,
1302 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001303 visitor.visit_object_type_flat(self.name, self.info,
1304 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001305
Markus Armbrusterac882192015-09-16 13:06:05 +02001306
Eric Blaked44f9ac2015-12-01 22:20:54 -07001307class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001308 role = 'member'
1309
Eric Blaked44f9ac2015-12-01 22:20:54 -07001310 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001311 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001312 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001313 self.owner = None
1314
1315 def set_owner(self, name):
1316 assert not self.owner
1317 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001318
Eric Blake27b60ab2015-11-18 01:52:51 -07001319 def check_clash(self, info, seen):
1320 cname = c_name(self.name)
Markus Armbruster2cfbae32017-03-15 13:56:55 +01001321 if cname.lower() != cname and self.owner not in name_case_whitelist:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001322 raise QAPISemError(info,
1323 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001324 if cname in seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001325 raise QAPISemError(info, "%s collides with %s" %
1326 (self.describe(), seen[cname].describe()))
Eric Blake27b60ab2015-11-18 01:52:51 -07001327 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001328
Eric Blake88d4ef82015-11-18 01:52:50 -07001329 def _pretty_owner(self):
1330 owner = self.owner
Eric Blake75996972016-03-17 16:48:29 -06001331 if owner.startswith('q_obj_'):
Eric Blake88d4ef82015-11-18 01:52:50 -07001332 # See QAPISchema._make_implicit_object_type() - reverse the
1333 # mapping there to create a nice human-readable description
Eric Blake75996972016-03-17 16:48:29 -06001334 owner = owner[6:]
Eric Blake88d4ef82015-11-18 01:52:50 -07001335 if owner.endswith('-arg'):
1336 return '(parameter of %s)' % owner[:-4]
Eric Blakeac4338f2016-03-17 16:48:39 -06001337 elif owner.endswith('-base'):
1338 return '(base of %s)' % owner[:-5]
Eric Blake88d4ef82015-11-18 01:52:50 -07001339 else:
1340 assert owner.endswith('-wrapper')
1341 # Unreachable and not implemented
1342 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001343 if owner.endswith('Kind'):
1344 # See QAPISchema._make_implicit_enum_type()
1345 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001346 return '(%s of %s)' % (self.role, owner)
1347
1348 def describe(self):
1349 return "'%s' %s" % (self.name, self._pretty_owner())
1350
Markus Armbrusterac882192015-09-16 13:06:05 +02001351
Eric Blaked44f9ac2015-12-01 22:20:54 -07001352class QAPISchemaObjectTypeMember(QAPISchemaMember):
1353 def __init__(self, name, typ, optional):
1354 QAPISchemaMember.__init__(self, name)
1355 assert isinstance(typ, str)
1356 assert isinstance(optional, bool)
1357 self._type_name = typ
1358 self.type = None
1359 self.optional = optional
1360
1361 def check(self, schema):
1362 assert self.owner
1363 self.type = schema.lookup_type(self._type_name)
1364 assert self.type
1365
1366
Markus Armbrusterac882192015-09-16 13:06:05 +02001367class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001368 def __init__(self, tag_name, tag_member, variants):
1369 # Flat unions pass tag_name but not tag_member.
1370 # Simple unions and alternates pass tag_member but not tag_name.
1371 # After check(), tag_member is always set, and tag_name remains
1372 # a reliable witness of being used by a flat union.
1373 assert bool(tag_member) != bool(tag_name)
1374 assert (isinstance(tag_name, str) or
1375 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001376 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001377 for v in variants:
1378 assert isinstance(v, QAPISchemaObjectTypeVariant)
Eric Blakeda9cb192016-07-13 21:50:15 -06001379 self._tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001380 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001381 self.variants = variants
1382
Eric Blake88d4ef82015-11-18 01:52:50 -07001383 def set_owner(self, name):
1384 for v in self.variants:
1385 v.set_owner(name)
1386
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001387 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001388 if not self.tag_member: # flat union
Eric Blakeda9cb192016-07-13 21:50:15 -06001389 self.tag_member = seen[c_name(self._tag_name)]
1390 assert self._tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001391 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1392 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001393 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001394 # Union names must match enum values; alternate names are
1395 # checked separately. Use 'seen' to tell the two apart.
1396 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001397 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001398 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001399 v.type.check(schema)
1400
Eric Blake27b60ab2015-11-18 01:52:51 -07001401 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001402 for v in self.variants:
1403 # Reset seen map for each variant, since qapi names from one
1404 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001405 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001406 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001407
Eric Blake437db252015-09-29 16:21:02 -06001408
Markus Armbrusterac882192015-09-16 13:06:05 +02001409class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001410 role = 'branch'
1411
Markus Armbrusterac882192015-09-16 13:06:05 +02001412 def __init__(self, name, typ):
1413 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1414
Markus Armbrusterac882192015-09-16 13:06:05 +02001415
1416class QAPISchemaAlternateType(QAPISchemaType):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001417 def __init__(self, name, info, doc, variants):
1418 QAPISchemaType.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001419 assert isinstance(variants, QAPISchemaObjectTypeVariants)
Eric Blakeda9cb192016-07-13 21:50:15 -06001420 assert variants.tag_member
Eric Blake88d4ef82015-11-18 01:52:50 -07001421 variants.set_owner(name)
1422 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001423 self.variants = variants
1424
1425 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001426 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001427 # Not calling self.variants.check_clash(), because there's nothing
1428 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001429 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001430 # Alternate branch names have no relation to the tag enum values;
1431 # so we have to check for potential name collisions ourselves.
1432 seen = {}
1433 for v in self.variants.variants:
1434 v.check_clash(self.info, seen)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001435 if self.doc:
1436 self.doc.connect_member(v)
Markus Armbrusterac882192015-09-16 13:06:05 +02001437
Eric Blake4040d992016-03-17 16:48:28 -06001438 def c_type(self):
1439 return c_name(self.name) + pointer_suffix
1440
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001441 def json_type(self):
1442 return 'value'
1443
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001444 def visit(self, visitor):
1445 visitor.visit_alternate_type(self.name, self.info, self.variants)
1446
Eric Blakec8184082016-07-13 21:50:20 -06001447 def is_empty(self):
1448 return False
1449
Markus Armbrusterac882192015-09-16 13:06:05 +02001450
1451class QAPISchemaCommand(QAPISchemaEntity):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001452 def __init__(self, name, info, doc, arg_type, ret_type,
1453 gen, success_response, boxed):
1454 QAPISchemaEntity.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001455 assert not arg_type or isinstance(arg_type, str)
1456 assert not ret_type or isinstance(ret_type, str)
1457 self._arg_type_name = arg_type
1458 self.arg_type = None
1459 self._ret_type_name = ret_type
1460 self.ret_type = None
1461 self.gen = gen
1462 self.success_response = success_response
Eric Blake48825ca2016-07-13 21:50:19 -06001463 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001464
1465 def check(self, schema):
1466 if self._arg_type_name:
1467 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001468 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1469 isinstance(self.arg_type, QAPISchemaAlternateType))
1470 self.arg_type.check(schema)
1471 if self.boxed:
1472 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001473 raise QAPISemError(self.info,
1474 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001475 else:
1476 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1477 assert not self.arg_type.variants
1478 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001479 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001480 if self._ret_type_name:
1481 self.ret_type = schema.lookup_type(self._ret_type_name)
1482 assert isinstance(self.ret_type, QAPISchemaType)
1483
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001484 def visit(self, visitor):
1485 visitor.visit_command(self.name, self.info,
1486 self.arg_type, self.ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001487 self.gen, self.success_response, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001488
Markus Armbrusterac882192015-09-16 13:06:05 +02001489
1490class QAPISchemaEvent(QAPISchemaEntity):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001491 def __init__(self, name, info, doc, arg_type, boxed):
1492 QAPISchemaEntity.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001493 assert not arg_type or isinstance(arg_type, str)
1494 self._arg_type_name = arg_type
1495 self.arg_type = None
Eric Blake48825ca2016-07-13 21:50:19 -06001496 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001497
1498 def check(self, schema):
1499 if self._arg_type_name:
1500 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001501 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1502 isinstance(self.arg_type, QAPISchemaAlternateType))
1503 self.arg_type.check(schema)
1504 if self.boxed:
1505 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001506 raise QAPISemError(self.info,
1507 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001508 else:
1509 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1510 assert not self.arg_type.variants
1511 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001512 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001513
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001514 def visit(self, visitor):
Eric Blake48825ca2016-07-13 21:50:19 -06001515 visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001516
Markus Armbrusterac882192015-09-16 13:06:05 +02001517
1518class QAPISchema(object):
1519 def __init__(self, fname):
1520 try:
Markus Armbrusteref801a92017-03-15 13:57:08 +01001521 parser = QAPISchemaParser(open(fname, 'r'))
Marc-André Lureau3313b612017-01-13 15:41:29 +01001522 self.exprs = check_exprs(parser.exprs)
1523 self.docs = check_docs(parser.docs)
Eric Blake7618b912015-10-12 22:22:22 -06001524 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001525 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001526 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001527 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001528 self._def_exprs()
1529 self.check()
Marc-André Lureau4148c292017-01-13 15:41:25 +01001530 except QAPIError as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001531 print >>sys.stderr, err
1532 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001533
Markus Armbrusterac882192015-09-16 13:06:05 +02001534 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001535 # Only the predefined types are allowed to not have info
1536 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001537 assert ent.name not in self._entity_dict
1538 self._entity_dict[ent.name] = ent
1539
1540 def lookup_entity(self, name, typ=None):
1541 ent = self._entity_dict.get(name)
1542 if typ and not isinstance(ent, typ):
1543 return None
1544 return ent
1545
1546 def lookup_type(self, name):
1547 return self.lookup_entity(name, QAPISchemaType)
1548
Eric Blake861877a2016-03-17 16:48:36 -06001549 def _def_builtin_type(self, name, json_type, c_type):
1550 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001551 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1552 # qapi-types.h from a single .c, all arrays of builtins must be
1553 # declared in the first file whether or not they are used. Nicer
1554 # would be to use lazy instantiation, while figuring out how to
1555 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001556 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001557
1558 def _def_predefineds(self):
Eric Blake861877a2016-03-17 16:48:36 -06001559 for t in [('str', 'string', 'char' + pointer_suffix),
1560 ('number', 'number', 'double'),
1561 ('int', 'int', 'int64_t'),
1562 ('int8', 'int', 'int8_t'),
1563 ('int16', 'int', 'int16_t'),
1564 ('int32', 'int', 'int32_t'),
1565 ('int64', 'int', 'int64_t'),
1566 ('uint8', 'int', 'uint8_t'),
1567 ('uint16', 'int', 'uint16_t'),
1568 ('uint32', 'int', 'uint32_t'),
1569 ('uint64', 'int', 'uint64_t'),
1570 ('size', 'int', 'uint64_t'),
1571 ('bool', 'boolean', 'bool'),
1572 ('any', 'value', 'QObject' + pointer_suffix)]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001573 self._def_builtin_type(*t)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001574 self.the_empty_object_type = QAPISchemaObjectType(
1575 'q_empty', None, None, None, [], None)
Markus Armbruster39a18152015-09-16 13:06:28 +02001576 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001577 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1578 'qstring', 'qdict', 'qlist',
1579 'qfloat', 'qbool'])
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001580 self._def_entity(QAPISchemaEnumType('QType', None, None,
1581 qtype_values, 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001582
Eric Blake93bda4d2015-12-01 22:20:55 -07001583 def _make_enum_members(self, values):
1584 return [QAPISchemaMember(v) for v in values]
1585
Eric Blake99df5282015-10-12 22:22:32 -06001586 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001587 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001588 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001589 self._def_entity(QAPISchemaEnumType(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001590 name, info, None, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001591 return name
1592
Eric Blake99df5282015-10-12 22:22:32 -06001593 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001594 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001595 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001596 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001597 return name
1598
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001599 def _make_implicit_object_type(self, name, info, doc, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001600 if not members:
1601 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001602 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake75996972016-03-17 16:48:29 -06001603 name = 'q_obj_%s-%s' % (name, role)
Markus Armbrusterac882192015-09-16 13:06:05 +02001604 if not self.lookup_entity(name, QAPISchemaObjectType):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001605 self._def_entity(QAPISchemaObjectType(name, info, doc, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001606 members, None))
1607 return name
1608
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001609 def _def_enum_type(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001610 name = expr['enum']
1611 data = expr['data']
1612 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001613 self._def_entity(QAPISchemaEnumType(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001614 name, info, doc, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001615
Eric Blake99df5282015-10-12 22:22:32 -06001616 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001617 optional = False
1618 if name.startswith('*'):
1619 name = name[1:]
1620 optional = True
1621 if isinstance(typ, list):
1622 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001623 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001624 return QAPISchemaObjectTypeMember(name, typ, optional)
1625
Eric Blake99df5282015-10-12 22:22:32 -06001626 def _make_members(self, data, info):
1627 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001628 for (key, value) in data.iteritems()]
1629
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001630 def _def_struct_type(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001631 name = expr['struct']
1632 base = expr.get('base')
1633 data = expr['data']
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001634 self._def_entity(QAPISchemaObjectType(name, info, doc, base,
Eric Blake99df5282015-10-12 22:22:32 -06001635 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001636 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001637
1638 def _make_variant(self, case, typ):
1639 return QAPISchemaObjectTypeVariant(case, typ)
1640
Eric Blake99df5282015-10-12 22:22:32 -06001641 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001642 if isinstance(typ, list):
1643 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001644 typ = self._make_array_type(typ[0], info)
1645 typ = self._make_implicit_object_type(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001646 typ, info, None, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001647 return QAPISchemaObjectTypeVariant(case, typ)
1648
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001649 def _def_union_type(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001650 name = expr['union']
1651 data = expr['data']
1652 base = expr.get('base')
1653 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001654 tag_member = None
Eric Blakeac4338f2016-03-17 16:48:39 -06001655 if isinstance(base, dict):
1656 base = (self._make_implicit_object_type(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001657 name, info, doc, 'base', self._make_members(base, info)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001658 if tag_name:
1659 variants = [self._make_variant(key, value)
1660 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001661 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001662 else:
Eric Blake99df5282015-10-12 22:22:32 -06001663 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001664 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001665 typ = self._make_implicit_enum_type(name, info,
1666 [v.name for v in variants])
1667 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001668 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001669 self._def_entity(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001670 QAPISchemaObjectType(name, info, doc, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001671 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001672 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001673 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001674
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001675 def _def_alternate_type(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001676 name = expr['alternate']
1677 data = expr['data']
1678 variants = [self._make_variant(key, value)
1679 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001680 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001681 self._def_entity(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001682 QAPISchemaAlternateType(name, info, doc,
Markus Armbrusterac882192015-09-16 13:06:05 +02001683 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001684 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001685 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001686
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001687 def _def_command(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001688 name = expr['command']
1689 data = expr.get('data')
1690 rets = expr.get('returns')
1691 gen = expr.get('gen', True)
1692 success_response = expr.get('success-response', True)
Eric Blake48825ca2016-07-13 21:50:19 -06001693 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001694 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001695 data = self._make_implicit_object_type(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001696 name, info, doc, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001697 if isinstance(rets, list):
1698 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001699 rets = self._make_array_type(rets[0], info)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001700 self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
1701 gen, success_response, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001702
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001703 def _def_event(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001704 name = expr['event']
1705 data = expr.get('data')
Eric Blake48825ca2016-07-13 21:50:19 -06001706 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001707 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001708 data = self._make_implicit_object_type(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001709 name, info, doc, 'arg', self._make_members(data, info))
1710 self._def_entity(QAPISchemaEvent(name, info, doc, data, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001711
1712 def _def_exprs(self):
1713 for expr_elem in self.exprs:
1714 expr = expr_elem['expr']
1715 info = expr_elem['info']
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001716 doc = expr_elem.get('doc')
Markus Armbrusterac882192015-09-16 13:06:05 +02001717 if 'enum' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001718 self._def_enum_type(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001719 elif 'struct' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001720 self._def_struct_type(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001721 elif 'union' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001722 self._def_union_type(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001723 elif 'alternate' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001724 self._def_alternate_type(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001725 elif 'command' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001726 self._def_command(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001727 elif 'event' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001728 self._def_event(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001729 else:
1730 assert False
1731
1732 def check(self):
1733 for ent in self._entity_dict.values():
1734 ent.check(self)
1735
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001736 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001737 visitor.visit_begin(self)
1738 for (name, entity) in sorted(self._entity_dict.items()):
1739 if visitor.visit_needed(entity):
1740 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001741 visitor.visit_end()
1742
Markus Armbruster2caba362013-07-27 17:41:56 +02001743
Markus Armbruster00e4b282015-06-10 10:04:36 +02001744#
1745# Code generation helpers
1746#
1747
Michael Roth0f923be2011-07-19 14:50:39 -05001748def camel_case(name):
1749 new_name = ''
1750 first = True
1751 for ch in name:
1752 if ch in ['_', '-']:
1753 first = True
1754 elif first:
1755 new_name += ch.upper()
1756 first = False
1757 else:
1758 new_name += ch.lower()
1759 return new_name
1760
Eric Blake437db252015-09-29 16:21:02 -06001761
Markus Armbruster849bc532015-05-14 06:50:53 -06001762# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1763# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1764# ENUM24_Name -> ENUM24_NAME
1765def camel_to_upper(value):
1766 c_fun_str = c_name(value, False)
1767 if value.isupper():
1768 return c_fun_str
1769
1770 new_name = ''
1771 l = len(c_fun_str)
1772 for i in range(l):
1773 c = c_fun_str[i]
Markus Armbrusteref801a92017-03-15 13:57:08 +01001774 # When c is upper and no '_' appears before, do more checks
1775 if c.isupper() and (i > 0) and c_fun_str[i - 1] != '_':
Eric Blake437db252015-09-29 16:21:02 -06001776 if i < l - 1 and c_fun_str[i + 1].islower():
1777 new_name += '_'
1778 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001779 new_name += '_'
1780 new_name += c
1781 return new_name.lstrip('_').upper()
1782
Eric Blake437db252015-09-29 16:21:02 -06001783
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001784def c_enum_const(type_name, const_name, prefix=None):
1785 if prefix is not None:
1786 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001787 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001788
Eric Blake18df5152015-05-14 06:50:48 -06001789c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001790
Eric Blake437db252015-09-29 16:21:02 -06001791
Eric Blakec6405b52015-05-14 06:50:55 -06001792# Map @name to a valid C identifier.
1793# If @protect, avoid returning certain ticklish identifiers (like
Markus Armbrusteref801a92017-03-15 13:57:08 +01001794# C keywords) by prepending 'q_'.
Eric Blakec6405b52015-05-14 06:50:55 -06001795#
1796# Used for converting 'name' from a 'name':'type' qapi definition
1797# into a generated struct member, as well as converting type names
1798# into substrings of a generated C function name.
1799# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1800# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001801def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001802 # ANSI X3J11/88-090, 3.1.1
1803 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001804 'default', 'do', 'double', 'else', 'enum', 'extern',
1805 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1806 'return', 'short', 'signed', 'sizeof', 'static',
1807 'struct', 'switch', 'typedef', 'union', 'unsigned',
1808 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001809 # ISO/IEC 9899:1999, 6.4.1
1810 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1811 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001812 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1813 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001814 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1815 # excluding _.*
1816 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001817 # C++ ISO/IEC 14882:2003 2.11
1818 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1819 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1820 'namespace', 'new', 'operator', 'private', 'protected',
1821 'public', 'reinterpret_cast', 'static_cast', 'template',
1822 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1823 'using', 'virtual', 'wchar_t',
1824 # alternative representations
1825 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1826 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001827 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001828 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001829 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001830 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1831 | cpp_words | polluted_words):
Markus Armbrusteref801a92017-03-15 13:57:08 +01001832 return 'q_' + name
Eric Blakec43567c2015-11-18 01:52:52 -07001833 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001834
Amos Kong05dfb262014-06-10 19:25:53 +08001835eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001836pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001837
Eric Blake437db252015-09-29 16:21:02 -06001838
Michael Roth0f923be2011-07-19 14:50:39 -05001839def genindent(count):
Markus Armbrusteref801a92017-03-15 13:57:08 +01001840 ret = ''
Eric Blake437db252015-09-29 16:21:02 -06001841 for _ in range(count):
Markus Armbrusteref801a92017-03-15 13:57:08 +01001842 ret += ' '
Michael Roth0f923be2011-07-19 14:50:39 -05001843 return ret
1844
1845indent_level = 0
1846
Eric Blake437db252015-09-29 16:21:02 -06001847
Michael Roth0f923be2011-07-19 14:50:39 -05001848def push_indent(indent_amount=4):
1849 global indent_level
1850 indent_level += indent_amount
1851
Eric Blake437db252015-09-29 16:21:02 -06001852
Michael Roth0f923be2011-07-19 14:50:39 -05001853def pop_indent(indent_amount=4):
1854 global indent_level
1855 indent_level -= indent_amount
1856
Eric Blake437db252015-09-29 16:21:02 -06001857
Markus Armbruster77e703b2015-06-24 19:27:32 +02001858# Generate @code with @kwds interpolated.
1859# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001860def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001861 raw = code % kwds
1862 if indent_level:
1863 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001864 # re.subn() lacks flags support before Python 2.7, use re.compile()
Markus Armbruster0fe675a2017-03-15 13:57:07 +01001865 raw = re.subn(re.compile(r'^.', re.MULTILINE),
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001866 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001867 raw = raw[0]
Markus Armbruster0fe675a2017-03-15 13:57:07 +01001868 return re.sub(re.escape(eatspace) + r' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001869
Eric Blake437db252015-09-29 16:21:02 -06001870
Michael Roth0f923be2011-07-19 14:50:39 -05001871def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001872 if code[0] == '\n':
1873 code = code[1:]
1874 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001875
Michael Roth0f923be2011-07-19 14:50:39 -05001876
1877def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001878 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001879
Eric Blake437db252015-09-29 16:21:02 -06001880
Michael Rothc0afa9c2013-05-10 17:46:00 -05001881def guardstart(name):
1882 return mcgen('''
1883
1884#ifndef %(name)s
1885#define %(name)s
1886
1887''',
1888 name=guardname(name))
1889
Eric Blake437db252015-09-29 16:21:02 -06001890
Michael Rothc0afa9c2013-05-10 17:46:00 -05001891def guardend(name):
1892 return mcgen('''
1893
1894#endif /* %(name)s */
1895
1896''',
1897 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001898
Eric Blake437db252015-09-29 16:21:02 -06001899
Markus Armbrustere98859a2015-09-16 13:06:16 +02001900def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001901 ret = mcgen('''
1902
Markus Armbrustere98859a2015-09-16 13:06:16 +02001903const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001904''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001905 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001906 for value in values:
1907 index = c_enum_const(name, value, prefix)
1908 ret += mcgen('''
1909 [%(index)s] = "%(value)s",
1910''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001911 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001912
Eric Blake7fb1cf12015-11-18 01:52:57 -07001913 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001914 ret += mcgen('''
1915 [%(max_index)s] = NULL,
1916};
1917''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001918 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001919 return ret
1920
Eric Blake437db252015-09-29 16:21:02 -06001921
Markus Armbrustere98859a2015-09-16 13:06:16 +02001922def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001923 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001924 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001925
1926 ret = mcgen('''
1927
1928typedef enum %(c_name)s {
1929''',
1930 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001931
1932 i = 0
1933 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001934 ret += mcgen('''
1935 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001936''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001937 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001938 i=i)
1939 i += 1
1940
Markus Armbrustere98859a2015-09-16 13:06:16 +02001941 ret += mcgen('''
1942} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001943''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001944 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001945
Markus Armbrustere98859a2015-09-16 13:06:16 +02001946 ret += mcgen('''
1947
1948extern const char *const %(c_name)s_lookup[];
1949''',
1950 c_name=c_name(name))
1951 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001952
Eric Blake437db252015-09-29 16:21:02 -06001953
Eric Blake48825ca2016-07-13 21:50:19 -06001954def gen_params(arg_type, boxed, extra):
Markus Armbruster03b43672015-09-16 13:06:20 +02001955 if not arg_type:
Eric Blakec8184082016-07-13 21:50:20 -06001956 assert not boxed
Markus Armbruster03b43672015-09-16 13:06:20 +02001957 return extra
Markus Armbruster03b43672015-09-16 13:06:20 +02001958 ret = ''
1959 sep = ''
Eric Blake48825ca2016-07-13 21:50:19 -06001960 if boxed:
Eric Blakec8184082016-07-13 21:50:20 -06001961 ret += '%s arg' % arg_type.c_param_type()
1962 sep = ', '
Eric Blake48825ca2016-07-13 21:50:19 -06001963 else:
1964 assert not arg_type.variants
1965 for memb in arg_type.members:
1966 ret += sep
1967 sep = ', '
1968 if memb.optional:
1969 ret += 'bool has_%s, ' % c_name(memb.name)
1970 ret += '%s %s' % (memb.type.c_param_type(),
1971 c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001972 if extra:
1973 ret += sep + extra
1974 return ret
1975
Eric Blake1f353342015-09-29 16:21:13 -06001976
Markus Armbruster00e4b282015-06-10 10:04:36 +02001977#
1978# Common command line parsing
1979#
1980
Eric Blake437db252015-09-29 16:21:02 -06001981
Markus Armbrusteref801a92017-03-15 13:57:08 +01001982def parse_command_line(extra_options='', extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001983
1984 try:
1985 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbrusteref801a92017-03-15 13:57:08 +01001986 'chp:o:' + extra_options,
1987 ['source', 'header', 'prefix=',
1988 'output-dir='] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001989 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001990 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001991 sys.exit(1)
1992
Markus Armbrusteref801a92017-03-15 13:57:08 +01001993 output_dir = ''
1994 prefix = ''
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001995 do_c = False
1996 do_h = False
1997 extra_opts = []
1998
1999 for oa in opts:
2000 o, a = oa
Markus Armbrusteref801a92017-03-15 13:57:08 +01002001 if o in ('-p', '--prefix'):
Markus Armbruster0fe675a2017-03-15 13:57:07 +01002002 match = re.match(r'([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
Markus Armbruster1cf47a12015-07-01 13:13:54 +02002003 if match.end() != len(a):
2004 print >>sys.stderr, \
2005 "%s: 'funny character '%s' in argument of --prefix" \
2006 % (sys.argv[0], a[match.end()])
2007 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02002008 prefix = a
Markus Armbrusteref801a92017-03-15 13:57:08 +01002009 elif o in ('-o', '--output-dir'):
2010 output_dir = a + '/'
2011 elif o in ('-c', '--source'):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02002012 do_c = True
Markus Armbrusteref801a92017-03-15 13:57:08 +01002013 elif o in ('-h', '--header'):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02002014 do_h = True
2015 else:
2016 extra_opts.append(oa)
2017
2018 if not do_c and not do_h:
2019 do_c = True
2020 do_h = True
2021
Markus Armbruster16d80f62015-04-02 13:32:16 +02002022 if len(args) != 1:
2023 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02002024 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02002025 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02002026
Markus Armbruster54414042015-06-09 16:22:45 +02002027 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002028
Markus Armbruster00e4b282015-06-10 10:04:36 +02002029#
2030# Generate output files with boilerplate
2031#
2032
Eric Blake437db252015-09-29 16:21:02 -06002033
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002034def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
2035 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02002036 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002037 c_file = output_dir + prefix + c_file
2038 h_file = output_dir + prefix + h_file
2039
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02002040 if output_dir:
2041 try:
2042 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01002043 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02002044 if e.errno != errno.EEXIST:
2045 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002046
2047 def maybe_open(really, name, opt):
2048 if really:
2049 return open(name, opt)
2050 else:
2051 import StringIO
2052 return StringIO.StringIO()
2053
2054 fdef = maybe_open(do_c, c_file, 'w')
2055 fdecl = maybe_open(do_h, h_file, 'w')
2056
2057 fdef.write(mcgen('''
2058/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2059%(comment)s
2060''',
Eric Blake437db252015-09-29 16:21:02 -06002061 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002062
2063 fdecl.write(mcgen('''
2064/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2065%(comment)s
2066#ifndef %(guard)s
2067#define %(guard)s
2068
2069''',
Eric Blake437db252015-09-29 16:21:02 -06002070 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002071
2072 return (fdef, fdecl)
2073
Eric Blake437db252015-09-29 16:21:02 -06002074
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002075def close_output(fdef, fdecl):
2076 fdecl.write('''
2077#endif
2078''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002079 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002080 fdef.close()