blob: 74a561afda02d15f7d11a00abdceebf13aad29ee [file] [log] [blame]
Michael Roth0f923be2011-07-19 14:50:39 -05001#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
Eric Blakefe2a9302015-05-04 09:05:02 -06005# Copyright (c) 2013-2015 Red Hat Inc.
Michael Roth0f923be2011-07-19 14:50:39 -05006#
7# Authors:
8# Anthony Liguori <aliguori@us.ibm.com>
Markus Armbrusterc7a3f252013-07-27 17:41:55 +02009# Markus Armbruster <armbru@redhat.com>
Michael Roth0f923be2011-07-19 14:50:39 -050010#
Markus Armbruster678e48a2014-03-01 08:40:34 +010011# This work is licensed under the terms of the GNU GPL, version 2.
12# See the COPYING file in the top-level directory.
Michael Roth0f923be2011-07-19 14:50:39 -050013
Lluís Vilanovaa719a272014-05-07 20:46:15 +020014import re
Michael Roth0f923be2011-07-19 14:50:39 -050015from ordereddict import OrderedDict
Markus Armbruster12f8e1b2015-04-02 14:46:39 +020016import errno
Markus Armbruster2114f5a2015-04-02 13:12:21 +020017import getopt
Lluís Vilanova33aaad52014-05-02 15:52:35 +020018import os
Markus Armbruster2caba362013-07-27 17:41:56 +020019import sys
Markus Armbruster47299262015-05-14 06:50:47 -060020import string
Michael Roth0f923be2011-07-19 14:50:39 -050021
Eric Blakeb52c4b92015-05-04 09:05:00 -060022builtin_types = {
Kevin Wolf69dd62d2013-07-08 16:14:21 +020023 'str': 'QTYPE_QSTRING',
24 'int': 'QTYPE_QINT',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
27 'int8': 'QTYPE_QINT',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
Eric Blakecb17f792015-05-04 09:05:01 -060035 'size': 'QTYPE_QINT',
Eric Blake1310a3d2015-12-01 22:20:46 -070036 'any': None, # any QType possible, actually
Eric Blake7264f5c2015-12-01 22:20:47 -070037 'QType': 'QTYPE_QSTRING',
Kevin Wolf69dd62d2013-07-08 16:14:21 +020038}
39
Eric Blake10d4d992015-05-04 09:05:23 -060040# Whitelist of commands allowed to return a non-dictionary
41returns_whitelist = [
42 # From QMP:
43 'human-monitor-command',
Markus Armbruster6eb39372015-09-16 13:06:25 +020044 'qom-get',
Eric Blake10d4d992015-05-04 09:05:23 -060045 'query-migrate-cache-size',
46 'query-tpm-models',
47 'query-tpm-types',
48 'ringbuf-read',
49
50 # From QGA:
51 'guest-file-open',
52 'guest-fsfreeze-freeze',
53 'guest-fsfreeze-freeze-list',
54 'guest-fsfreeze-status',
55 'guest-fsfreeze-thaw',
56 'guest-get-time',
57 'guest-set-vcpus',
58 'guest-sync',
59 'guest-sync-delimited',
Eric Blake10d4d992015-05-04 09:05:23 -060060]
61
Eric Blake893e1f22015-12-01 22:20:57 -070062# Whitelist of entities allowed to violate case conventions
63case_whitelist = [
64 # From QMP:
65 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
66 'CpuInfoBase', # CPU, visible through query-cpu
67 'CpuInfoMIPS', # PC, visible through query-cpu
68 'CpuInfoTricore', # PC, visible through query-cpu
69 'InputAxis', # TODO: drop when x-input-send-event is fixed
70 'InputButton', # TODO: drop when x-input-send-event is fixed
71 'QapiErrorClass', # all members, visible through errors
72 'UuidInfo', # UUID, visible through query-uuid
73 'X86CPURegister32', # all members, visible indirectly through qom-get
74]
75
Eric Blake4dc2e692015-05-04 09:05:17 -060076enum_types = []
77struct_types = []
78union_types = []
79events = []
80all_names = {}
81
Markus Armbruster00e4b282015-06-10 10:04:36 +020082#
83# Parsing the schema into expressions
84#
85
Eric Blake437db252015-09-29 16:21:02 -060086
Lluís Vilanovaa719a272014-05-07 20:46:15 +020087def error_path(parent):
88 res = ""
89 while parent:
90 res = ("In file included from %s:%d:\n" % (parent['file'],
91 parent['line'])) + res
92 parent = parent['parent']
93 return res
94
Eric Blake437db252015-09-29 16:21:02 -060095
Markus Armbruster2caba362013-07-27 17:41:56 +020096class QAPISchemaError(Exception):
97 def __init__(self, schema, msg):
Eric Blake59b00542015-09-29 16:21:01 -060098 Exception.__init__(self)
Markus Armbruster54414042015-06-09 16:22:45 +020099 self.fname = schema.fname
Markus Armbruster2caba362013-07-27 17:41:56 +0200100 self.msg = msg
Wenchao Xia515b9432014-03-04 18:44:33 -0800101 self.col = 1
102 self.line = schema.line
103 for ch in schema.src[schema.line_pos:schema.pos]:
104 if ch == '\t':
Markus Armbruster2caba362013-07-27 17:41:56 +0200105 self.col = (self.col + 7) % 8 + 1
106 else:
107 self.col += 1
Markus Armbruster54414042015-06-09 16:22:45 +0200108 self.info = schema.incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +0200109
110 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200111 return error_path(self.info) + \
Markus Armbruster54414042015-06-09 16:22:45 +0200112 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
Markus Armbruster2caba362013-07-27 17:41:56 +0200113
Eric Blake437db252015-09-29 16:21:02 -0600114
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800115class QAPIExprError(Exception):
116 def __init__(self, expr_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -0600117 Exception.__init__(self)
Eric Blake7618b912015-10-12 22:22:22 -0600118 assert expr_info
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200119 self.info = expr_info
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800120 self.msg = msg
121
122 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200123 return error_path(self.info['parent']) + \
124 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800125
Eric Blake437db252015-09-29 16:21:02 -0600126
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200127class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500128
Eric Blake437db252015-09-29 16:21:02 -0600129 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200130 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200131 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200132 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200133 previously_included.append(abs_fname)
134 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200135 self.src = fp.read()
136 if self.src == '' or self.src[-1] != '\n':
137 self.src += '\n'
138 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800139 self.line = 1
140 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200141 self.exprs = []
142 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500143
Eric Blake437db252015-09-29 16:21:02 -0600144 while self.tok is not None:
Markus Armbruster54414042015-06-09 16:22:45 +0200145 expr_info = {'file': fname, 'line': self.line,
146 'parent': self.incl_info}
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200147 expr = self.get_expr(False)
148 if isinstance(expr, dict) and "include" in expr:
149 if len(expr) != 1:
Eric Blake437db252015-09-29 16:21:02 -0600150 raise QAPIExprError(expr_info,
151 "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200152 include = expr["include"]
153 if not isinstance(include, str):
154 raise QAPIExprError(expr_info,
Eric Blake7408fb62015-09-29 16:21:00 -0600155 "Value of 'include' must be a string")
Markus Armbruster54414042015-06-09 16:22:45 +0200156 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
157 include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200158 # catch inclusion cycle
159 inf = expr_info
160 while inf:
161 if incl_abs_fname == os.path.abspath(inf['file']):
Stefan Hajnoczi7ac9a9d2014-08-27 12:08:51 +0100162 raise QAPIExprError(expr_info, "Inclusion loop for %s"
163 % include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200164 inf = inf['parent']
Benoît Canet24fd8482014-05-16 12:51:56 +0200165 # skip multiple include of the same file
Markus Armbruster54414042015-06-09 16:22:45 +0200166 if incl_abs_fname in previously_included:
Benoît Canet24fd8482014-05-16 12:51:56 +0200167 continue
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200168 try:
Markus Armbruster54414042015-06-09 16:22:45 +0200169 fobj = open(incl_abs_fname, 'r')
Luiz Capitulino34788812014-05-20 13:50:19 -0400170 except IOError, e:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200171 raise QAPIExprError(expr_info,
172 '%s: %s' % (e.strerror, include))
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200173 exprs_include = QAPISchemaParser(fobj, previously_included,
174 expr_info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200175 self.exprs.extend(exprs_include.exprs)
176 else:
177 expr_elem = {'expr': expr,
178 'info': expr_info}
179 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500180
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200181 def accept(self):
182 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200183 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200184 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200185 self.cursor += 1
186 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500187
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200188 if self.tok == '#':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200189 self.cursor = self.src.find('\n', self.cursor)
Eric Blake8712fa52015-10-26 16:34:41 -0600190 elif self.tok in "{}:,[]":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200191 return
192 elif self.tok == "'":
193 string = ''
194 esc = False
195 while True:
196 ch = self.src[self.cursor]
197 self.cursor += 1
198 if ch == '\n':
Markus Armbruster2caba362013-07-27 17:41:56 +0200199 raise QAPISchemaError(self,
200 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200201 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600202 if ch == 'b':
203 string += '\b'
204 elif ch == 'f':
205 string += '\f'
206 elif ch == 'n':
207 string += '\n'
208 elif ch == 'r':
209 string += '\r'
210 elif ch == 't':
211 string += '\t'
212 elif ch == 'u':
213 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600214 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600215 ch = self.src[self.cursor]
216 self.cursor += 1
217 if ch not in "0123456789abcdefABCDEF":
218 raise QAPISchemaError(self,
219 '\\u escape needs 4 '
220 'hex digits')
221 value = (value << 4) + int(ch, 16)
222 # If Python 2 and 3 didn't disagree so much on
223 # how to handle Unicode, then we could allow
224 # Unicode string defaults. But most of QAPI is
225 # ASCII-only, so we aren't losing much for now.
226 if not value or value > 0x7f:
227 raise QAPISchemaError(self,
228 'For now, \\u escape '
229 'only supports non-zero '
230 'values up to \\u007f')
231 string += chr(value)
232 elif ch in "\\/'\"":
233 string += ch
234 else:
235 raise QAPISchemaError(self,
Eric Blake437db252015-09-29 16:21:02 -0600236 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200237 esc = False
238 elif ch == "\\":
239 esc = True
240 elif ch == "'":
241 self.val = string
242 return
243 else:
244 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200245 elif self.src.startswith("true", self.pos):
246 self.val = True
247 self.cursor += 3
248 return
249 elif self.src.startswith("false", self.pos):
250 self.val = False
251 self.cursor += 4
252 return
253 elif self.src.startswith("null", self.pos):
254 self.val = None
255 self.cursor += 3
256 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200257 elif self.tok == '\n':
258 if self.cursor == len(self.src):
259 self.tok = None
260 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800261 self.line += 1
262 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200263 elif not self.tok.isspace():
264 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500265
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200266 def get_members(self):
267 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200268 if self.tok == '}':
269 self.accept()
270 return expr
271 if self.tok != "'":
272 raise QAPISchemaError(self, 'Expected string or "}"')
273 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200274 key = self.val
275 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200276 if self.tok != ':':
277 raise QAPISchemaError(self, 'Expected ":"')
278 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800279 if key in expr:
280 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200281 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200282 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200283 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200284 return expr
285 if self.tok != ',':
286 raise QAPISchemaError(self, 'Expected "," or "}"')
287 self.accept()
288 if self.tok != "'":
289 raise QAPISchemaError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500290
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200291 def get_values(self):
292 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200293 if self.tok == ']':
294 self.accept()
295 return expr
Eric Blake437db252015-09-29 16:21:02 -0600296 if self.tok not in "{['tfn":
Fam Zhenge53188a2015-05-04 09:05:18 -0600297 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
298 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200299 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200300 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200301 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200302 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200303 return expr
304 if self.tok != ',':
305 raise QAPISchemaError(self, 'Expected "," or "]"')
306 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500307
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200308 def get_expr(self, nested):
309 if self.tok != '{' and not nested:
310 raise QAPISchemaError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200311 if self.tok == '{':
312 self.accept()
313 expr = self.get_members()
314 elif self.tok == '[':
315 self.accept()
316 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600317 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200318 expr = self.val
319 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200320 else:
321 raise QAPISchemaError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200322 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200323
Markus Armbruster00e4b282015-06-10 10:04:36 +0200324#
325# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200326# TODO fold into QAPISchema
327# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200328#
329
Eric Blake437db252015-09-29 16:21:02 -0600330
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800331def find_base_fields(base):
332 base_struct_define = find_struct(base)
333 if not base_struct_define:
334 return None
335 return base_struct_define['data']
336
Eric Blake437db252015-09-29 16:21:02 -0600337
Eric Blake811d04f2015-05-04 09:05:10 -0600338# Return the qtype of an alternate branch, or None on error.
339def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600340 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600341 return builtin_types[qapi_type]
342 elif find_struct(qapi_type):
343 return "QTYPE_QDICT"
344 elif find_enum(qapi_type):
345 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600346 elif find_union(qapi_type):
347 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600348 return None
349
Eric Blake437db252015-09-29 16:21:02 -0600350
Wenchao Xiabceae762014-03-06 17:08:56 -0800351# Return the discriminator enum define if discriminator is specified as an
352# enum type, otherwise return None.
353def discriminator_find_enum_define(expr):
354 base = expr.get('base')
355 discriminator = expr.get('discriminator')
356
357 if not (discriminator and base):
358 return None
359
360 base_fields = find_base_fields(base)
361 if not base_fields:
362 return None
363
364 discriminator_type = base_fields.get(discriminator)
365 if not discriminator_type:
366 return None
367
368 return find_enum(discriminator_type)
369
Eric Blake437db252015-09-29 16:21:02 -0600370
Eric Blake59a92fe2015-11-18 01:52:56 -0700371# Names must be letters, numbers, -, and _. They must start with letter,
372# except for downstream extensions which must start with __RFQDN_.
373# Dots are only valid in the downstream extension prefix.
374valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
375 '[a-zA-Z][a-zA-Z0-9_-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600376
377
378def check_name(expr_info, source, name, allow_optional=False,
379 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600380 global valid_name
381 membername = name
382
383 if not isinstance(name, str):
384 raise QAPIExprError(expr_info,
385 "%s requires a string name" % source)
386 if name.startswith('*'):
387 membername = name[1:]
388 if not allow_optional:
389 raise QAPIExprError(expr_info,
390 "%s does not allow optional name '%s'"
391 % (source, name))
392 # Enum members can start with a digit, because the generated C
393 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700394 if enum_member and membername[0].isdigit():
395 membername = 'D' + membername
Eric Blake9fb081e2015-10-26 16:34:44 -0600396 # Reserve the entire 'q_' namespace for c_name()
397 if not valid_name.match(membername) or \
398 c_name(membername, False).startswith('q_'):
Eric Blakec9e0a792015-05-04 09:05:22 -0600399 raise QAPIExprError(expr_info,
400 "%s uses invalid name '%s'" % (source, name))
401
Eric Blake437db252015-09-29 16:21:02 -0600402
403def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200404 global all_names
405 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200406 # FIXME should reject names that differ only in '_' vs. '.'
407 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200408 if name in all_names:
409 raise QAPIExprError(info,
410 "%s '%s' is already defined"
411 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600412 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200413 raise QAPIExprError(info,
Eric Blake255960d2015-10-26 16:34:43 -0600414 "%s '%s' should not end in '%s'"
415 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200416 all_names[name] = meta
417
Eric Blake437db252015-09-29 16:21:02 -0600418
Markus Armbruster00e4b282015-06-10 10:04:36 +0200419def add_struct(definition, info):
420 global struct_types
421 name = definition['struct']
422 add_name(name, info, 'struct')
423 struct_types.append(definition)
424
Eric Blake437db252015-09-29 16:21:02 -0600425
Markus Armbruster00e4b282015-06-10 10:04:36 +0200426def find_struct(name):
427 global struct_types
428 for struct in struct_types:
429 if struct['struct'] == name:
430 return struct
431 return None
432
Eric Blake437db252015-09-29 16:21:02 -0600433
Markus Armbruster00e4b282015-06-10 10:04:36 +0200434def add_union(definition, info):
435 global union_types
436 name = definition['union']
437 add_name(name, info, 'union')
438 union_types.append(definition)
439
Eric Blake437db252015-09-29 16:21:02 -0600440
Markus Armbruster00e4b282015-06-10 10:04:36 +0200441def find_union(name):
442 global union_types
443 for union in union_types:
444 if union['union'] == name:
445 return union
446 return None
447
Eric Blake437db252015-09-29 16:21:02 -0600448
449def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200450 global enum_types
451 add_name(name, info, 'enum', implicit)
452 enum_types.append({"enum_name": name, "enum_values": enum_values})
453
Eric Blake437db252015-09-29 16:21:02 -0600454
Markus Armbruster00e4b282015-06-10 10:04:36 +0200455def find_enum(name):
456 global enum_types
457 for enum in enum_types:
458 if enum['enum_name'] == name:
459 return enum
460 return None
461
Markus Armbruster00e4b282015-06-10 10:04:36 +0200462
Eric Blake437db252015-09-29 16:21:02 -0600463def is_enum(name):
464 return find_enum(name) is not None
465
466
467def check_type(expr_info, source, value, allow_array=False,
468 allow_dict=False, allow_optional=False,
469 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600470 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600471
472 if value is None:
473 return
474
Eric Blakedd883c62015-05-04 09:05:21 -0600475 # Check if array type for value is okay
476 if isinstance(value, list):
477 if not allow_array:
478 raise QAPIExprError(expr_info,
479 "%s cannot be an array" % source)
480 if len(value) != 1 or not isinstance(value[0], str):
481 raise QAPIExprError(expr_info,
482 "%s: array type must contain single type name"
483 % source)
484 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600485
486 # Check if type name for value is okay
487 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600488 if value not in all_names:
Eric Blakedd883c62015-05-04 09:05:21 -0600489 raise QAPIExprError(expr_info,
490 "%s uses unknown type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200491 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600492 if not all_names[value] in allow_metas:
493 raise QAPIExprError(expr_info,
494 "%s cannot use %s type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200495 % (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600496 return
497
Eric Blakedd883c62015-05-04 09:05:21 -0600498 if not allow_dict:
499 raise QAPIExprError(expr_info,
500 "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200501
502 if not isinstance(value, OrderedDict):
503 raise QAPIExprError(expr_info,
504 "%s should be a dictionary or type name" % source)
505
506 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600507 for (key, arg) in value.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600508 check_name(expr_info, "Member of %s" % source, key,
509 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600510 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Eric Blake9fb081e2015-10-26 16:34:44 -0600511 raise QAPIExprError(expr_info,
512 "Member of %s uses reserved name '%s'"
513 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600514 # Todo: allow dictionaries to represent default values of
515 # an optional argument.
Eric Blakedd883c62015-05-04 09:05:21 -0600516 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200517 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600518 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600519 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600520
Eric Blake437db252015-09-29 16:21:02 -0600521
522def check_member_clash(expr_info, base_name, data, source=""):
Eric Blakeff55d722015-05-04 09:05:37 -0600523 base = find_struct(base_name)
524 assert base
525 base_members = base['data']
526 for key in data.keys():
527 if key.startswith('*'):
528 key = key[1:]
529 if key in base_members or "*" + key in base_members:
530 raise QAPIExprError(expr_info,
531 "Member name '%s'%s clashes with base '%s'"
532 % (key, source, base_name))
533 if base.get('base'):
534 check_member_clash(expr_info, base['base'], data, source)
535
Eric Blake437db252015-09-29 16:21:02 -0600536
Eric Blakedd883c62015-05-04 09:05:21 -0600537def check_command(expr, expr_info):
538 name = expr['command']
Eric Blake2cbf0992015-05-04 09:05:24 -0600539
Eric Blakedd883c62015-05-04 09:05:21 -0600540 check_type(expr_info, "'data' for command '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600541 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200542 allow_metas=['struct'])
Eric Blake10d4d992015-05-04 09:05:23 -0600543 returns_meta = ['union', 'struct']
544 if name in returns_whitelist:
545 returns_meta += ['built-in', 'alternate', 'enum']
Eric Blakedd883c62015-05-04 09:05:21 -0600546 check_type(expr_info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200547 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200548 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600549
Eric Blake437db252015-09-29 16:21:02 -0600550
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200551def check_event(expr, expr_info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600552 global events
553 name = expr['event']
Eric Blake4dc2e692015-05-04 09:05:17 -0600554
Eric Blake4dc2e692015-05-04 09:05:17 -0600555 events.append(name)
Eric Blakedd883c62015-05-04 09:05:21 -0600556 check_type(expr_info, "'data' for event '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600557 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster315932b2015-07-01 10:12:24 +0200558 allow_metas=['struct'])
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200559
Eric Blake437db252015-09-29 16:21:02 -0600560
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800561def check_union(expr, expr_info):
562 name = expr['union']
563 base = expr.get('base')
564 discriminator = expr.get('discriminator')
565 members = expr['data']
Eric Blake04e06392015-11-18 01:52:58 -0700566 values = {}
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800567
Eric Blake811d04f2015-05-04 09:05:10 -0600568 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600569
570 # With no discriminator it is a simple union.
571 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600572 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600573 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600574 if base is not None:
575 raise QAPIExprError(expr_info,
Eric Blake811d04f2015-05-04 09:05:10 -0600576 "Simple union '%s' must not have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600577 % name)
578
579 # Else, it's a flat union.
580 else:
581 # The object must have a string member 'base'.
Eric Blake376863e2015-09-29 16:21:07 -0600582 check_type(expr_info, "'base' for union '%s'" % name,
583 base, allow_metas=['struct'])
584 if not base:
Eric Blake44bd1272015-05-04 09:05:08 -0600585 raise QAPIExprError(expr_info,
Eric Blake376863e2015-09-29 16:21:07 -0600586 "Flat union '%s' must have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600587 % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800588 base_fields = find_base_fields(base)
Eric Blake376863e2015-09-29 16:21:07 -0600589 assert base_fields
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800590
Eric Blakec9e0a792015-05-04 09:05:22 -0600591 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600592 # member of the base struct.
Eric Blakec9e0a792015-05-04 09:05:22 -0600593 check_name(expr_info, "Discriminator of flat union '%s'" % name,
594 discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800595 discriminator_type = base_fields.get(discriminator)
596 if not discriminator_type:
597 raise QAPIExprError(expr_info,
598 "Discriminator '%s' is not a member of base "
Eric Blakefd41dd42015-05-04 09:05:25 -0600599 "struct '%s'"
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800600 % (discriminator, base))
601 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600602 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800603 # Do not allow string discriminator
604 if not enum_define:
605 raise QAPIExprError(expr_info,
606 "Discriminator '%s' must be of enumeration "
607 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800608
609 # Check every branch
610 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600611 check_name(expr_info, "Member of union '%s'" % name, key)
612
Eric Blakedd883c62015-05-04 09:05:21 -0600613 # Each value must name a known type; furthermore, in flat unions,
Eric Blakeff55d722015-05-04 09:05:37 -0600614 # branches must be a struct with no overlapping member names
Eric Blakedd883c62015-05-04 09:05:21 -0600615 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200616 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakeff55d722015-05-04 09:05:37 -0600617 if base:
618 branch_struct = find_struct(value)
619 assert branch_struct
620 check_member_clash(expr_info, base, branch_struct['data'],
621 " of branch '%s'" % key)
Eric Blakedd883c62015-05-04 09:05:21 -0600622
Eric Blake44bd1272015-05-04 09:05:08 -0600623 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700624 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600625 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600626 if key not in enum_define['enum_values']:
Eric Blake44bd1272015-05-04 09:05:08 -0600627 raise QAPIExprError(expr_info,
628 "Discriminator value '%s' is not found in "
629 "enum '%s'" %
630 (key, enum_define["enum_name"]))
631
632 # Otherwise, check for conflicts in the generated enum
633 else:
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600634 c_key = camel_to_upper(key)
Eric Blake44bd1272015-05-04 09:05:08 -0600635 if c_key in values:
636 raise QAPIExprError(expr_info,
637 "Union '%s' member '%s' clashes with '%s'"
638 % (name, key, values[c_key]))
639 values[c_key] = key
640
Eric Blake437db252015-09-29 16:21:02 -0600641
Eric Blake811d04f2015-05-04 09:05:10 -0600642def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600643 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600644 members = expr['data']
Eric Blake04e06392015-11-18 01:52:58 -0700645 values = {}
Eric Blake811d04f2015-05-04 09:05:10 -0600646 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600647
Eric Blake811d04f2015-05-04 09:05:10 -0600648 # Check every branch
649 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600650 check_name(expr_info, "Member of alternate '%s'" % name, key)
651
Eric Blake0426d532015-12-01 22:20:48 -0700652 # Check for conflicts in the branch names
653 c_key = c_name(key)
Eric Blake811d04f2015-05-04 09:05:10 -0600654 if c_key in values:
655 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600656 "Alternate '%s' member '%s' clashes with '%s'"
657 % (name, key, values[c_key]))
Eric Blake811d04f2015-05-04 09:05:10 -0600658 values[c_key] = key
659
660 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600661 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
662 value,
663 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600664 qtype = find_alternate_member_qtype(value)
Eric Blakedd883c62015-05-04 09:05:21 -0600665 assert qtype
Eric Blake811d04f2015-05-04 09:05:10 -0600666 if qtype in types_seen:
667 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600668 "Alternate '%s' member '%s' can't "
Eric Blake811d04f2015-05-04 09:05:10 -0600669 "be distinguished from member '%s'"
670 % (name, key, types_seen[qtype]))
671 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800672
Eric Blake437db252015-09-29 16:21:02 -0600673
Eric Blakecf393592015-05-04 09:05:04 -0600674def check_enum(expr, expr_info):
675 name = expr['enum']
676 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100677 prefix = expr.get('prefix')
Eric Blake04e06392015-11-18 01:52:58 -0700678 values = {}
Eric Blakecf393592015-05-04 09:05:04 -0600679
680 if not isinstance(members, list):
681 raise QAPIExprError(expr_info,
682 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100683 if prefix is not None and not isinstance(prefix, str):
684 raise QAPIExprError(expr_info,
685 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600686 for member in members:
Eric Blake437db252015-09-29 16:21:02 -0600687 check_name(expr_info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600688 enum_member=True)
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600689 key = camel_to_upper(member)
Eric Blakecf393592015-05-04 09:05:04 -0600690 if key in values:
691 raise QAPIExprError(expr_info,
692 "Enum '%s' member '%s' clashes with '%s'"
693 % (name, member, values[key]))
694 values[key] = member
695
Eric Blake437db252015-09-29 16:21:02 -0600696
Eric Blakedd883c62015-05-04 09:05:21 -0600697def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600698 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600699 members = expr['data']
700
Eric Blakefd41dd42015-05-04 09:05:25 -0600701 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600702 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600703 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600704 allow_metas=['struct'])
Eric Blakeff55d722015-05-04 09:05:37 -0600705 if expr.get('base'):
706 check_member_clash(expr_info, expr['base'], expr['data'])
Eric Blakedd883c62015-05-04 09:05:21 -0600707
Eric Blake437db252015-09-29 16:21:02 -0600708
Eric Blake0545f6b2015-05-04 09:05:15 -0600709def check_keys(expr_elem, meta, required, optional=[]):
710 expr = expr_elem['expr']
711 info = expr_elem['info']
712 name = expr[meta]
713 if not isinstance(name, str):
714 raise QAPIExprError(info,
715 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600716 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600717 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600718 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600719 raise QAPIExprError(info,
720 "Unknown key '%s' in %s '%s'"
721 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600722 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600723 raise QAPIExprError(info,
724 "'%s' of %s '%s' should only use false value"
725 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600726 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600727 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600728 raise QAPIExprError(info,
729 "Key '%s' is missing from %s '%s'"
730 % (key, meta, name))
731
Eric Blake437db252015-09-29 16:21:02 -0600732
Markus Armbruster4d076d62015-06-10 08:55:21 +0200733def check_exprs(exprs):
734 global all_names
735
736 # Learn the types and check for valid expression keys
737 for builtin in builtin_types.keys():
738 all_names[builtin] = 'built-in'
739 for expr_elem in exprs:
740 expr = expr_elem['expr']
741 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600742 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100743 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200744 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600745 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200746 check_keys(expr_elem, 'union', ['data'],
747 ['base', 'discriminator'])
748 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600749 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200750 check_keys(expr_elem, 'alternate', ['data'])
751 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600752 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200753 check_keys(expr_elem, 'struct', ['data'], ['base'])
754 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600755 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200756 check_keys(expr_elem, 'command', [],
757 ['data', 'returns', 'gen', 'success-response'])
758 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600759 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200760 check_keys(expr_elem, 'event', [], ['data'])
761 add_name(expr['event'], info, 'event')
762 else:
763 raise QAPIExprError(expr_elem['info'],
764 "Expression is missing metatype")
765
766 # Try again for hidden UnionKind enum
767 for expr_elem in exprs:
768 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600769 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200770 if not discriminator_find_enum_define(expr):
771 add_enum('%sKind' % expr['union'], expr_elem['info'],
772 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600773 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200774 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
775 implicit=True)
776
777 # Validate that exprs make sense
778 for expr_elem in exprs:
779 expr = expr_elem['expr']
780 info = expr_elem['info']
781
Eric Blake437db252015-09-29 16:21:02 -0600782 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200783 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600784 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200785 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600786 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200787 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600788 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200789 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600790 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200791 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600792 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200793 check_event(expr, info)
794 else:
795 assert False, 'unexpected meta type'
796
Markus Armbrusterac882192015-09-16 13:06:05 +0200797 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600798
Markus Armbrusterac882192015-09-16 13:06:05 +0200799
800#
801# Schema compiler frontend
802#
803
804class QAPISchemaEntity(object):
805 def __init__(self, name, info):
806 assert isinstance(name, str)
807 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -0600808 # For explicitly defined entities, info points to the (explicit)
809 # definition. For builtins (and their arrays), info is None.
810 # For implicitly defined entities, info points to a place that
811 # triggered the implicit definition (there may be more than one
812 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +0200813 self.info = info
814
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200815 def c_name(self):
816 return c_name(self.name)
817
Markus Armbrusterac882192015-09-16 13:06:05 +0200818 def check(self, schema):
819 pass
820
Eric Blake49823c42015-10-12 22:22:27 -0600821 def is_implicit(self):
822 return not self.info
823
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200824 def visit(self, visitor):
825 pass
826
827
828class QAPISchemaVisitor(object):
829 def visit_begin(self, schema):
830 pass
831
832 def visit_end(self):
833 pass
834
Eric Blake25a0d9c2015-10-12 22:22:21 -0600835 def visit_needed(self, entity):
836 # Default to visiting everything
837 return True
838
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200839 def visit_builtin_type(self, name, info, json_type):
840 pass
841
842 def visit_enum_type(self, name, info, values, prefix):
843 pass
844
845 def visit_array_type(self, name, info, element_type):
846 pass
847
848 def visit_object_type(self, name, info, base, members, variants):
849 pass
850
Markus Armbruster39a18152015-09-16 13:06:28 +0200851 def visit_object_type_flat(self, name, info, members, variants):
852 pass
853
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200854 def visit_alternate_type(self, name, info, variants):
855 pass
856
857 def visit_command(self, name, info, arg_type, ret_type,
858 gen, success_response):
859 pass
860
861 def visit_event(self, name, info, arg_type):
862 pass
863
Markus Armbrusterac882192015-09-16 13:06:05 +0200864
865class QAPISchemaType(QAPISchemaEntity):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200866 def c_type(self, is_param=False):
867 return c_name(self.name) + pointer_suffix
868
869 def c_null(self):
870 return 'NULL'
871
872 def json_type(self):
873 pass
874
875 def alternate_qtype(self):
876 json2qtype = {
877 'string': 'QTYPE_QSTRING',
878 'number': 'QTYPE_QFLOAT',
879 'int': 'QTYPE_QINT',
880 'boolean': 'QTYPE_QBOOL',
881 'object': 'QTYPE_QDICT'
882 }
883 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200884
885
886class QAPISchemaBuiltinType(QAPISchemaType):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200887 def __init__(self, name, json_type, c_type, c_null):
Markus Armbrusterac882192015-09-16 13:06:05 +0200888 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200889 assert not c_type or isinstance(c_type, str)
890 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
891 'value')
892 self._json_type_name = json_type
893 self._c_type_name = c_type
894 self._c_null_val = c_null
895
896 def c_name(self):
897 return self.name
898
899 def c_type(self, is_param=False):
900 if is_param and self.name == 'str':
901 return 'const ' + self._c_type_name
902 return self._c_type_name
903
904 def c_null(self):
905 return self._c_null_val
906
907 def json_type(self):
908 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200909
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200910 def visit(self, visitor):
911 visitor.visit_builtin_type(self.name, self.info, self.json_type())
912
Markus Armbrusterac882192015-09-16 13:06:05 +0200913
914class QAPISchemaEnumType(QAPISchemaType):
915 def __init__(self, name, info, values, prefix):
916 QAPISchemaType.__init__(self, name, info)
917 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -0700918 assert isinstance(v, QAPISchemaMember)
919 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200920 assert prefix is None or isinstance(prefix, str)
921 self.values = values
922 self.prefix = prefix
923
924 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -0700925 seen = {}
926 for v in self.values:
927 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200928
Eric Blake99df5282015-10-12 22:22:32 -0600929 def is_implicit(self):
930 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -0600931 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -0600932
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200933 def c_type(self, is_param=False):
934 return c_name(self.name)
935
Eric Blake93bda4d2015-12-01 22:20:55 -0700936 def member_names(self):
937 return [v.name for v in self.values]
938
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200939 def c_null(self):
Eric Blake93bda4d2015-12-01 22:20:55 -0700940 return c_enum_const(self.name, (self.member_names() + ['_MAX'])[0],
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200941 self.prefix)
942
943 def json_type(self):
944 return 'string'
945
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200946 def visit(self, visitor):
947 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -0700948 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200949
Markus Armbrusterac882192015-09-16 13:06:05 +0200950
951class QAPISchemaArrayType(QAPISchemaType):
952 def __init__(self, name, info, element_type):
953 QAPISchemaType.__init__(self, name, info)
954 assert isinstance(element_type, str)
955 self._element_type_name = element_type
956 self.element_type = None
957
958 def check(self, schema):
959 self.element_type = schema.lookup_type(self._element_type_name)
960 assert self.element_type
961
Eric Blake99df5282015-10-12 22:22:32 -0600962 def is_implicit(self):
963 return True
964
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200965 def json_type(self):
966 return 'array'
967
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200968 def visit(self, visitor):
969 visitor.visit_array_type(self.name, self.info, self.element_type)
970
Markus Armbrusterac882192015-09-16 13:06:05 +0200971
972class QAPISchemaObjectType(QAPISchemaType):
973 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -0700974 # struct has local_members, optional base, and no variants
975 # flat union has base, variants, and no local_members
976 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +0200977 QAPISchemaType.__init__(self, name, info)
978 assert base is None or isinstance(base, str)
979 for m in local_members:
980 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -0700981 m.set_owner(name)
982 if variants is not None:
983 assert isinstance(variants, QAPISchemaObjectTypeVariants)
984 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200985 self._base_name = base
986 self.base = None
987 self.local_members = local_members
988 self.variants = variants
989 self.members = None
990
991 def check(self, schema):
992 assert self.members is not False # not running in cycles
993 if self.members:
994 return
995 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -0700996 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +0200997 if self._base_name:
998 self.base = schema.lookup_type(self._base_name)
999 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +02001000 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001001 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001002 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001003 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -07001004 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001005 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +02001006 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001007 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -07001008 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -07001009 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001010
Eric Blake27b60ab2015-11-18 01:52:51 -07001011 # Check that the members of this type do not cause duplicate JSON fields,
1012 # and update seen to track the members seen so far. Report any errors
1013 # on behalf of info, which is not necessarily self.info
1014 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -07001015 assert not self.variants # not implemented
1016 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -07001017 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -07001018
Eric Blake99df5282015-10-12 22:22:32 -06001019 def is_implicit(self):
1020 # See QAPISchema._make_implicit_object_type()
1021 return self.name[0] == ':'
1022
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001023 def c_name(self):
Eric Blake49823c42015-10-12 22:22:27 -06001024 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001025 return QAPISchemaType.c_name(self)
1026
1027 def c_type(self, is_param=False):
Eric Blake49823c42015-10-12 22:22:27 -06001028 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001029 return QAPISchemaType.c_type(self)
1030
1031 def json_type(self):
1032 return 'object'
1033
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001034 def visit(self, visitor):
1035 visitor.visit_object_type(self.name, self.info,
1036 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001037 visitor.visit_object_type_flat(self.name, self.info,
1038 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001039
Markus Armbrusterac882192015-09-16 13:06:05 +02001040
Eric Blaked44f9ac2015-12-01 22:20:54 -07001041class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001042 role = 'member'
1043
Eric Blaked44f9ac2015-12-01 22:20:54 -07001044 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001045 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001046 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001047 self.owner = None
1048
1049 def set_owner(self, name):
1050 assert not self.owner
1051 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001052
Eric Blake27b60ab2015-11-18 01:52:51 -07001053 def check_clash(self, info, seen):
1054 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001055 if cname.lower() != cname and self.owner not in case_whitelist:
1056 raise QAPIExprError(info,
1057 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001058 if cname in seen:
1059 raise QAPIExprError(info,
1060 "%s collides with %s"
1061 % (self.describe(), seen[cname].describe()))
1062 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001063
Eric Blake88d4ef82015-11-18 01:52:50 -07001064 def _pretty_owner(self):
1065 owner = self.owner
1066 if owner.startswith(':obj-'):
1067 # See QAPISchema._make_implicit_object_type() - reverse the
1068 # mapping there to create a nice human-readable description
1069 owner = owner[5:]
1070 if owner.endswith('-arg'):
1071 return '(parameter of %s)' % owner[:-4]
1072 else:
1073 assert owner.endswith('-wrapper')
1074 # Unreachable and not implemented
1075 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001076 if owner.endswith('Kind'):
1077 # See QAPISchema._make_implicit_enum_type()
1078 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001079 return '(%s of %s)' % (self.role, owner)
1080
1081 def describe(self):
1082 return "'%s' %s" % (self.name, self._pretty_owner())
1083
Markus Armbrusterac882192015-09-16 13:06:05 +02001084
Eric Blaked44f9ac2015-12-01 22:20:54 -07001085class QAPISchemaObjectTypeMember(QAPISchemaMember):
1086 def __init__(self, name, typ, optional):
1087 QAPISchemaMember.__init__(self, name)
1088 assert isinstance(typ, str)
1089 assert isinstance(optional, bool)
1090 self._type_name = typ
1091 self.type = None
1092 self.optional = optional
1093
1094 def check(self, schema):
1095 assert self.owner
1096 self.type = schema.lookup_type(self._type_name)
1097 assert self.type
1098
1099
Markus Armbrusterac882192015-09-16 13:06:05 +02001100class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001101 def __init__(self, tag_name, tag_member, variants):
1102 # Flat unions pass tag_name but not tag_member.
1103 # Simple unions and alternates pass tag_member but not tag_name.
1104 # After check(), tag_member is always set, and tag_name remains
1105 # a reliable witness of being used by a flat union.
1106 assert bool(tag_member) != bool(tag_name)
1107 assert (isinstance(tag_name, str) or
1108 isinstance(tag_member, QAPISchemaObjectTypeMember))
Markus Armbrusterac882192015-09-16 13:06:05 +02001109 for v in variants:
1110 assert isinstance(v, QAPISchemaObjectTypeVariant)
1111 self.tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001112 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001113 self.variants = variants
1114
Eric Blake88d4ef82015-11-18 01:52:50 -07001115 def set_owner(self, name):
1116 for v in self.variants:
1117 v.set_owner(name)
1118
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001119 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001120 if not self.tag_member: # flat union
Eric Blake27b60ab2015-11-18 01:52:51 -07001121 self.tag_member = seen[c_name(self.tag_name)]
1122 assert self.tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001123 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1124 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001125 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001126 # Union names must match enum values; alternate names are
1127 # checked separately. Use 'seen' to tell the two apart.
1128 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001129 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001130 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001131 v.type.check(schema)
1132
Eric Blake27b60ab2015-11-18 01:52:51 -07001133 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001134 for v in self.variants:
1135 # Reset seen map for each variant, since qapi names from one
1136 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001137 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001138 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001139
Eric Blake437db252015-09-29 16:21:02 -06001140
Markus Armbrusterac882192015-09-16 13:06:05 +02001141class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001142 role = 'branch'
1143
Markus Armbrusterac882192015-09-16 13:06:05 +02001144 def __init__(self, name, typ):
1145 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1146
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001147 # This function exists to support ugly simple union special cases
1148 # TODO get rid of them, and drop the function
1149 def simple_union_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001150 if (self.type.is_implicit() and
1151 isinstance(self.type, QAPISchemaObjectType)):
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001152 assert len(self.type.members) == 1
1153 assert not self.type.variants
1154 return self.type.members[0].type
1155 return None
1156
Markus Armbrusterac882192015-09-16 13:06:05 +02001157
1158class QAPISchemaAlternateType(QAPISchemaType):
1159 def __init__(self, name, info, variants):
1160 QAPISchemaType.__init__(self, name, info)
1161 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1162 assert not variants.tag_name
Eric Blake88d4ef82015-11-18 01:52:50 -07001163 variants.set_owner(name)
1164 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001165 self.variants = variants
1166
1167 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001168 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001169 # Not calling self.variants.check_clash(), because there's nothing
1170 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001171 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001172 # Alternate branch names have no relation to the tag enum values;
1173 # so we have to check for potential name collisions ourselves.
1174 seen = {}
1175 for v in self.variants.variants:
1176 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001177
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001178 def json_type(self):
1179 return 'value'
1180
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001181 def visit(self, visitor):
1182 visitor.visit_alternate_type(self.name, self.info, self.variants)
1183
Markus Armbrusterac882192015-09-16 13:06:05 +02001184
1185class QAPISchemaCommand(QAPISchemaEntity):
1186 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1187 QAPISchemaEntity.__init__(self, name, info)
1188 assert not arg_type or isinstance(arg_type, str)
1189 assert not ret_type or isinstance(ret_type, str)
1190 self._arg_type_name = arg_type
1191 self.arg_type = None
1192 self._ret_type_name = ret_type
1193 self.ret_type = None
1194 self.gen = gen
1195 self.success_response = success_response
1196
1197 def check(self, schema):
1198 if self._arg_type_name:
1199 self.arg_type = schema.lookup_type(self._arg_type_name)
1200 assert isinstance(self.arg_type, QAPISchemaObjectType)
1201 assert not self.arg_type.variants # not implemented
1202 if self._ret_type_name:
1203 self.ret_type = schema.lookup_type(self._ret_type_name)
1204 assert isinstance(self.ret_type, QAPISchemaType)
1205
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001206 def visit(self, visitor):
1207 visitor.visit_command(self.name, self.info,
1208 self.arg_type, self.ret_type,
1209 self.gen, self.success_response)
1210
Markus Armbrusterac882192015-09-16 13:06:05 +02001211
1212class QAPISchemaEvent(QAPISchemaEntity):
1213 def __init__(self, name, info, arg_type):
1214 QAPISchemaEntity.__init__(self, name, info)
1215 assert not arg_type or isinstance(arg_type, str)
1216 self._arg_type_name = arg_type
1217 self.arg_type = None
1218
1219 def check(self, schema):
1220 if self._arg_type_name:
1221 self.arg_type = schema.lookup_type(self._arg_type_name)
1222 assert isinstance(self.arg_type, QAPISchemaObjectType)
1223 assert not self.arg_type.variants # not implemented
1224
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001225 def visit(self, visitor):
1226 visitor.visit_event(self.name, self.info, self.arg_type)
1227
Markus Armbrusterac882192015-09-16 13:06:05 +02001228
1229class QAPISchema(object):
1230 def __init__(self, fname):
1231 try:
1232 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001233 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001234 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001235 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001236 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001237 self._def_exprs()
1238 self.check()
Markus Armbrusterac882192015-09-16 13:06:05 +02001239 except (QAPISchemaError, QAPIExprError), err:
1240 print >>sys.stderr, err
1241 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001242
Markus Armbrusterac882192015-09-16 13:06:05 +02001243 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001244 # Only the predefined types are allowed to not have info
1245 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001246 assert ent.name not in self._entity_dict
1247 self._entity_dict[ent.name] = ent
1248
1249 def lookup_entity(self, name, typ=None):
1250 ent = self._entity_dict.get(name)
1251 if typ and not isinstance(ent, typ):
1252 return None
1253 return ent
1254
1255 def lookup_type(self, name):
1256 return self.lookup_entity(name, QAPISchemaType)
1257
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001258 def _def_builtin_type(self, name, json_type, c_type, c_null):
1259 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1260 c_type, c_null))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001261 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1262 # qapi-types.h from a single .c, all arrays of builtins must be
1263 # declared in the first file whether or not they are used. Nicer
1264 # would be to use lazy instantiation, while figuring out how to
1265 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001266 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001267
1268 def _def_predefineds(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001269 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1270 ('number', 'number', 'double', '0'),
1271 ('int', 'int', 'int64_t', '0'),
1272 ('int8', 'int', 'int8_t', '0'),
1273 ('int16', 'int', 'int16_t', '0'),
1274 ('int32', 'int', 'int32_t', '0'),
1275 ('int64', 'int', 'int64_t', '0'),
1276 ('uint8', 'int', 'uint8_t', '0'),
1277 ('uint16', 'int', 'uint16_t', '0'),
1278 ('uint32', 'int', 'uint32_t', '0'),
1279 ('uint64', 'int', 'uint64_t', '0'),
1280 ('size', 'int', 'uint64_t', '0'),
1281 ('bool', 'boolean', 'bool', 'false'),
Markus Armbruster28770e02015-09-16 13:06:24 +02001282 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001283 self._def_builtin_type(*t)
Markus Armbruster39a18152015-09-16 13:06:28 +02001284 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1285 [], None)
1286 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001287 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1288 'qstring', 'qdict', 'qlist',
1289 'qfloat', 'qbool'])
1290 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001291 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001292
Eric Blake93bda4d2015-12-01 22:20:55 -07001293 def _make_enum_members(self, values):
1294 return [QAPISchemaMember(v) for v in values]
1295
Eric Blake99df5282015-10-12 22:22:32 -06001296 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001297 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001298 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001299 self._def_entity(QAPISchemaEnumType(
1300 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001301 return name
1302
Eric Blake99df5282015-10-12 22:22:32 -06001303 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001304 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001305 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001306 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001307 return name
1308
Eric Blake99df5282015-10-12 22:22:32 -06001309 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001310 if not members:
1311 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001312 # See also QAPISchemaObjectTypeMember._pretty_owner()
Markus Armbrusterac882192015-09-16 13:06:05 +02001313 name = ':obj-%s-%s' % (name, role)
1314 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001315 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001316 members, None))
1317 return name
1318
1319 def _def_enum_type(self, expr, info):
1320 name = expr['enum']
1321 data = expr['data']
1322 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001323 self._def_entity(QAPISchemaEnumType(
1324 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001325
Eric Blake99df5282015-10-12 22:22:32 -06001326 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001327 optional = False
1328 if name.startswith('*'):
1329 name = name[1:]
1330 optional = True
1331 if isinstance(typ, list):
1332 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001333 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001334 return QAPISchemaObjectTypeMember(name, typ, optional)
1335
Eric Blake99df5282015-10-12 22:22:32 -06001336 def _make_members(self, data, info):
1337 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001338 for (key, value) in data.iteritems()]
1339
1340 def _def_struct_type(self, expr, info):
1341 name = expr['struct']
1342 base = expr.get('base')
1343 data = expr['data']
1344 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001345 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001346 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001347
1348 def _make_variant(self, case, typ):
1349 return QAPISchemaObjectTypeVariant(case, typ)
1350
Eric Blake99df5282015-10-12 22:22:32 -06001351 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001352 if isinstance(typ, list):
1353 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001354 typ = self._make_array_type(typ[0], info)
1355 typ = self._make_implicit_object_type(
1356 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001357 return QAPISchemaObjectTypeVariant(case, typ)
1358
Markus Armbrusterac882192015-09-16 13:06:05 +02001359 def _def_union_type(self, expr, info):
1360 name = expr['union']
1361 data = expr['data']
1362 base = expr.get('base')
1363 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001364 tag_member = None
Markus Armbrusterac882192015-09-16 13:06:05 +02001365 if tag_name:
1366 variants = [self._make_variant(key, value)
1367 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001368 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001369 else:
Eric Blake99df5282015-10-12 22:22:32 -06001370 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001371 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001372 typ = self._make_implicit_enum_type(name, info,
1373 [v.name for v in variants])
1374 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001375 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001376 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001377 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001378 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001379 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001380 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001381
1382 def _def_alternate_type(self, expr, info):
1383 name = expr['alternate']
1384 data = expr['data']
1385 variants = [self._make_variant(key, value)
1386 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001387 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001388 self._def_entity(
1389 QAPISchemaAlternateType(name, info,
1390 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001391 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001392 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001393
1394 def _def_command(self, expr, info):
1395 name = expr['command']
1396 data = expr.get('data')
1397 rets = expr.get('returns')
1398 gen = expr.get('gen', True)
1399 success_response = expr.get('success-response', True)
1400 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001401 data = self._make_implicit_object_type(
1402 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001403 if isinstance(rets, list):
1404 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001405 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001406 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1407 success_response))
1408
1409 def _def_event(self, expr, info):
1410 name = expr['event']
1411 data = expr.get('data')
1412 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001413 data = self._make_implicit_object_type(
1414 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001415 self._def_entity(QAPISchemaEvent(name, info, data))
1416
1417 def _def_exprs(self):
1418 for expr_elem in self.exprs:
1419 expr = expr_elem['expr']
1420 info = expr_elem['info']
1421 if 'enum' in expr:
1422 self._def_enum_type(expr, info)
1423 elif 'struct' in expr:
1424 self._def_struct_type(expr, info)
1425 elif 'union' in expr:
1426 self._def_union_type(expr, info)
1427 elif 'alternate' in expr:
1428 self._def_alternate_type(expr, info)
1429 elif 'command' in expr:
1430 self._def_command(expr, info)
1431 elif 'event' in expr:
1432 self._def_event(expr, info)
1433 else:
1434 assert False
1435
1436 def check(self):
1437 for ent in self._entity_dict.values():
1438 ent.check(self)
1439
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001440 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001441 visitor.visit_begin(self)
1442 for (name, entity) in sorted(self._entity_dict.items()):
1443 if visitor.visit_needed(entity):
1444 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001445 visitor.visit_end()
1446
Markus Armbruster2caba362013-07-27 17:41:56 +02001447
Markus Armbruster00e4b282015-06-10 10:04:36 +02001448#
1449# Code generation helpers
1450#
1451
Michael Roth0f923be2011-07-19 14:50:39 -05001452def camel_case(name):
1453 new_name = ''
1454 first = True
1455 for ch in name:
1456 if ch in ['_', '-']:
1457 first = True
1458 elif first:
1459 new_name += ch.upper()
1460 first = False
1461 else:
1462 new_name += ch.lower()
1463 return new_name
1464
Eric Blake437db252015-09-29 16:21:02 -06001465
Markus Armbruster849bc532015-05-14 06:50:53 -06001466# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1467# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1468# ENUM24_Name -> ENUM24_NAME
1469def camel_to_upper(value):
1470 c_fun_str = c_name(value, False)
1471 if value.isupper():
1472 return c_fun_str
1473
1474 new_name = ''
1475 l = len(c_fun_str)
1476 for i in range(l):
1477 c = c_fun_str[i]
1478 # When c is upper and no "_" appears before, do more checks
1479 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001480 if i < l - 1 and c_fun_str[i + 1].islower():
1481 new_name += '_'
1482 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001483 new_name += '_'
1484 new_name += c
1485 return new_name.lstrip('_').upper()
1486
Eric Blake437db252015-09-29 16:21:02 -06001487
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001488def c_enum_const(type_name, const_name, prefix=None):
1489 if prefix is not None:
1490 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001491 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001492
Eric Blake18df5152015-05-14 06:50:48 -06001493c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001494
Eric Blake437db252015-09-29 16:21:02 -06001495
Eric Blakec6405b52015-05-14 06:50:55 -06001496# Map @name to a valid C identifier.
1497# If @protect, avoid returning certain ticklish identifiers (like
1498# C keywords) by prepending "q_".
1499#
1500# Used for converting 'name' from a 'name':'type' qapi definition
1501# into a generated struct member, as well as converting type names
1502# into substrings of a generated C function name.
1503# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1504# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001505def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001506 # ANSI X3J11/88-090, 3.1.1
1507 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001508 'default', 'do', 'double', 'else', 'enum', 'extern',
1509 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1510 'return', 'short', 'signed', 'sizeof', 'static',
1511 'struct', 'switch', 'typedef', 'union', 'unsigned',
1512 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001513 # ISO/IEC 9899:1999, 6.4.1
1514 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1515 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001516 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1517 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001518 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1519 # excluding _.*
1520 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001521 # C++ ISO/IEC 14882:2003 2.11
1522 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1523 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1524 'namespace', 'new', 'operator', 'private', 'protected',
1525 'public', 'reinterpret_cast', 'static_cast', 'template',
1526 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1527 'using', 'virtual', 'wchar_t',
1528 # alternative representations
1529 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1530 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001531 # namespace pollution:
Max Reitz8592a542013-12-20 19:28:18 +01001532 polluted_words = set(['unix', 'errno'])
Eric Blakec43567c2015-11-18 01:52:52 -07001533 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001534 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1535 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001536 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001537 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001538
Amos Kong05dfb262014-06-10 19:25:53 +08001539eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001540pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001541
Eric Blake437db252015-09-29 16:21:02 -06001542
Michael Roth0f923be2011-07-19 14:50:39 -05001543def genindent(count):
1544 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001545 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001546 ret += " "
1547 return ret
1548
1549indent_level = 0
1550
Eric Blake437db252015-09-29 16:21:02 -06001551
Michael Roth0f923be2011-07-19 14:50:39 -05001552def push_indent(indent_amount=4):
1553 global indent_level
1554 indent_level += indent_amount
1555
Eric Blake437db252015-09-29 16:21:02 -06001556
Michael Roth0f923be2011-07-19 14:50:39 -05001557def pop_indent(indent_amount=4):
1558 global indent_level
1559 indent_level -= indent_amount
1560
Eric Blake437db252015-09-29 16:21:02 -06001561
Markus Armbruster77e703b2015-06-24 19:27:32 +02001562# Generate @code with @kwds interpolated.
1563# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001564def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001565 raw = code % kwds
1566 if indent_level:
1567 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001568 # re.subn() lacks flags support before Python 2.7, use re.compile()
1569 raw = re.subn(re.compile("^.", re.MULTILINE),
1570 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001571 raw = raw[0]
1572 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001573
Eric Blake437db252015-09-29 16:21:02 -06001574
Michael Roth0f923be2011-07-19 14:50:39 -05001575def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001576 if code[0] == '\n':
1577 code = code[1:]
1578 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001579
Michael Roth0f923be2011-07-19 14:50:39 -05001580
1581def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001582 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001583
Eric Blake437db252015-09-29 16:21:02 -06001584
Michael Rothc0afa9c2013-05-10 17:46:00 -05001585def guardstart(name):
1586 return mcgen('''
1587
1588#ifndef %(name)s
1589#define %(name)s
1590
1591''',
1592 name=guardname(name))
1593
Eric Blake437db252015-09-29 16:21:02 -06001594
Michael Rothc0afa9c2013-05-10 17:46:00 -05001595def guardend(name):
1596 return mcgen('''
1597
1598#endif /* %(name)s */
1599
1600''',
1601 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001602
Eric Blake437db252015-09-29 16:21:02 -06001603
Markus Armbrustere98859a2015-09-16 13:06:16 +02001604def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001605 ret = mcgen('''
1606
Markus Armbrustere98859a2015-09-16 13:06:16 +02001607const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001608''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001609 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001610 for value in values:
1611 index = c_enum_const(name, value, prefix)
1612 ret += mcgen('''
1613 [%(index)s] = "%(value)s",
1614''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001615 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001616
Eric Blake7fb1cf12015-11-18 01:52:57 -07001617 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001618 ret += mcgen('''
1619 [%(max_index)s] = NULL,
1620};
1621''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001622 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001623 return ret
1624
Eric Blake437db252015-09-29 16:21:02 -06001625
Markus Armbrustere98859a2015-09-16 13:06:16 +02001626def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001627 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001628 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001629
1630 ret = mcgen('''
1631
1632typedef enum %(c_name)s {
1633''',
1634 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001635
1636 i = 0
1637 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001638 ret += mcgen('''
1639 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001640''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001641 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001642 i=i)
1643 i += 1
1644
Markus Armbrustere98859a2015-09-16 13:06:16 +02001645 ret += mcgen('''
1646} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001647''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001648 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001649
Markus Armbrustere98859a2015-09-16 13:06:16 +02001650 ret += mcgen('''
1651
1652extern const char *const %(c_name)s_lookup[];
1653''',
1654 c_name=c_name(name))
1655 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001656
Eric Blake437db252015-09-29 16:21:02 -06001657
Markus Armbruster03b43672015-09-16 13:06:20 +02001658def gen_params(arg_type, extra):
1659 if not arg_type:
1660 return extra
1661 assert not arg_type.variants
1662 ret = ''
1663 sep = ''
1664 for memb in arg_type.members:
1665 ret += sep
1666 sep = ', '
1667 if memb.optional:
1668 ret += 'bool has_%s, ' % c_name(memb.name)
1669 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1670 if extra:
1671 ret += sep + extra
1672 return ret
1673
Eric Blake1f353342015-09-29 16:21:13 -06001674
Eric Blake18bdbc32015-09-29 16:21:15 -06001675def gen_err_check(label='out', skiperr=False):
1676 if skiperr:
Eric Blake1f353342015-09-29 16:21:13 -06001677 return ''
1678 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001679 if (err) {
Eric Blake1f353342015-09-29 16:21:13 -06001680 goto %(label)s;
1681 }
1682''',
Eric Blake18bdbc32015-09-29 16:21:15 -06001683 label=label)
Eric Blake1f353342015-09-29 16:21:13 -06001684
1685
Eric Blake18bdbc32015-09-29 16:21:15 -06001686def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
Eric Blake82ca8e42015-09-29 16:21:14 -06001687 ret = ''
Eric Blake18bdbc32015-09-29 16:21:15 -06001688 if skiperr:
Eric Blake82ca8e42015-09-29 16:21:14 -06001689 errparg = 'NULL'
Eric Blake18bdbc32015-09-29 16:21:15 -06001690 else:
1691 errparg = '&err'
Eric Blake82ca8e42015-09-29 16:21:14 -06001692
1693 for memb in members:
1694 if memb.optional:
1695 ret += mcgen('''
Eric Blake29637a62015-12-01 22:20:53 -07001696 if (visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s")) {
Eric Blake82ca8e42015-09-29 16:21:14 -06001697''',
1698 prefix=prefix, c_name=c_name(memb.name),
1699 name=memb.name, errp=errparg)
Eric Blake82ca8e42015-09-29 16:21:14 -06001700 push_indent()
1701
1702 # Ugly: sometimes we need to cast away const
1703 if need_cast and memb.type.name == 'str':
1704 cast = '(char **)'
1705 else:
1706 cast = ''
1707
1708 ret += mcgen('''
1709 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1710''',
1711 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1712 c_name=c_name(memb.name), name=memb.name,
1713 errp=errparg)
Eric Blake18bdbc32015-09-29 16:21:15 -06001714 ret += gen_err_check(skiperr=skiperr)
Eric Blake82ca8e42015-09-29 16:21:14 -06001715
1716 if memb.optional:
1717 pop_indent()
1718 ret += mcgen('''
1719 }
1720''')
1721 return ret
1722
1723
Markus Armbruster00e4b282015-06-10 10:04:36 +02001724#
1725# Common command line parsing
1726#
1727
Eric Blake437db252015-09-29 16:21:02 -06001728
1729def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001730
1731 try:
1732 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001733 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001734 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001735 "output-dir="] + extra_long_options)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001736 except getopt.GetoptError, err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001737 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001738 sys.exit(1)
1739
1740 output_dir = ""
1741 prefix = ""
1742 do_c = False
1743 do_h = False
1744 extra_opts = []
1745
1746 for oa in opts:
1747 o, a = oa
1748 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001749 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1750 if match.end() != len(a):
1751 print >>sys.stderr, \
1752 "%s: 'funny character '%s' in argument of --prefix" \
1753 % (sys.argv[0], a[match.end()])
1754 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001755 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001756 elif o in ("-o", "--output-dir"):
1757 output_dir = a + "/"
1758 elif o in ("-c", "--source"):
1759 do_c = True
1760 elif o in ("-h", "--header"):
1761 do_h = True
1762 else:
1763 extra_opts.append(oa)
1764
1765 if not do_c and not do_h:
1766 do_c = True
1767 do_h = True
1768
Markus Armbruster16d80f62015-04-02 13:32:16 +02001769 if len(args) != 1:
1770 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001771 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001772 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001773
Markus Armbruster54414042015-06-09 16:22:45 +02001774 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001775
Markus Armbruster00e4b282015-06-10 10:04:36 +02001776#
1777# Generate output files with boilerplate
1778#
1779
Eric Blake437db252015-09-29 16:21:02 -06001780
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001781def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1782 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001783 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001784 c_file = output_dir + prefix + c_file
1785 h_file = output_dir + prefix + h_file
1786
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001787 if output_dir:
1788 try:
1789 os.makedirs(output_dir)
1790 except os.error, e:
1791 if e.errno != errno.EEXIST:
1792 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001793
1794 def maybe_open(really, name, opt):
1795 if really:
1796 return open(name, opt)
1797 else:
1798 import StringIO
1799 return StringIO.StringIO()
1800
1801 fdef = maybe_open(do_c, c_file, 'w')
1802 fdecl = maybe_open(do_h, h_file, 'w')
1803
1804 fdef.write(mcgen('''
1805/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1806%(comment)s
1807''',
Eric Blake437db252015-09-29 16:21:02 -06001808 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001809
1810 fdecl.write(mcgen('''
1811/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1812%(comment)s
1813#ifndef %(guard)s
1814#define %(guard)s
1815
1816''',
Eric Blake437db252015-09-29 16:21:02 -06001817 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001818
1819 return (fdef, fdecl)
1820
Eric Blake437db252015-09-29 16:21:02 -06001821
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001822def close_output(fdef, fdecl):
1823 fdecl.write('''
1824#endif
1825''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001826 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001827 fdef.close()