blob: 1f79eb4d1709a7ae4074e5cc9d621cce5edd9b87 [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 = []
Eric Blake4dc2e692015-05-04 09:05:17 -060052all_names = {}
53
Markus Armbruster00e4b282015-06-10 10:04:36 +020054#
55# Parsing the schema into expressions
56#
57
Eric Blake437db252015-09-29 16:21:02 -060058
Lluís Vilanovaa719a272014-05-07 20:46:15 +020059def error_path(parent):
Markus Armbrusteref801a92017-03-15 13:57:08 +010060 res = ''
Lluís Vilanovaa719a272014-05-07 20:46:15 +020061 while parent:
Markus Armbrusteref801a92017-03-15 13:57:08 +010062 res = ('In file included from %s:%d:\n' % (parent['file'],
Lluís Vilanovaa719a272014-05-07 20:46:15 +020063 parent['line'])) + res
64 parent = parent['parent']
65 return res
66
Eric Blake437db252015-09-29 16:21:02 -060067
Marc-André Lureau4148c292017-01-13 15:41:25 +010068class QAPIError(Exception):
69 def __init__(self, fname, line, col, incl_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -060070 Exception.__init__(self)
Marc-André Lureau4148c292017-01-13 15:41:25 +010071 self.fname = fname
72 self.line = line
73 self.col = col
74 self.info = incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +020075 self.msg = msg
Marc-André Lureau4148c292017-01-13 15:41:25 +010076
77 def __str__(self):
Markus Armbrusteref801a92017-03-15 13:57:08 +010078 loc = '%s:%d' % (self.fname, self.line)
Marc-André Lureau4148c292017-01-13 15:41:25 +010079 if self.col is not None:
Markus Armbrusteref801a92017-03-15 13:57:08 +010080 loc += ':%s' % self.col
81 return error_path(self.info) + '%s: %s' % (loc, self.msg)
Marc-André Lureau4148c292017-01-13 15:41:25 +010082
83
84class QAPIParseError(QAPIError):
85 def __init__(self, parser, msg):
86 col = 1
87 for ch in parser.src[parser.line_pos:parser.pos]:
Wenchao Xia515b9432014-03-04 18:44:33 -080088 if ch == '\t':
Marc-André Lureau4148c292017-01-13 15:41:25 +010089 col = (col + 7) % 8 + 1
Markus Armbruster2caba362013-07-27 17:41:56 +020090 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +010091 col += 1
92 QAPIError.__init__(self, parser.fname, parser.line, col,
93 parser.incl_info, msg)
Markus Armbruster2caba362013-07-27 17:41:56 +020094
Eric Blake437db252015-09-29 16:21:02 -060095
Marc-André Lureau4148c292017-01-13 15:41:25 +010096class QAPISemError(QAPIError):
97 def __init__(self, info, msg):
98 QAPIError.__init__(self, info['file'], info['line'], None,
99 info['parent'], msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800100
Eric Blake437db252015-09-29 16:21:02 -0600101
Marc-André Lureau3313b612017-01-13 15:41:29 +0100102class QAPIDoc(object):
103 class Section(object):
104 def __init__(self, name=None):
105 # optional section name (argument/member or section name)
106 self.name = name
107 # the list of lines for this section
108 self.content = []
Markus Armbrusterb116fd82017-03-15 13:57:00 +0100109 self.optional = False
Marc-André Lureau3313b612017-01-13 15:41:29 +0100110
111 def append(self, line):
112 self.content.append(line)
113
114 def __repr__(self):
Markus Armbrusteref801a92017-03-15 13:57:08 +0100115 return '\n'.join(self.content).strip()
Marc-André Lureau3313b612017-01-13 15:41:29 +0100116
117 class ArgSection(Section):
Markus Armbruster069fb5b2017-03-15 13:57:03 +0100118 def __init__(self, name):
119 QAPIDoc.Section.__init__(self, name)
120 self.member = None
121
122 def connect(self, member):
123 self.member = member
Marc-André Lureau3313b612017-01-13 15:41:29 +0100124
125 def __init__(self, parser, info):
126 # self.parser is used to report errors with QAPIParseError. The
127 # resulting error position depends on the state of the parser.
128 # It happens to be the beginning of the comment. More or less
129 # servicable, but action at a distance.
130 self.parser = parser
131 self.info = info
132 self.symbol = None
133 self.body = QAPIDoc.Section()
134 # dict mapping parameter name to ArgSection
135 self.args = OrderedDict()
136 # a list of Section
137 self.sections = []
138 # the current section
139 self.section = self.body
Marc-André Lureau3313b612017-01-13 15:41:29 +0100140
141 def has_section(self, name):
142 """Return True if we have a section with this name."""
143 for i in self.sections:
144 if i.name == name:
145 return True
146 return False
147
148 def append(self, line):
149 """Parse a comment line and add it to the documentation."""
150 line = line[1:]
151 if not line:
152 self._append_freeform(line)
153 return
154
155 if line[0] != ' ':
156 raise QAPIParseError(self.parser, "Missing space after #")
157 line = line[1:]
158
159 # FIXME not nice: things like '# @foo:' and '# @foo: ' aren't
160 # recognized, and get silently treated as ordinary text
161 if self.symbol:
162 self._append_symbol_line(line)
Markus Armbrusteref801a92017-03-15 13:57:08 +0100163 elif not self.body.content and line.startswith('@'):
164 if not line.endswith(':'):
Marc-André Lureau3313b612017-01-13 15:41:29 +0100165 raise QAPIParseError(self.parser, "Line should end with :")
166 self.symbol = line[1:-1]
167 # FIXME invalid names other than the empty string aren't flagged
168 if not self.symbol:
169 raise QAPIParseError(self.parser, "Invalid name")
170 else:
171 self._append_freeform(line)
172
Markus Armbruster4ea71482017-03-15 13:57:23 +0100173 def end_comment(self):
174 self._end_section()
175
Marc-André Lureau3313b612017-01-13 15:41:29 +0100176 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))
Markus Armbruster4ea71482017-03-15 13:57:23 +0100203 self._end_section()
Marc-André Lureau3313b612017-01-13 15:41:29 +0100204 self.section = QAPIDoc.ArgSection(name)
205 self.args[name] = self.section
206
Markus Armbrusteref801a92017-03-15 13:57:08 +0100207 def _start_section(self, name=''):
208 if name in ('Returns', 'Since') and self.has_section(name):
Marc-André Lureau3313b612017-01-13 15:41:29 +0100209 raise QAPIParseError(self.parser,
210 "Duplicated '%s' section" % name)
Markus Armbruster4ea71482017-03-15 13:57:23 +0100211 self._end_section()
Marc-André Lureau3313b612017-01-13 15:41:29 +0100212 self.section = QAPIDoc.Section(name)
213 self.sections.append(self.section)
214
Markus Armbruster4ea71482017-03-15 13:57:23 +0100215 def _end_section(self):
216 if self.section:
217 contents = str(self.section)
218 if self.section.name and (not contents or contents.isspace()):
219 raise QAPIParseError(self.parser, "Empty doc section '%s'"
220 % self.section.name)
221 self.section = None
222
Marc-André Lureau3313b612017-01-13 15:41:29 +0100223 def _append_freeform(self, line):
224 in_arg = isinstance(self.section, QAPIDoc.ArgSection)
225 if (in_arg and self.section.content
226 and not self.section.content[-1]
227 and line and not line[0].isspace()):
228 self._start_section()
229 if (in_arg or not self.section.name
Markus Armbrusteref801a92017-03-15 13:57:08 +0100230 or not self.section.name.startswith('Example')):
Marc-André Lureau3313b612017-01-13 15:41:29 +0100231 line = line.strip()
Markus Armbruster2d433232017-03-15 13:57:22 +0100232 match = re.match(r'(@\S+:)', line)
233 if match:
234 raise QAPIParseError(self.parser,
235 "'%s' not allowed in free-form documentation"
236 % match.group(1))
Markus Armbruster1d8bda12017-03-15 13:57:06 +0100237 # TODO Drop this once the dust has settled
238 if (isinstance(self.section, QAPIDoc.ArgSection)
239 and '#optional' in line):
240 raise QAPISemError(self.info, "Please drop the #optional tag")
Marc-André Lureau3313b612017-01-13 15:41:29 +0100241 self.section.append(line)
242
Markus Armbruster069fb5b2017-03-15 13:57:03 +0100243 def connect_member(self, member):
244 if member.name not in self.args:
245 # Undocumented TODO outlaw
Markus Armbruster860e8772017-03-15 13:57:04 +0100246 self.args[member.name] = QAPIDoc.ArgSection(member.name)
247 self.args[member.name].connect(member)
Markus Armbruster069fb5b2017-03-15 13:57:03 +0100248
Markus Armbrustera9f396b2017-03-15 13:57:27 +0100249 def check_expr(self, expr):
250 if self.has_section('Returns') and 'command' not in expr:
251 raise QAPISemError(self.info,
252 "'Returns:' is only valid for commands")
253
Markus Armbruster816a57c2017-03-15 13:57:26 +0100254 def check(self):
255 bogus = [name for name, section in self.args.iteritems()
256 if not section.member]
257 if bogus:
258 raise QAPISemError(
259 self.info,
260 "The following documented members are not in "
261 "the declaration: %s" % ", ".join(bogus))
262
Marc-André Lureau3313b612017-01-13 15:41:29 +0100263
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200264class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500265
Eric Blake437db252015-09-29 16:21:02 -0600266 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200267 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200268 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200269 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200270 previously_included.append(abs_fname)
271 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200272 self.src = fp.read()
273 if self.src == '' or self.src[-1] != '\n':
274 self.src += '\n'
275 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800276 self.line = 1
277 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200278 self.exprs = []
Marc-André Lureau3313b612017-01-13 15:41:29 +0100279 self.docs = []
Markus Armbrustere7823a22017-03-15 13:57:20 +0100280 self.cur_doc = None
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200281 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500282
Eric Blake437db252015-09-29 16:21:02 -0600283 while self.tok is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100284 info = {'file': fname, 'line': self.line,
285 'parent': self.incl_info}
Marc-André Lureau3313b612017-01-13 15:41:29 +0100286 if self.tok == '#':
Markus Armbrustere7823a22017-03-15 13:57:20 +0100287 self.reject_expr_doc()
288 self.cur_doc = self.get_doc(info)
289 self.docs.append(self.cur_doc)
Marc-André Lureau3313b612017-01-13 15:41:29 +0100290 continue
291
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200292 expr = self.get_expr(False)
Markus Armbrustere04dea82017-03-15 13:56:50 +0100293 if 'include' in expr:
Markus Armbrustere7823a22017-03-15 13:57:20 +0100294 self.reject_expr_doc()
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200295 if len(expr) != 1:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100296 raise QAPISemError(info, "Invalid 'include' directive")
Markus Armbrusteref801a92017-03-15 13:57:08 +0100297 include = expr['include']
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200298 if not isinstance(include, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100299 raise QAPISemError(info,
300 "Value of 'include' must be a string")
Markus Armbrustere04dea82017-03-15 13:56:50 +0100301 self._include(include, info, os.path.dirname(abs_fname),
302 previously_included)
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100303 elif "pragma" in expr:
Markus Armbrustere7823a22017-03-15 13:57:20 +0100304 self.reject_expr_doc()
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100305 if len(expr) != 1:
306 raise QAPISemError(info, "Invalid 'pragma' directive")
307 pragma = expr['pragma']
308 if not isinstance(pragma, dict):
309 raise QAPISemError(
310 info, "Value of 'pragma' must be a dictionary")
311 for name, value in pragma.iteritems():
312 self._pragma(name, value, info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200313 else:
314 expr_elem = {'expr': expr,
Marc-André Lureau4148c292017-01-13 15:41:25 +0100315 'info': info}
Markus Armbrustere7823a22017-03-15 13:57:20 +0100316 if self.cur_doc:
317 if not self.cur_doc.symbol:
318 raise QAPISemError(
319 self.cur_doc.info,
320 "Expression documentation required")
Markus Armbrustere7823a22017-03-15 13:57:20 +0100321 expr_elem['doc'] = self.cur_doc
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200322 self.exprs.append(expr_elem)
Markus Armbrustere7823a22017-03-15 13:57:20 +0100323 self.cur_doc = None
324 self.reject_expr_doc()
325
326 def reject_expr_doc(self):
327 if self.cur_doc and self.cur_doc.symbol:
328 raise QAPISemError(
329 self.cur_doc.info,
330 "Documentation for '%s' is not followed by the definition"
331 % self.cur_doc.symbol)
Michael Roth0f923be2011-07-19 14:50:39 -0500332
Markus Armbrustere04dea82017-03-15 13:56:50 +0100333 def _include(self, include, info, base_dir, previously_included):
334 incl_abs_fname = os.path.join(base_dir, include)
335 # catch inclusion cycle
336 inf = info
337 while inf:
338 if incl_abs_fname == os.path.abspath(inf['file']):
339 raise QAPISemError(info, "Inclusion loop for %s" % include)
340 inf = inf['parent']
341
342 # skip multiple include of the same file
343 if incl_abs_fname in previously_included:
344 return
345 try:
346 fobj = open(incl_abs_fname, 'r')
347 except IOError as e:
348 raise QAPISemError(info, '%s: %s' % (e.strerror, include))
349 exprs_include = QAPISchemaParser(fobj, previously_included, info)
350 self.exprs.extend(exprs_include.exprs)
351 self.docs.extend(exprs_include.docs)
352
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100353 def _pragma(self, name, value, info):
Markus Armbruster2cfbae32017-03-15 13:56:55 +0100354 global doc_required, returns_whitelist, name_case_whitelist
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100355 if name == 'doc-required':
356 if not isinstance(value, bool):
357 raise QAPISemError(info,
358 "Pragma 'doc-required' must be boolean")
359 doc_required = value
Markus Armbruster1554a8f2017-03-15 13:56:54 +0100360 elif name == 'returns-whitelist':
361 if (not isinstance(value, list)
362 or any([not isinstance(elt, str) for elt in value])):
363 raise QAPISemError(info,
364 "Pragma returns-whitelist must be"
365 " a list of strings")
366 returns_whitelist = value
Markus Armbruster2cfbae32017-03-15 13:56:55 +0100367 elif name == 'name-case-whitelist':
368 if (not isinstance(value, list)
369 or any([not isinstance(elt, str) for elt in value])):
370 raise QAPISemError(info,
371 "Pragma name-case-whitelist must be"
372 " a list of strings")
373 name_case_whitelist = value
Markus Armbrusterbc52d032017-03-15 13:56:51 +0100374 else:
375 raise QAPISemError(info, "Unknown pragma '%s'" % name)
376
Marc-André Lureau3313b612017-01-13 15:41:29 +0100377 def accept(self, skip_comment=True):
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200378 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200379 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200380 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200381 self.cursor += 1
382 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500383
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200384 if self.tok == '#':
Marc-André Lureau3313b612017-01-13 15:41:29 +0100385 if self.src[self.cursor] == '#':
386 # Start of doc comment
387 skip_comment = False
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200388 self.cursor = self.src.find('\n', self.cursor)
Marc-André Lureau3313b612017-01-13 15:41:29 +0100389 if not skip_comment:
390 self.val = self.src[self.pos:self.cursor]
391 return
Markus Armbrusteref801a92017-03-15 13:57:08 +0100392 elif self.tok in '{}:,[]':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200393 return
394 elif self.tok == "'":
395 string = ''
396 esc = False
397 while True:
398 ch = self.src[self.cursor]
399 self.cursor += 1
400 if ch == '\n':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100401 raise QAPIParseError(self, 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200402 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600403 if ch == 'b':
404 string += '\b'
405 elif ch == 'f':
406 string += '\f'
407 elif ch == 'n':
408 string += '\n'
409 elif ch == 'r':
410 string += '\r'
411 elif ch == 't':
412 string += '\t'
413 elif ch == 'u':
414 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600415 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600416 ch = self.src[self.cursor]
417 self.cursor += 1
Markus Armbrusteref801a92017-03-15 13:57:08 +0100418 if ch not in '0123456789abcdefABCDEF':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100419 raise QAPIParseError(self,
420 '\\u escape needs 4 '
421 'hex digits')
Eric Blakea7f59662015-05-04 09:05:36 -0600422 value = (value << 4) + int(ch, 16)
423 # If Python 2 and 3 didn't disagree so much on
424 # how to handle Unicode, then we could allow
425 # Unicode string defaults. But most of QAPI is
426 # ASCII-only, so we aren't losing much for now.
427 if not value or value > 0x7f:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100428 raise QAPIParseError(self,
429 'For now, \\u escape '
430 'only supports non-zero '
431 'values up to \\u007f')
Eric Blakea7f59662015-05-04 09:05:36 -0600432 string += chr(value)
Markus Armbrusteref801a92017-03-15 13:57:08 +0100433 elif ch in '\\/\'"':
Eric Blakea7f59662015-05-04 09:05:36 -0600434 string += ch
435 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100436 raise QAPIParseError(self,
437 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200438 esc = False
Markus Armbrusteref801a92017-03-15 13:57:08 +0100439 elif ch == '\\':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200440 esc = True
441 elif ch == "'":
442 self.val = string
443 return
444 else:
445 string += ch
Markus Armbrusteref801a92017-03-15 13:57:08 +0100446 elif self.src.startswith('true', self.pos):
Markus Armbrustere565d932015-06-10 08:24:58 +0200447 self.val = True
448 self.cursor += 3
449 return
Markus Armbrusteref801a92017-03-15 13:57:08 +0100450 elif self.src.startswith('false', self.pos):
Markus Armbrustere565d932015-06-10 08:24:58 +0200451 self.val = False
452 self.cursor += 4
453 return
Markus Armbrusteref801a92017-03-15 13:57:08 +0100454 elif self.src.startswith('null', self.pos):
Markus Armbrustere565d932015-06-10 08:24:58 +0200455 self.val = None
456 self.cursor += 3
457 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200458 elif self.tok == '\n':
459 if self.cursor == len(self.src):
460 self.tok = None
461 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800462 self.line += 1
463 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200464 elif not self.tok.isspace():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100465 raise QAPIParseError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500466
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200467 def get_members(self):
468 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200469 if self.tok == '}':
470 self.accept()
471 return expr
472 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100473 raise QAPIParseError(self, 'Expected string or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200474 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200475 key = self.val
476 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200477 if self.tok != ':':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100478 raise QAPIParseError(self, 'Expected ":"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200479 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800480 if key in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100481 raise QAPIParseError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200482 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200483 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200484 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200485 return expr
486 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100487 raise QAPIParseError(self, 'Expected "," or "}"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200488 self.accept()
489 if self.tok != "'":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100490 raise QAPIParseError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500491
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200492 def get_values(self):
493 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200494 if self.tok == ']':
495 self.accept()
496 return expr
Eric Blake437db252015-09-29 16:21:02 -0600497 if self.tok not in "{['tfn":
Marc-André Lureau4148c292017-01-13 15:41:25 +0100498 raise QAPIParseError(self, 'Expected "{", "[", "]", string, '
499 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200500 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200501 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200502 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200503 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200504 return expr
505 if self.tok != ',':
Marc-André Lureau4148c292017-01-13 15:41:25 +0100506 raise QAPIParseError(self, 'Expected "," or "]"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200507 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500508
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200509 def get_expr(self, nested):
510 if self.tok != '{' and not nested:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100511 raise QAPIParseError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200512 if self.tok == '{':
513 self.accept()
514 expr = self.get_members()
515 elif self.tok == '[':
516 self.accept()
517 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600518 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200519 expr = self.val
520 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200521 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100522 raise QAPIParseError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200523 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200524
Marc-André Lureau3313b612017-01-13 15:41:29 +0100525 def get_doc(self, info):
526 if self.val != '##':
527 raise QAPIParseError(self, "Junk after '##' at start of "
528 "documentation comment")
529
530 doc = QAPIDoc(self, info)
531 self.accept(False)
532 while self.tok == '#':
533 if self.val.startswith('##'):
534 # End of doc comment
535 if self.val != '##':
536 raise QAPIParseError(self, "Junk after '##' at end of "
537 "documentation comment")
Markus Armbruster4ea71482017-03-15 13:57:23 +0100538 doc.end_comment()
Marc-André Lureau3313b612017-01-13 15:41:29 +0100539 self.accept()
540 return doc
541 else:
542 doc.append(self.val)
543 self.accept(False)
544
545 raise QAPIParseError(self, "Documentation comment must end with '##'")
546
547
Markus Armbruster00e4b282015-06-10 10:04:36 +0200548#
549# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200550# TODO fold into QAPISchema
551# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200552#
553
Eric Blake437db252015-09-29 16:21:02 -0600554
Eric Blake14f00c62016-03-03 09:16:43 -0700555def find_base_members(base):
Eric Blakeac4338f2016-03-17 16:48:39 -0600556 if isinstance(base, dict):
557 return base
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800558 base_struct_define = find_struct(base)
559 if not base_struct_define:
560 return None
561 return base_struct_define['data']
562
Eric Blake437db252015-09-29 16:21:02 -0600563
Eric Blake811d04f2015-05-04 09:05:10 -0600564# Return the qtype of an alternate branch, or None on error.
565def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600566 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600567 return builtin_types[qapi_type]
568 elif find_struct(qapi_type):
Markus Armbrusteref801a92017-03-15 13:57:08 +0100569 return 'QTYPE_QDICT'
Eric Blake44bd1272015-05-04 09:05:08 -0600570 elif find_enum(qapi_type):
Markus Armbrusteref801a92017-03-15 13:57:08 +0100571 return 'QTYPE_QSTRING'
Eric Blake811d04f2015-05-04 09:05:10 -0600572 elif find_union(qapi_type):
Markus Armbrusteref801a92017-03-15 13:57:08 +0100573 return 'QTYPE_QDICT'
Eric Blake44bd1272015-05-04 09:05:08 -0600574 return None
575
Eric Blake437db252015-09-29 16:21:02 -0600576
Wenchao Xiabceae762014-03-06 17:08:56 -0800577# Return the discriminator enum define if discriminator is specified as an
578# enum type, otherwise return None.
579def discriminator_find_enum_define(expr):
580 base = expr.get('base')
581 discriminator = expr.get('discriminator')
582
583 if not (discriminator and base):
584 return None
585
Eric Blake14f00c62016-03-03 09:16:43 -0700586 base_members = find_base_members(base)
587 if not base_members:
Wenchao Xiabceae762014-03-06 17:08:56 -0800588 return None
589
Eric Blake14f00c62016-03-03 09:16:43 -0700590 discriminator_type = base_members.get(discriminator)
Wenchao Xiabceae762014-03-06 17:08:56 -0800591 if not discriminator_type:
592 return None
593
594 return find_enum(discriminator_type)
595
Eric Blake437db252015-09-29 16:21:02 -0600596
Eric Blake59a92fe2015-11-18 01:52:56 -0700597# Names must be letters, numbers, -, and _. They must start with letter,
598# except for downstream extensions which must start with __RFQDN_.
599# Dots are only valid in the downstream extension prefix.
Markus Armbruster0fe675a2017-03-15 13:57:07 +0100600valid_name = re.compile(r'^(__[a-zA-Z0-9.-]+_)?'
Eric Blake59a92fe2015-11-18 01:52:56 -0700601 '[a-zA-Z][a-zA-Z0-9_-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600602
603
Marc-André Lureau4148c292017-01-13 15:41:25 +0100604def check_name(info, source, name, allow_optional=False,
Eric Blake437db252015-09-29 16:21:02 -0600605 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600606 global valid_name
607 membername = name
608
609 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100610 raise QAPISemError(info, "%s requires a string name" % source)
Eric Blakec9e0a792015-05-04 09:05:22 -0600611 if name.startswith('*'):
612 membername = name[1:]
613 if not allow_optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100614 raise QAPISemError(info, "%s does not allow optional name '%s'"
615 % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600616 # Enum members can start with a digit, because the generated C
617 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700618 if enum_member and membername[0].isdigit():
619 membername = 'D' + membername
Eric Blake75996972016-03-17 16:48:29 -0600620 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
621 # and 'q_obj_*' implicit type names.
Eric Blake9fb081e2015-10-26 16:34:44 -0600622 if not valid_name.match(membername) or \
623 c_name(membername, False).startswith('q_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100624 raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
Eric Blakec9e0a792015-05-04 09:05:22 -0600625
Eric Blake437db252015-09-29 16:21:02 -0600626
627def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200628 global all_names
629 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200630 # FIXME should reject names that differ only in '_' vs. '.'
631 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200632 if name in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100633 raise QAPISemError(info, "%s '%s' is already defined"
634 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600635 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100636 raise QAPISemError(info, "%s '%s' should not end in '%s'"
637 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200638 all_names[name] = meta
639
Eric Blake437db252015-09-29 16:21:02 -0600640
Markus Armbruster00e4b282015-06-10 10:04:36 +0200641def add_struct(definition, info):
642 global struct_types
Markus Armbruster00e4b282015-06-10 10:04:36 +0200643 struct_types.append(definition)
644
Eric Blake437db252015-09-29 16:21:02 -0600645
Markus Armbruster00e4b282015-06-10 10:04:36 +0200646def find_struct(name):
647 global struct_types
648 for struct in struct_types:
649 if struct['struct'] == name:
650 return struct
651 return None
652
Eric Blake437db252015-09-29 16:21:02 -0600653
Markus Armbruster00e4b282015-06-10 10:04:36 +0200654def add_union(definition, info):
655 global union_types
Markus Armbruster00e4b282015-06-10 10:04:36 +0200656 union_types.append(definition)
657
Eric Blake437db252015-09-29 16:21:02 -0600658
Markus Armbruster00e4b282015-06-10 10:04:36 +0200659def find_union(name):
660 global union_types
661 for union in union_types:
662 if union['union'] == name:
663 return union
664 return None
665
Eric Blake437db252015-09-29 16:21:02 -0600666
Markus Armbrustereda43c62017-03-15 13:57:29 +0100667def add_enum(definition, info):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200668 global enum_types
Markus Armbrustereda43c62017-03-15 13:57:29 +0100669 enum_types.append(definition)
Markus Armbruster00e4b282015-06-10 10:04:36 +0200670
Eric Blake437db252015-09-29 16:21:02 -0600671
Markus Armbruster00e4b282015-06-10 10:04:36 +0200672def find_enum(name):
673 global enum_types
674 for enum in enum_types:
Markus Armbrustereda43c62017-03-15 13:57:29 +0100675 if enum['enum'] == name:
Markus Armbruster00e4b282015-06-10 10:04:36 +0200676 return enum
677 return None
678
Markus Armbruster00e4b282015-06-10 10:04:36 +0200679
Eric Blake437db252015-09-29 16:21:02 -0600680def is_enum(name):
681 return find_enum(name) is not None
682
683
Marc-André Lureau4148c292017-01-13 15:41:25 +0100684def check_type(info, source, value, allow_array=False,
Eric Blake437db252015-09-29 16:21:02 -0600685 allow_dict=False, allow_optional=False,
686 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600687 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600688
689 if value is None:
690 return
691
Eric Blakedd883c62015-05-04 09:05:21 -0600692 # Check if array type for value is okay
693 if isinstance(value, list):
694 if not allow_array:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100695 raise QAPISemError(info, "%s cannot be an array" % source)
Eric Blakedd883c62015-05-04 09:05:21 -0600696 if len(value) != 1 or not isinstance(value[0], str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100697 raise QAPISemError(info,
698 "%s: array type must contain single type name" %
699 source)
Eric Blakedd883c62015-05-04 09:05:21 -0600700 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600701
702 # Check if type name for value is okay
703 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600704 if value not in all_names:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100705 raise QAPISemError(info, "%s uses unknown type '%s'"
706 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600707 if not all_names[value] in allow_metas:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100708 raise QAPISemError(info, "%s cannot use %s type '%s'" %
709 (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600710 return
711
Eric Blakedd883c62015-05-04 09:05:21 -0600712 if not allow_dict:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100713 raise QAPISemError(info, "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200714
715 if not isinstance(value, OrderedDict):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100716 raise QAPISemError(info,
717 "%s should be a dictionary or type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200718
719 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600720 for (key, arg) in value.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100721 check_name(info, "Member of %s" % source, key,
Eric Blakec9e0a792015-05-04 09:05:22 -0600722 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600723 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100724 raise QAPISemError(info, "Member of %s uses reserved name '%s'"
725 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600726 # Todo: allow dictionaries to represent default values of
727 # an optional argument.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100728 check_type(info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200729 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600730 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600731 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600732
Eric Blake437db252015-09-29 16:21:02 -0600733
Marc-André Lureau4148c292017-01-13 15:41:25 +0100734def check_command(expr, info):
Eric Blakedd883c62015-05-04 09:05:21 -0600735 name = expr['command']
Eric Blakec8184082016-07-13 21:50:20 -0600736 boxed = expr.get('boxed', False)
Eric Blake2cbf0992015-05-04 09:05:24 -0600737
Eric Blakec8184082016-07-13 21:50:20 -0600738 args_meta = ['struct']
739 if boxed:
740 args_meta += ['union', 'alternate']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100741 check_type(info, "'data' for command '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600742 expr.get('data'), allow_dict=not boxed, allow_optional=True,
743 allow_metas=args_meta)
Eric Blake10d4d992015-05-04 09:05:23 -0600744 returns_meta = ['union', 'struct']
745 if name in returns_whitelist:
746 returns_meta += ['built-in', 'alternate', 'enum']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100747 check_type(info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200748 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200749 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600750
Eric Blake437db252015-09-29 16:21:02 -0600751
Marc-André Lureau4148c292017-01-13 15:41:25 +0100752def check_event(expr, info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600753 name = expr['event']
Eric Blakec8184082016-07-13 21:50:20 -0600754 boxed = expr.get('boxed', False)
Eric Blake4dc2e692015-05-04 09:05:17 -0600755
Eric Blakec8184082016-07-13 21:50:20 -0600756 meta = ['struct']
757 if boxed:
758 meta += ['union', 'alternate']
Marc-André Lureau4148c292017-01-13 15:41:25 +0100759 check_type(info, "'data' for event '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600760 expr.get('data'), allow_dict=not boxed, allow_optional=True,
761 allow_metas=meta)
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200762
Eric Blake437db252015-09-29 16:21:02 -0600763
Marc-André Lureau4148c292017-01-13 15:41:25 +0100764def check_union(expr, info):
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800765 name = expr['union']
766 base = expr.get('base')
767 discriminator = expr.get('discriminator')
768 members = expr['data']
769
Eric Blake811d04f2015-05-04 09:05:10 -0600770 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600771
772 # With no discriminator it is a simple union.
773 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600774 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600775 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600776 if base is not None:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100777 raise QAPISemError(info, "Simple union '%s' must not have a base" %
778 name)
Eric Blake44bd1272015-05-04 09:05:08 -0600779
780 # Else, it's a flat union.
781 else:
Eric Blakeac4338f2016-03-17 16:48:39 -0600782 # The object must have a string or dictionary 'base'.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100783 check_type(info, "'base' for union '%s'" % name,
Eric Blakeac4338f2016-03-17 16:48:39 -0600784 base, allow_dict=True, allow_optional=True,
785 allow_metas=['struct'])
Eric Blake376863e2015-09-29 16:21:07 -0600786 if not base:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100787 raise QAPISemError(info, "Flat union '%s' must have a base"
788 % name)
Eric Blake14f00c62016-03-03 09:16:43 -0700789 base_members = find_base_members(base)
Markus Armbruster48153742017-03-15 13:56:58 +0100790 assert base_members is not None
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800791
Eric Blakec9e0a792015-05-04 09:05:22 -0600792 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600793 # member of the base struct.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100794 check_name(info, "Discriminator of flat union '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600795 discriminator)
Eric Blake14f00c62016-03-03 09:16:43 -0700796 discriminator_type = base_members.get(discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800797 if not discriminator_type:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100798 raise QAPISemError(info,
799 "Discriminator '%s' is not a member of base "
800 "struct '%s'"
801 % (discriminator, base))
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800802 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600803 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800804 # Do not allow string discriminator
805 if not enum_define:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100806 raise QAPISemError(info,
807 "Discriminator '%s' must be of enumeration "
808 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800809
Eric Blake02a57ae2016-02-17 23:48:16 -0700810 # Check every branch; don't allow an empty union
811 if len(members) == 0:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100812 raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800813 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100814 check_name(info, "Member of union '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600815
Eric Blake01cfbaa2015-12-01 22:20:58 -0700816 # Each value must name a known type
Marc-André Lureau4148c292017-01-13 15:41:25 +0100817 check_type(info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200818 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600819
Eric Blake44bd1272015-05-04 09:05:08 -0600820 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700821 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600822 if enum_define:
Markus Armbrustereda43c62017-03-15 13:57:29 +0100823 if key not in enum_define['data']:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100824 raise QAPISemError(info,
825 "Discriminator value '%s' is not found in "
826 "enum '%s'"
Markus Armbrustereda43c62017-03-15 13:57:29 +0100827 % (key, enum_define['enum']))
Eric Blake44bd1272015-05-04 09:05:08 -0600828
Eric Blaked0b18232016-07-13 21:50:13 -0600829 # If discriminator is user-defined, ensure all values are covered
830 if enum_define:
Markus Armbrustereda43c62017-03-15 13:57:29 +0100831 for value in enum_define['data']:
Eric Blaked0b18232016-07-13 21:50:13 -0600832 if value not in members.keys():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100833 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
834 % (name, value))
Eric Blaked0b18232016-07-13 21:50:13 -0600835
Eric Blake437db252015-09-29 16:21:02 -0600836
Marc-André Lureau4148c292017-01-13 15:41:25 +0100837def check_alternate(expr, info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600838 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600839 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600840 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600841
Eric Blake02a57ae2016-02-17 23:48:16 -0700842 # Check every branch; require at least two branches
843 if len(members) < 2:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100844 raise QAPISemError(info,
845 "Alternate '%s' should have at least two branches "
846 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600847 for (key, value) in members.items():
Marc-André Lureau4148c292017-01-13 15:41:25 +0100848 check_name(info, "Member of alternate '%s'" % name, key)
Eric Blakec9e0a792015-05-04 09:05:22 -0600849
Eric Blake811d04f2015-05-04 09:05:10 -0600850 # Ensure alternates have no type conflicts.
Marc-André Lureau4148c292017-01-13 15:41:25 +0100851 check_type(info, "Member '%s' of alternate '%s'" % (key, name),
Eric Blakedd883c62015-05-04 09:05:21 -0600852 value,
853 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600854 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700855 if not qtype:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100856 raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
857 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600858 if qtype in types_seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100859 raise QAPISemError(info, "Alternate '%s' member '%s' can't "
860 "be distinguished from member '%s'"
861 % (name, key, types_seen[qtype]))
Eric Blake811d04f2015-05-04 09:05:10 -0600862 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800863
Eric Blake437db252015-09-29 16:21:02 -0600864
Marc-André Lureau4148c292017-01-13 15:41:25 +0100865def check_enum(expr, info):
Eric Blakecf393592015-05-04 09:05:04 -0600866 name = expr['enum']
867 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100868 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600869
870 if not isinstance(members, list):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100871 raise QAPISemError(info,
872 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100873 if prefix is not None and not isinstance(prefix, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100874 raise QAPISemError(info,
875 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600876 for member in members:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100877 check_name(info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600878 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600879
Eric Blake437db252015-09-29 16:21:02 -0600880
Marc-André Lureau4148c292017-01-13 15:41:25 +0100881def check_struct(expr, info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600882 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600883 members = expr['data']
884
Marc-André Lureau4148c292017-01-13 15:41:25 +0100885 check_type(info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600886 allow_dict=True, allow_optional=True)
Marc-André Lureau4148c292017-01-13 15:41:25 +0100887 check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600888 allow_metas=['struct'])
889
Eric Blake437db252015-09-29 16:21:02 -0600890
Eric Blake0545f6b2015-05-04 09:05:15 -0600891def check_keys(expr_elem, meta, required, optional=[]):
892 expr = expr_elem['expr']
893 info = expr_elem['info']
894 name = expr[meta]
895 if not isinstance(name, str):
Marc-André Lureau4148c292017-01-13 15:41:25 +0100896 raise QAPISemError(info, "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600897 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600898 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600899 if key not in required and key not in optional:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100900 raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
901 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600902 if (key == 'gen' or key == 'success-response') and value is not False:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100903 raise QAPISemError(info,
904 "'%s' of %s '%s' should only use false value"
905 % (key, meta, name))
Eric Blakec8184082016-07-13 21:50:20 -0600906 if key == 'boxed' and value is not True:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100907 raise QAPISemError(info,
908 "'%s' of %s '%s' should only use true value"
909 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600910 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600911 if key not in expr:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100912 raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
913 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600914
Eric Blake437db252015-09-29 16:21:02 -0600915
Markus Armbruster4d076d62015-06-10 08:55:21 +0200916def check_exprs(exprs):
917 global all_names
918
Markus Armbruster79470162017-03-15 13:57:21 +0100919 # Populate name table with names of built-in types
Markus Armbruster4d076d62015-06-10 08:55:21 +0200920 for builtin in builtin_types.keys():
921 all_names[builtin] = 'built-in'
Markus Armbruster79470162017-03-15 13:57:21 +0100922
923 # Learn the types and check for valid expression keys
Markus Armbruster4d076d62015-06-10 08:55:21 +0200924 for expr_elem in exprs:
925 expr = expr_elem['expr']
926 info = expr_elem['info']
Markus Armbruster79470162017-03-15 13:57:21 +0100927 doc = expr_elem.get('doc')
Marc-André Lureau3313b612017-01-13 15:41:29 +0100928
Markus Armbruster79470162017-03-15 13:57:21 +0100929 if not doc and doc_required:
Marc-André Lureau3313b612017-01-13 15:41:29 +0100930 raise QAPISemError(info,
931 "Expression missing documentation comment")
932
Eric Blake437db252015-09-29 16:21:02 -0600933 if 'enum' in expr:
Markus Armbruster6f053452017-03-15 13:57:30 +0100934 meta = 'enum'
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100935 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbrustereda43c62017-03-15 13:57:29 +0100936 add_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600937 elif 'union' in expr:
Markus Armbruster6f053452017-03-15 13:57:30 +0100938 meta = 'union'
Markus Armbruster4d076d62015-06-10 08:55:21 +0200939 check_keys(expr_elem, 'union', ['data'],
940 ['base', 'discriminator'])
941 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600942 elif 'alternate' in expr:
Markus Armbruster6f053452017-03-15 13:57:30 +0100943 meta = 'alternate'
Markus Armbruster4d076d62015-06-10 08:55:21 +0200944 check_keys(expr_elem, 'alternate', ['data'])
Eric Blake437db252015-09-29 16:21:02 -0600945 elif 'struct' in expr:
Markus Armbruster6f053452017-03-15 13:57:30 +0100946 meta = 'struct'
Markus Armbruster4d076d62015-06-10 08:55:21 +0200947 check_keys(expr_elem, 'struct', ['data'], ['base'])
948 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600949 elif 'command' in expr:
Markus Armbruster6f053452017-03-15 13:57:30 +0100950 meta = 'command'
Markus Armbruster4d076d62015-06-10 08:55:21 +0200951 check_keys(expr_elem, 'command', [],
Eric Blakec8184082016-07-13 21:50:20 -0600952 ['data', 'returns', 'gen', 'success-response', 'boxed'])
Eric Blake437db252015-09-29 16:21:02 -0600953 elif 'event' in expr:
Markus Armbruster6f053452017-03-15 13:57:30 +0100954 meta = 'event'
Eric Blakec8184082016-07-13 21:50:20 -0600955 check_keys(expr_elem, 'event', [], ['data', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200956 else:
Marc-André Lureau4148c292017-01-13 15:41:25 +0100957 raise QAPISemError(expr_elem['info'],
958 "Expression is missing metatype")
Markus Armbruster6f053452017-03-15 13:57:30 +0100959 name = expr[meta]
960 add_name(name, info, meta)
Markus Armbruster79470162017-03-15 13:57:21 +0100961 if doc and doc.symbol != name:
962 raise QAPISemError(info, "Definition of '%s' follows documentation"
963 " for '%s'" % (name, doc.symbol))
Markus Armbruster4d076d62015-06-10 08:55:21 +0200964
965 # Try again for hidden UnionKind enum
966 for expr_elem in exprs:
967 expr = expr_elem['expr']
Markus Armbrustereda43c62017-03-15 13:57:29 +0100968 if 'union' in expr and not discriminator_find_enum_define(expr):
969 name = '%sKind' % expr['union']
Eric Blake437db252015-09-29 16:21:02 -0600970 elif 'alternate' in expr:
Markus Armbrustereda43c62017-03-15 13:57:29 +0100971 name = '%sKind' % expr['alternate']
972 else:
973 continue
974 add_enum({ 'enum': name }, expr_elem['info'])
Markus Armbruster6f053452017-03-15 13:57:30 +0100975 add_name(name, info, 'enum', implicit=True)
Markus Armbruster4d076d62015-06-10 08:55:21 +0200976
977 # Validate that exprs make sense
978 for expr_elem in exprs:
979 expr = expr_elem['expr']
980 info = expr_elem['info']
Markus Armbrustera9f396b2017-03-15 13:57:27 +0100981 doc = expr_elem.get('doc')
Markus Armbruster4d076d62015-06-10 08:55:21 +0200982
Eric Blake437db252015-09-29 16:21:02 -0600983 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200984 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600985 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200986 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600987 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200988 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600989 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200990 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600991 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200992 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600993 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200994 check_event(expr, info)
995 else:
996 assert False, 'unexpected meta type'
997
Markus Armbrustera9f396b2017-03-15 13:57:27 +0100998 if doc:
999 doc.check_expr(expr)
1000
Markus Armbrusterac882192015-09-16 13:06:05 +02001001 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -06001002
Markus Armbrusterac882192015-09-16 13:06:05 +02001003
1004#
1005# Schema compiler frontend
1006#
1007
1008class QAPISchemaEntity(object):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001009 def __init__(self, name, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001010 assert isinstance(name, str)
1011 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -06001012 # For explicitly defined entities, info points to the (explicit)
1013 # definition. For builtins (and their arrays), info is None.
1014 # For implicitly defined entities, info points to a place that
1015 # triggered the implicit definition (there may be more than one
1016 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +02001017 self.info = info
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001018 self.doc = doc
Markus Armbrusterac882192015-09-16 13:06:05 +02001019
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001020 def c_name(self):
1021 return c_name(self.name)
1022
Markus Armbrusterac882192015-09-16 13:06:05 +02001023 def check(self, schema):
1024 pass
1025
Eric Blake49823c42015-10-12 22:22:27 -06001026 def is_implicit(self):
1027 return not self.info
1028
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001029 def visit(self, visitor):
1030 pass
1031
1032
1033class QAPISchemaVisitor(object):
1034 def visit_begin(self, schema):
1035 pass
1036
1037 def visit_end(self):
1038 pass
1039
Eric Blake25a0d9c2015-10-12 22:22:21 -06001040 def visit_needed(self, entity):
1041 # Default to visiting everything
1042 return True
1043
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001044 def visit_builtin_type(self, name, info, json_type):
1045 pass
1046
1047 def visit_enum_type(self, name, info, values, prefix):
1048 pass
1049
1050 def visit_array_type(self, name, info, element_type):
1051 pass
1052
1053 def visit_object_type(self, name, info, base, members, variants):
1054 pass
1055
Markus Armbruster39a18152015-09-16 13:06:28 +02001056 def visit_object_type_flat(self, name, info, members, variants):
1057 pass
1058
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001059 def visit_alternate_type(self, name, info, variants):
1060 pass
1061
1062 def visit_command(self, name, info, arg_type, ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001063 gen, success_response, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001064 pass
1065
Eric Blake48825ca2016-07-13 21:50:19 -06001066 def visit_event(self, name, info, arg_type, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001067 pass
1068
Markus Armbrusterac882192015-09-16 13:06:05 +02001069
1070class QAPISchemaType(QAPISchemaEntity):
Eric Blake4040d992016-03-17 16:48:28 -06001071 # Return the C type for common use.
1072 # For the types we commonly box, this is a pointer type.
1073 def c_type(self):
1074 pass
1075
1076 # Return the C type to be used in a parameter list.
1077 def c_param_type(self):
1078 return self.c_type()
1079
1080 # Return the C type to be used where we suppress boxing.
1081 def c_unboxed_type(self):
1082 return self.c_type()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001083
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001084 def json_type(self):
1085 pass
1086
1087 def alternate_qtype(self):
1088 json2qtype = {
1089 'string': 'QTYPE_QSTRING',
1090 'number': 'QTYPE_QFLOAT',
1091 'int': 'QTYPE_QINT',
1092 'boolean': 'QTYPE_QBOOL',
1093 'object': 'QTYPE_QDICT'
1094 }
1095 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +02001096
Markus Armbruster691e0312017-03-15 13:57:14 +01001097 def doc_type(self):
1098 if self.is_implicit():
1099 return None
1100 return self.name
1101
Markus Armbrusterac882192015-09-16 13:06:05 +02001102
1103class QAPISchemaBuiltinType(QAPISchemaType):
Eric Blake861877a2016-03-17 16:48:36 -06001104 def __init__(self, name, json_type, c_type):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001105 QAPISchemaType.__init__(self, name, None, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001106 assert not c_type or isinstance(c_type, str)
1107 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
1108 'value')
1109 self._json_type_name = json_type
1110 self._c_type_name = c_type
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001111
1112 def c_name(self):
1113 return self.name
1114
Eric Blake4040d992016-03-17 16:48:28 -06001115 def c_type(self):
1116 return self._c_type_name
1117
1118 def c_param_type(self):
1119 if self.name == 'str':
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001120 return 'const ' + self._c_type_name
1121 return self._c_type_name
1122
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001123 def json_type(self):
1124 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +02001125
Markus Armbruster691e0312017-03-15 13:57:14 +01001126 def doc_type(self):
1127 return self.json_type()
1128
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001129 def visit(self, visitor):
1130 visitor.visit_builtin_type(self.name, self.info, self.json_type())
1131
Markus Armbrusterac882192015-09-16 13:06:05 +02001132
1133class QAPISchemaEnumType(QAPISchemaType):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001134 def __init__(self, name, info, doc, values, prefix):
1135 QAPISchemaType.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001136 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -07001137 assert isinstance(v, QAPISchemaMember)
1138 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001139 assert prefix is None or isinstance(prefix, str)
1140 self.values = values
1141 self.prefix = prefix
1142
1143 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -07001144 seen = {}
1145 for v in self.values:
1146 v.check_clash(self.info, seen)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001147 if self.doc:
1148 self.doc.connect_member(v)
Markus Armbrusterac882192015-09-16 13:06:05 +02001149
Eric Blake99df5282015-10-12 22:22:32 -06001150 def is_implicit(self):
Markus Armbruster46362112017-03-15 13:57:02 +01001151 # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
1152 return self.name.endswith('Kind') or self.name == 'QType'
Eric Blake99df5282015-10-12 22:22:32 -06001153
Eric Blake4040d992016-03-17 16:48:28 -06001154 def c_type(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001155 return c_name(self.name)
1156
Eric Blake93bda4d2015-12-01 22:20:55 -07001157 def member_names(self):
1158 return [v.name for v in self.values]
1159
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001160 def json_type(self):
1161 return 'string'
1162
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001163 def visit(self, visitor):
1164 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -07001165 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001166
Markus Armbrusterac882192015-09-16 13:06:05 +02001167
1168class QAPISchemaArrayType(QAPISchemaType):
1169 def __init__(self, name, info, element_type):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001170 QAPISchemaType.__init__(self, name, info, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001171 assert isinstance(element_type, str)
1172 self._element_type_name = element_type
1173 self.element_type = None
1174
1175 def check(self, schema):
1176 self.element_type = schema.lookup_type(self._element_type_name)
1177 assert self.element_type
1178
Eric Blake99df5282015-10-12 22:22:32 -06001179 def is_implicit(self):
1180 return True
1181
Eric Blake4040d992016-03-17 16:48:28 -06001182 def c_type(self):
1183 return c_name(self.name) + pointer_suffix
1184
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001185 def json_type(self):
1186 return 'array'
1187
Markus Armbruster691e0312017-03-15 13:57:14 +01001188 def doc_type(self):
1189 elt_doc_type = self.element_type.doc_type()
1190 if not elt_doc_type:
1191 return None
1192 return 'array of ' + elt_doc_type
1193
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001194 def visit(self, visitor):
1195 visitor.visit_array_type(self.name, self.info, self.element_type)
1196
Markus Armbrusterac882192015-09-16 13:06:05 +02001197
1198class QAPISchemaObjectType(QAPISchemaType):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001199 def __init__(self, name, info, doc, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -07001200 # struct has local_members, optional base, and no variants
1201 # flat union has base, variants, and no local_members
1202 # simple union has local_members, variants, and no base
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001203 QAPISchemaType.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001204 assert base is None or isinstance(base, str)
1205 for m in local_members:
1206 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -07001207 m.set_owner(name)
1208 if variants is not None:
1209 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1210 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001211 self._base_name = base
1212 self.base = None
1213 self.local_members = local_members
1214 self.variants = variants
1215 self.members = None
1216
1217 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -07001218 if self.members is False: # check for cycles
Marc-André Lureau4148c292017-01-13 15:41:25 +01001219 raise QAPISemError(self.info,
1220 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001221 if self.members:
1222 return
1223 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -07001224 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +02001225 if self._base_name:
1226 self.base = schema.lookup_type(self._base_name)
1227 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +02001228 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001229 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001230 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001231 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001232 m.check_clash(self.info, seen)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001233 if self.doc:
1234 self.doc.connect_member(m)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001235 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +02001236 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001237 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001238 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -07001239 self.variants.check_clash(schema, self.info, seen)
Markus Armbruster816a57c2017-03-15 13:57:26 +01001240 if self.doc:
1241 self.doc.check()
Markus Armbrusterac882192015-09-16 13:06:05 +02001242
Eric Blake14f00c62016-03-03 09:16:43 -07001243 # Check that the members of this type do not cause duplicate JSON members,
Eric Blake27b60ab2015-11-18 01:52:51 -07001244 # and update seen to track the members seen so far. Report any errors
1245 # on behalf of info, which is not necessarily self.info
1246 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -07001247 assert not self.variants # not implemented
1248 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -07001249 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -07001250
Eric Blake99df5282015-10-12 22:22:32 -06001251 def is_implicit(self):
Eric Blake75996972016-03-17 16:48:29 -06001252 # See QAPISchema._make_implicit_object_type(), as well as
1253 # _def_predefineds()
1254 return self.name.startswith('q_')
Eric Blake99df5282015-10-12 22:22:32 -06001255
Eric Blakeb6167702016-07-13 21:50:16 -06001256 def is_empty(self):
1257 assert self.members is not None
1258 return not self.members and not self.variants
1259
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001260 def c_name(self):
Eric Blakecd50a252016-07-13 21:50:14 -06001261 assert self.name != 'q_empty'
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001262 return QAPISchemaType.c_name(self)
1263
Eric Blake4040d992016-03-17 16:48:28 -06001264 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001265 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -07001266 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001267
Eric Blake4040d992016-03-17 16:48:28 -06001268 def c_unboxed_type(self):
Eric Blake4040d992016-03-17 16:48:28 -06001269 return c_name(self.name)
1270
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001271 def json_type(self):
1272 return 'object'
1273
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001274 def visit(self, visitor):
1275 visitor.visit_object_type(self.name, self.info,
1276 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001277 visitor.visit_object_type_flat(self.name, self.info,
1278 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001279
Markus Armbrusterac882192015-09-16 13:06:05 +02001280
Eric Blaked44f9ac2015-12-01 22:20:54 -07001281class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001282 role = 'member'
1283
Eric Blaked44f9ac2015-12-01 22:20:54 -07001284 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001285 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001286 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001287 self.owner = None
1288
1289 def set_owner(self, name):
1290 assert not self.owner
1291 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001292
Eric Blake27b60ab2015-11-18 01:52:51 -07001293 def check_clash(self, info, seen):
1294 cname = c_name(self.name)
Markus Armbruster2cfbae32017-03-15 13:56:55 +01001295 if cname.lower() != cname and self.owner not in name_case_whitelist:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001296 raise QAPISemError(info,
1297 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001298 if cname in seen:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001299 raise QAPISemError(info, "%s collides with %s" %
1300 (self.describe(), seen[cname].describe()))
Eric Blake27b60ab2015-11-18 01:52:51 -07001301 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001302
Eric Blake88d4ef82015-11-18 01:52:50 -07001303 def _pretty_owner(self):
1304 owner = self.owner
Eric Blake75996972016-03-17 16:48:29 -06001305 if owner.startswith('q_obj_'):
Eric Blake88d4ef82015-11-18 01:52:50 -07001306 # See QAPISchema._make_implicit_object_type() - reverse the
1307 # mapping there to create a nice human-readable description
Eric Blake75996972016-03-17 16:48:29 -06001308 owner = owner[6:]
Eric Blake88d4ef82015-11-18 01:52:50 -07001309 if owner.endswith('-arg'):
1310 return '(parameter of %s)' % owner[:-4]
Eric Blakeac4338f2016-03-17 16:48:39 -06001311 elif owner.endswith('-base'):
1312 return '(base of %s)' % owner[:-5]
Eric Blake88d4ef82015-11-18 01:52:50 -07001313 else:
1314 assert owner.endswith('-wrapper')
1315 # Unreachable and not implemented
1316 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001317 if owner.endswith('Kind'):
1318 # See QAPISchema._make_implicit_enum_type()
1319 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001320 return '(%s of %s)' % (self.role, owner)
1321
1322 def describe(self):
1323 return "'%s' %s" % (self.name, self._pretty_owner())
1324
Markus Armbrusterac882192015-09-16 13:06:05 +02001325
Eric Blaked44f9ac2015-12-01 22:20:54 -07001326class QAPISchemaObjectTypeMember(QAPISchemaMember):
1327 def __init__(self, name, typ, optional):
1328 QAPISchemaMember.__init__(self, name)
1329 assert isinstance(typ, str)
1330 assert isinstance(optional, bool)
1331 self._type_name = typ
1332 self.type = None
1333 self.optional = optional
1334
1335 def check(self, schema):
1336 assert self.owner
1337 self.type = schema.lookup_type(self._type_name)
1338 assert self.type
1339
1340
Markus Armbrusterac882192015-09-16 13:06:05 +02001341class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001342 def __init__(self, tag_name, tag_member, variants):
1343 # Flat unions pass tag_name but not tag_member.
1344 # Simple unions and alternates pass tag_member but not tag_name.
1345 # After check(), tag_member is always set, and tag_name remains
1346 # a reliable witness of being used by a flat union.
1347 assert bool(tag_member) != bool(tag_name)
1348 assert (isinstance(tag_name, str) or
1349 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001350 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001351 for v in variants:
1352 assert isinstance(v, QAPISchemaObjectTypeVariant)
Eric Blakeda9cb192016-07-13 21:50:15 -06001353 self._tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001354 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001355 self.variants = variants
1356
Eric Blake88d4ef82015-11-18 01:52:50 -07001357 def set_owner(self, name):
1358 for v in self.variants:
1359 v.set_owner(name)
1360
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001361 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001362 if not self.tag_member: # flat union
Eric Blakeda9cb192016-07-13 21:50:15 -06001363 self.tag_member = seen[c_name(self._tag_name)]
1364 assert self._tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001365 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1366 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001367 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001368 # Union names must match enum values; alternate names are
1369 # checked separately. Use 'seen' to tell the two apart.
1370 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001371 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001372 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001373 v.type.check(schema)
1374
Eric Blake27b60ab2015-11-18 01:52:51 -07001375 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001376 for v in self.variants:
1377 # Reset seen map for each variant, since qapi names from one
1378 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001379 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001380 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001381
Eric Blake437db252015-09-29 16:21:02 -06001382
Markus Armbrusterac882192015-09-16 13:06:05 +02001383class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001384 role = 'branch'
1385
Markus Armbrusterac882192015-09-16 13:06:05 +02001386 def __init__(self, name, typ):
1387 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1388
Markus Armbrusterac882192015-09-16 13:06:05 +02001389
1390class QAPISchemaAlternateType(QAPISchemaType):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001391 def __init__(self, name, info, doc, variants):
1392 QAPISchemaType.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001393 assert isinstance(variants, QAPISchemaObjectTypeVariants)
Eric Blakeda9cb192016-07-13 21:50:15 -06001394 assert variants.tag_member
Eric Blake88d4ef82015-11-18 01:52:50 -07001395 variants.set_owner(name)
1396 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001397 self.variants = variants
1398
1399 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001400 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001401 # Not calling self.variants.check_clash(), because there's nothing
1402 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001403 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001404 # Alternate branch names have no relation to the tag enum values;
1405 # so we have to check for potential name collisions ourselves.
1406 seen = {}
1407 for v in self.variants.variants:
1408 v.check_clash(self.info, seen)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001409 if self.doc:
1410 self.doc.connect_member(v)
Markus Armbruster816a57c2017-03-15 13:57:26 +01001411 if self.doc:
1412 self.doc.check()
Markus Armbrusterac882192015-09-16 13:06:05 +02001413
Eric Blake4040d992016-03-17 16:48:28 -06001414 def c_type(self):
1415 return c_name(self.name) + pointer_suffix
1416
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001417 def json_type(self):
1418 return 'value'
1419
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001420 def visit(self, visitor):
1421 visitor.visit_alternate_type(self.name, self.info, self.variants)
1422
Eric Blakec8184082016-07-13 21:50:20 -06001423 def is_empty(self):
1424 return False
1425
Markus Armbrusterac882192015-09-16 13:06:05 +02001426
1427class QAPISchemaCommand(QAPISchemaEntity):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001428 def __init__(self, name, info, doc, arg_type, ret_type,
1429 gen, success_response, boxed):
1430 QAPISchemaEntity.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001431 assert not arg_type or isinstance(arg_type, str)
1432 assert not ret_type or isinstance(ret_type, str)
1433 self._arg_type_name = arg_type
1434 self.arg_type = None
1435 self._ret_type_name = ret_type
1436 self.ret_type = None
1437 self.gen = gen
1438 self.success_response = success_response
Eric Blake48825ca2016-07-13 21:50:19 -06001439 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001440
1441 def check(self, schema):
1442 if self._arg_type_name:
1443 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001444 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1445 isinstance(self.arg_type, QAPISchemaAlternateType))
1446 self.arg_type.check(schema)
1447 if self.boxed:
1448 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001449 raise QAPISemError(self.info,
1450 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001451 else:
1452 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1453 assert not self.arg_type.variants
1454 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001455 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001456 if self._ret_type_name:
1457 self.ret_type = schema.lookup_type(self._ret_type_name)
1458 assert isinstance(self.ret_type, QAPISchemaType)
1459
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001460 def visit(self, visitor):
1461 visitor.visit_command(self.name, self.info,
1462 self.arg_type, self.ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001463 self.gen, self.success_response, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001464
Markus Armbrusterac882192015-09-16 13:06:05 +02001465
1466class QAPISchemaEvent(QAPISchemaEntity):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001467 def __init__(self, name, info, doc, arg_type, boxed):
1468 QAPISchemaEntity.__init__(self, name, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001469 assert not arg_type or isinstance(arg_type, str)
1470 self._arg_type_name = arg_type
1471 self.arg_type = None
Eric Blake48825ca2016-07-13 21:50:19 -06001472 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001473
1474 def check(self, schema):
1475 if self._arg_type_name:
1476 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001477 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1478 isinstance(self.arg_type, QAPISchemaAlternateType))
1479 self.arg_type.check(schema)
1480 if self.boxed:
1481 if self.arg_type.is_empty():
Marc-André Lureau4148c292017-01-13 15:41:25 +01001482 raise QAPISemError(self.info,
1483 "Cannot use 'boxed' with empty type")
Eric Blakec8184082016-07-13 21:50:20 -06001484 else:
1485 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1486 assert not self.arg_type.variants
1487 elif self.boxed:
Marc-André Lureau4148c292017-01-13 15:41:25 +01001488 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001489
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001490 def visit(self, visitor):
Eric Blake48825ca2016-07-13 21:50:19 -06001491 visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001492
Markus Armbrusterac882192015-09-16 13:06:05 +02001493
1494class QAPISchema(object):
1495 def __init__(self, fname):
1496 try:
Markus Armbrusteref801a92017-03-15 13:57:08 +01001497 parser = QAPISchemaParser(open(fname, 'r'))
Marc-André Lureau3313b612017-01-13 15:41:29 +01001498 self.exprs = check_exprs(parser.exprs)
Markus Armbrustera9f396b2017-03-15 13:57:27 +01001499 self.docs = parser.docs
Eric Blake7618b912015-10-12 22:22:22 -06001500 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001501 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001502 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001503 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001504 self._def_exprs()
1505 self.check()
Marc-André Lureau4148c292017-01-13 15:41:25 +01001506 except QAPIError as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001507 print >>sys.stderr, err
1508 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001509
Markus Armbrusterac882192015-09-16 13:06:05 +02001510 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001511 # Only the predefined types are allowed to not have info
1512 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001513 assert ent.name not in self._entity_dict
1514 self._entity_dict[ent.name] = ent
1515
1516 def lookup_entity(self, name, typ=None):
1517 ent = self._entity_dict.get(name)
1518 if typ and not isinstance(ent, typ):
1519 return None
1520 return ent
1521
1522 def lookup_type(self, name):
1523 return self.lookup_entity(name, QAPISchemaType)
1524
Eric Blake861877a2016-03-17 16:48:36 -06001525 def _def_builtin_type(self, name, json_type, c_type):
1526 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001527 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1528 # qapi-types.h from a single .c, all arrays of builtins must be
1529 # declared in the first file whether or not they are used. Nicer
1530 # would be to use lazy instantiation, while figuring out how to
1531 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001532 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001533
1534 def _def_predefineds(self):
Eric Blake861877a2016-03-17 16:48:36 -06001535 for t in [('str', 'string', 'char' + pointer_suffix),
1536 ('number', 'number', 'double'),
1537 ('int', 'int', 'int64_t'),
1538 ('int8', 'int', 'int8_t'),
1539 ('int16', 'int', 'int16_t'),
1540 ('int32', 'int', 'int32_t'),
1541 ('int64', 'int', 'int64_t'),
1542 ('uint8', 'int', 'uint8_t'),
1543 ('uint16', 'int', 'uint16_t'),
1544 ('uint32', 'int', 'uint32_t'),
1545 ('uint64', 'int', 'uint64_t'),
1546 ('size', 'int', 'uint64_t'),
1547 ('bool', 'boolean', 'bool'),
1548 ('any', 'value', 'QObject' + pointer_suffix)]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001549 self._def_builtin_type(*t)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001550 self.the_empty_object_type = QAPISchemaObjectType(
1551 'q_empty', None, None, None, [], None)
Markus Armbruster39a18152015-09-16 13:06:28 +02001552 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001553 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1554 'qstring', 'qdict', 'qlist',
1555 'qfloat', 'qbool'])
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001556 self._def_entity(QAPISchemaEnumType('QType', None, None,
1557 qtype_values, 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001558
Eric Blake93bda4d2015-12-01 22:20:55 -07001559 def _make_enum_members(self, values):
1560 return [QAPISchemaMember(v) for v in values]
1561
Eric Blake99df5282015-10-12 22:22:32 -06001562 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001563 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001564 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001565 self._def_entity(QAPISchemaEnumType(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001566 name, info, None, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001567 return name
1568
Eric Blake99df5282015-10-12 22:22:32 -06001569 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001570 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001571 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001572 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001573 return name
1574
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001575 def _make_implicit_object_type(self, name, info, doc, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001576 if not members:
1577 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001578 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake75996972016-03-17 16:48:29 -06001579 name = 'q_obj_%s-%s' % (name, role)
Markus Armbrusterac882192015-09-16 13:06:05 +02001580 if not self.lookup_entity(name, QAPISchemaObjectType):
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001581 self._def_entity(QAPISchemaObjectType(name, info, doc, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001582 members, None))
1583 return name
1584
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001585 def _def_enum_type(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001586 name = expr['enum']
1587 data = expr['data']
1588 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001589 self._def_entity(QAPISchemaEnumType(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001590 name, info, doc, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001591
Eric Blake99df5282015-10-12 22:22:32 -06001592 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001593 optional = False
1594 if name.startswith('*'):
1595 name = name[1:]
1596 optional = True
1597 if isinstance(typ, list):
1598 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001599 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001600 return QAPISchemaObjectTypeMember(name, typ, optional)
1601
Eric Blake99df5282015-10-12 22:22:32 -06001602 def _make_members(self, data, info):
1603 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001604 for (key, value) in data.iteritems()]
1605
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001606 def _def_struct_type(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001607 name = expr['struct']
1608 base = expr.get('base')
1609 data = expr['data']
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001610 self._def_entity(QAPISchemaObjectType(name, info, doc, base,
Eric Blake99df5282015-10-12 22:22:32 -06001611 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001612 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001613
1614 def _make_variant(self, case, typ):
1615 return QAPISchemaObjectTypeVariant(case, typ)
1616
Eric Blake99df5282015-10-12 22:22:32 -06001617 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001618 if isinstance(typ, list):
1619 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001620 typ = self._make_array_type(typ[0], info)
1621 typ = self._make_implicit_object_type(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001622 typ, info, None, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001623 return QAPISchemaObjectTypeVariant(case, typ)
1624
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001625 def _def_union_type(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001626 name = expr['union']
1627 data = expr['data']
1628 base = expr.get('base')
1629 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001630 tag_member = None
Eric Blakeac4338f2016-03-17 16:48:39 -06001631 if isinstance(base, dict):
1632 base = (self._make_implicit_object_type(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001633 name, info, doc, 'base', self._make_members(base, info)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001634 if tag_name:
1635 variants = [self._make_variant(key, value)
1636 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001637 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001638 else:
Eric Blake99df5282015-10-12 22:22:32 -06001639 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001640 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001641 typ = self._make_implicit_enum_type(name, info,
1642 [v.name for v in variants])
1643 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001644 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001645 self._def_entity(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001646 QAPISchemaObjectType(name, info, doc, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001647 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001648 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001649 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001650
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001651 def _def_alternate_type(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001652 name = expr['alternate']
1653 data = expr['data']
1654 variants = [self._make_variant(key, value)
1655 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001656 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001657 self._def_entity(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001658 QAPISchemaAlternateType(name, info, doc,
Markus Armbrusterac882192015-09-16 13:06:05 +02001659 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001660 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001661 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001662
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001663 def _def_command(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001664 name = expr['command']
1665 data = expr.get('data')
1666 rets = expr.get('returns')
1667 gen = expr.get('gen', True)
1668 success_response = expr.get('success-response', True)
Eric Blake48825ca2016-07-13 21:50:19 -06001669 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001670 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001671 data = self._make_implicit_object_type(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001672 name, info, doc, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001673 if isinstance(rets, list):
1674 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001675 rets = self._make_array_type(rets[0], info)
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001676 self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
1677 gen, success_response, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001678
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001679 def _def_event(self, expr, info, doc):
Markus Armbrusterac882192015-09-16 13:06:05 +02001680 name = expr['event']
1681 data = expr.get('data')
Eric Blake48825ca2016-07-13 21:50:19 -06001682 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001683 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001684 data = self._make_implicit_object_type(
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001685 name, info, doc, 'arg', self._make_members(data, info))
1686 self._def_entity(QAPISchemaEvent(name, info, doc, data, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001687
1688 def _def_exprs(self):
1689 for expr_elem in self.exprs:
1690 expr = expr_elem['expr']
1691 info = expr_elem['info']
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001692 doc = expr_elem.get('doc')
Markus Armbrusterac882192015-09-16 13:06:05 +02001693 if 'enum' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001694 self._def_enum_type(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001695 elif 'struct' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001696 self._def_struct_type(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001697 elif 'union' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001698 self._def_union_type(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001699 elif 'alternate' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001700 self._def_alternate_type(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001701 elif 'command' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001702 self._def_command(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001703 elif 'event' in expr:
Markus Armbruster069fb5b2017-03-15 13:57:03 +01001704 self._def_event(expr, info, doc)
Markus Armbrusterac882192015-09-16 13:06:05 +02001705 else:
1706 assert False
1707
1708 def check(self):
1709 for ent in self._entity_dict.values():
1710 ent.check(self)
1711
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001712 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001713 visitor.visit_begin(self)
1714 for (name, entity) in sorted(self._entity_dict.items()):
1715 if visitor.visit_needed(entity):
1716 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001717 visitor.visit_end()
1718
Markus Armbruster2caba362013-07-27 17:41:56 +02001719
Markus Armbruster00e4b282015-06-10 10:04:36 +02001720#
1721# Code generation helpers
1722#
1723
Michael Roth0f923be2011-07-19 14:50:39 -05001724def camel_case(name):
1725 new_name = ''
1726 first = True
1727 for ch in name:
1728 if ch in ['_', '-']:
1729 first = True
1730 elif first:
1731 new_name += ch.upper()
1732 first = False
1733 else:
1734 new_name += ch.lower()
1735 return new_name
1736
Eric Blake437db252015-09-29 16:21:02 -06001737
Markus Armbruster849bc532015-05-14 06:50:53 -06001738# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1739# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1740# ENUM24_Name -> ENUM24_NAME
1741def camel_to_upper(value):
1742 c_fun_str = c_name(value, False)
1743 if value.isupper():
1744 return c_fun_str
1745
1746 new_name = ''
1747 l = len(c_fun_str)
1748 for i in range(l):
1749 c = c_fun_str[i]
Markus Armbrusteref801a92017-03-15 13:57:08 +01001750 # When c is upper and no '_' appears before, do more checks
1751 if c.isupper() and (i > 0) and c_fun_str[i - 1] != '_':
Eric Blake437db252015-09-29 16:21:02 -06001752 if i < l - 1 and c_fun_str[i + 1].islower():
1753 new_name += '_'
1754 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001755 new_name += '_'
1756 new_name += c
1757 return new_name.lstrip('_').upper()
1758
Eric Blake437db252015-09-29 16:21:02 -06001759
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001760def c_enum_const(type_name, const_name, prefix=None):
1761 if prefix is not None:
1762 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001763 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001764
Eric Blake18df5152015-05-14 06:50:48 -06001765c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001766
Eric Blake437db252015-09-29 16:21:02 -06001767
Eric Blakec6405b52015-05-14 06:50:55 -06001768# Map @name to a valid C identifier.
1769# If @protect, avoid returning certain ticklish identifiers (like
Markus Armbrusteref801a92017-03-15 13:57:08 +01001770# C keywords) by prepending 'q_'.
Eric Blakec6405b52015-05-14 06:50:55 -06001771#
1772# Used for converting 'name' from a 'name':'type' qapi definition
1773# into a generated struct member, as well as converting type names
1774# into substrings of a generated C function name.
1775# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1776# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001777def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001778 # ANSI X3J11/88-090, 3.1.1
1779 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001780 'default', 'do', 'double', 'else', 'enum', 'extern',
1781 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1782 'return', 'short', 'signed', 'sizeof', 'static',
1783 'struct', 'switch', 'typedef', 'union', 'unsigned',
1784 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001785 # ISO/IEC 9899:1999, 6.4.1
1786 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1787 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001788 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1789 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001790 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1791 # excluding _.*
1792 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001793 # C++ ISO/IEC 14882:2003 2.11
1794 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1795 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1796 'namespace', 'new', 'operator', 'private', 'protected',
1797 'public', 'reinterpret_cast', 'static_cast', 'template',
1798 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1799 'using', 'virtual', 'wchar_t',
1800 # alternative representations
1801 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1802 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001803 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001804 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001805 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001806 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1807 | cpp_words | polluted_words):
Markus Armbrusteref801a92017-03-15 13:57:08 +01001808 return 'q_' + name
Eric Blakec43567c2015-11-18 01:52:52 -07001809 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001810
Amos Kong05dfb262014-06-10 19:25:53 +08001811eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001812pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001813
Eric Blake437db252015-09-29 16:21:02 -06001814
Michael Roth0f923be2011-07-19 14:50:39 -05001815def genindent(count):
Markus Armbrusteref801a92017-03-15 13:57:08 +01001816 ret = ''
Eric Blake437db252015-09-29 16:21:02 -06001817 for _ in range(count):
Markus Armbrusteref801a92017-03-15 13:57:08 +01001818 ret += ' '
Michael Roth0f923be2011-07-19 14:50:39 -05001819 return ret
1820
1821indent_level = 0
1822
Eric Blake437db252015-09-29 16:21:02 -06001823
Michael Roth0f923be2011-07-19 14:50:39 -05001824def push_indent(indent_amount=4):
1825 global indent_level
1826 indent_level += indent_amount
1827
Eric Blake437db252015-09-29 16:21:02 -06001828
Michael Roth0f923be2011-07-19 14:50:39 -05001829def pop_indent(indent_amount=4):
1830 global indent_level
1831 indent_level -= indent_amount
1832
Eric Blake437db252015-09-29 16:21:02 -06001833
Markus Armbruster77e703b2015-06-24 19:27:32 +02001834# Generate @code with @kwds interpolated.
1835# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001836def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001837 raw = code % kwds
1838 if indent_level:
1839 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001840 # re.subn() lacks flags support before Python 2.7, use re.compile()
Markus Armbruster0fe675a2017-03-15 13:57:07 +01001841 raw = re.subn(re.compile(r'^.', re.MULTILINE),
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001842 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001843 raw = raw[0]
Markus Armbruster0fe675a2017-03-15 13:57:07 +01001844 return re.sub(re.escape(eatspace) + r' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001845
Eric Blake437db252015-09-29 16:21:02 -06001846
Michael Roth0f923be2011-07-19 14:50:39 -05001847def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001848 if code[0] == '\n':
1849 code = code[1:]
1850 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001851
Michael Roth0f923be2011-07-19 14:50:39 -05001852
1853def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001854 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001855
Eric Blake437db252015-09-29 16:21:02 -06001856
Michael Rothc0afa9c2013-05-10 17:46:00 -05001857def guardstart(name):
1858 return mcgen('''
1859
1860#ifndef %(name)s
1861#define %(name)s
1862
1863''',
1864 name=guardname(name))
1865
Eric Blake437db252015-09-29 16:21:02 -06001866
Michael Rothc0afa9c2013-05-10 17:46:00 -05001867def guardend(name):
1868 return mcgen('''
1869
1870#endif /* %(name)s */
1871
1872''',
1873 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001874
Eric Blake437db252015-09-29 16:21:02 -06001875
Markus Armbrustere98859a2015-09-16 13:06:16 +02001876def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001877 ret = mcgen('''
1878
Markus Armbrustere98859a2015-09-16 13:06:16 +02001879const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001880''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001881 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001882 for value in values:
1883 index = c_enum_const(name, value, prefix)
1884 ret += mcgen('''
1885 [%(index)s] = "%(value)s",
1886''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001887 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001888
Eric Blake7fb1cf12015-11-18 01:52:57 -07001889 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001890 ret += mcgen('''
1891 [%(max_index)s] = NULL,
1892};
1893''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001894 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001895 return ret
1896
Eric Blake437db252015-09-29 16:21:02 -06001897
Markus Armbrustere98859a2015-09-16 13:06:16 +02001898def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001899 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001900 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001901
1902 ret = mcgen('''
1903
1904typedef enum %(c_name)s {
1905''',
1906 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001907
1908 i = 0
1909 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001910 ret += mcgen('''
1911 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001912''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001913 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001914 i=i)
1915 i += 1
1916
Markus Armbrustere98859a2015-09-16 13:06:16 +02001917 ret += mcgen('''
1918} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001919''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001920 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001921
Markus Armbrustere98859a2015-09-16 13:06:16 +02001922 ret += mcgen('''
1923
1924extern const char *const %(c_name)s_lookup[];
1925''',
1926 c_name=c_name(name))
1927 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001928
Eric Blake437db252015-09-29 16:21:02 -06001929
Eric Blake48825ca2016-07-13 21:50:19 -06001930def gen_params(arg_type, boxed, extra):
Markus Armbruster03b43672015-09-16 13:06:20 +02001931 if not arg_type:
Eric Blakec8184082016-07-13 21:50:20 -06001932 assert not boxed
Markus Armbruster03b43672015-09-16 13:06:20 +02001933 return extra
Markus Armbruster03b43672015-09-16 13:06:20 +02001934 ret = ''
1935 sep = ''
Eric Blake48825ca2016-07-13 21:50:19 -06001936 if boxed:
Eric Blakec8184082016-07-13 21:50:20 -06001937 ret += '%s arg' % arg_type.c_param_type()
1938 sep = ', '
Eric Blake48825ca2016-07-13 21:50:19 -06001939 else:
1940 assert not arg_type.variants
1941 for memb in arg_type.members:
1942 ret += sep
1943 sep = ', '
1944 if memb.optional:
1945 ret += 'bool has_%s, ' % c_name(memb.name)
1946 ret += '%s %s' % (memb.type.c_param_type(),
1947 c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001948 if extra:
1949 ret += sep + extra
1950 return ret
1951
Eric Blake1f353342015-09-29 16:21:13 -06001952
Markus Armbruster00e4b282015-06-10 10:04:36 +02001953#
1954# Common command line parsing
1955#
1956
Eric Blake437db252015-09-29 16:21:02 -06001957
Markus Armbrusteref801a92017-03-15 13:57:08 +01001958def parse_command_line(extra_options='', extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001959
1960 try:
1961 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbrusteref801a92017-03-15 13:57:08 +01001962 'chp:o:' + extra_options,
1963 ['source', 'header', 'prefix=',
1964 'output-dir='] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001965 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001966 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001967 sys.exit(1)
1968
Markus Armbrusteref801a92017-03-15 13:57:08 +01001969 output_dir = ''
1970 prefix = ''
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001971 do_c = False
1972 do_h = False
1973 extra_opts = []
1974
1975 for oa in opts:
1976 o, a = oa
Markus Armbrusteref801a92017-03-15 13:57:08 +01001977 if o in ('-p', '--prefix'):
Markus Armbruster0fe675a2017-03-15 13:57:07 +01001978 match = re.match(r'([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001979 if match.end() != len(a):
1980 print >>sys.stderr, \
1981 "%s: 'funny character '%s' in argument of --prefix" \
1982 % (sys.argv[0], a[match.end()])
1983 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001984 prefix = a
Markus Armbrusteref801a92017-03-15 13:57:08 +01001985 elif o in ('-o', '--output-dir'):
1986 output_dir = a + '/'
1987 elif o in ('-c', '--source'):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001988 do_c = True
Markus Armbrusteref801a92017-03-15 13:57:08 +01001989 elif o in ('-h', '--header'):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001990 do_h = True
1991 else:
1992 extra_opts.append(oa)
1993
1994 if not do_c and not do_h:
1995 do_c = True
1996 do_h = True
1997
Markus Armbruster16d80f62015-04-02 13:32:16 +02001998 if len(args) != 1:
1999 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02002000 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02002001 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02002002
Markus Armbruster54414042015-06-09 16:22:45 +02002003 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002004
Markus Armbruster00e4b282015-06-10 10:04:36 +02002005#
2006# Generate output files with boilerplate
2007#
2008
Eric Blake437db252015-09-29 16:21:02 -06002009
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002010def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
2011 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02002012 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002013 c_file = output_dir + prefix + c_file
2014 h_file = output_dir + prefix + h_file
2015
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02002016 if output_dir:
2017 try:
2018 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01002019 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02002020 if e.errno != errno.EEXIST:
2021 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002022
2023 def maybe_open(really, name, opt):
2024 if really:
2025 return open(name, opt)
2026 else:
2027 import StringIO
2028 return StringIO.StringIO()
2029
2030 fdef = maybe_open(do_c, c_file, 'w')
2031 fdecl = maybe_open(do_h, h_file, 'w')
2032
2033 fdef.write(mcgen('''
2034/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2035%(comment)s
2036''',
Eric Blake437db252015-09-29 16:21:02 -06002037 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002038
2039 fdecl.write(mcgen('''
2040/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
2041%(comment)s
2042#ifndef %(guard)s
2043#define %(guard)s
2044
2045''',
Eric Blake437db252015-09-29 16:21:02 -06002046 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002047
2048 return (fdef, fdecl)
2049
Eric Blake437db252015-09-29 16:21:02 -06002050
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002051def close_output(fdef, fdecl):
2052 fdecl.write('''
2053#endif
2054''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002055 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02002056 fdef.close()