blob: b7fbdae1f2b49ba14e1fba925d6ebf858d3d7205 [file] [log] [blame]
Michael Roth0f923be2011-07-19 14:50:39 -05001#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
Eric Blakee4083112016-01-29 06:48:41 -07005# Copyright (c) 2013-2016 Red Hat Inc.
Michael Roth0f923be2011-07-19 14:50:39 -05006#
7# Authors:
8# Anthony Liguori <aliguori@us.ibm.com>
Markus Armbrusterc7a3f252013-07-27 17:41:55 +02009# Markus Armbruster <armbru@redhat.com>
Michael Roth0f923be2011-07-19 14:50:39 -050010#
Markus Armbruster678e48a2014-03-01 08:40:34 +010011# This work is licensed under the terms of the GNU GPL, version 2.
12# See the COPYING file in the top-level directory.
Michael Roth0f923be2011-07-19 14:50:39 -050013
Lluís Vilanovaa719a272014-05-07 20:46:15 +020014import re
Michael Roth0f923be2011-07-19 14:50:39 -050015from ordereddict import OrderedDict
Markus Armbruster12f8e1b2015-04-02 14:46:39 +020016import errno
Markus Armbruster2114f5a2015-04-02 13:12:21 +020017import getopt
Lluís Vilanova33aaad52014-05-02 15:52:35 +020018import os
Markus Armbruster2caba362013-07-27 17:41:56 +020019import sys
Markus Armbruster47299262015-05-14 06:50:47 -060020import string
Michael Roth0f923be2011-07-19 14:50:39 -050021
Eric Blakeb52c4b92015-05-04 09:05:00 -060022builtin_types = {
Kevin Wolf69dd62d2013-07-08 16:14:21 +020023 'str': 'QTYPE_QSTRING',
24 'int': 'QTYPE_QINT',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
27 'int8': 'QTYPE_QINT',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
Eric Blakecb17f792015-05-04 09:05:01 -060035 'size': 'QTYPE_QINT',
Eric Blake1310a3d2015-12-01 22:20:46 -070036 'any': None, # any QType possible, actually
Eric Blake7264f5c2015-12-01 22:20:47 -070037 'QType': 'QTYPE_QSTRING',
Kevin Wolf69dd62d2013-07-08 16:14:21 +020038}
39
Eric Blake10d4d992015-05-04 09:05:23 -060040# Whitelist of commands allowed to return a non-dictionary
41returns_whitelist = [
42 # From QMP:
43 'human-monitor-command',
Markus Armbruster6eb39372015-09-16 13:06:25 +020044 'qom-get',
Eric Blake10d4d992015-05-04 09:05:23 -060045 'query-migrate-cache-size',
46 'query-tpm-models',
47 'query-tpm-types',
48 'ringbuf-read',
49
50 # From QGA:
51 'guest-file-open',
52 'guest-fsfreeze-freeze',
53 'guest-fsfreeze-freeze-list',
54 'guest-fsfreeze-status',
55 'guest-fsfreeze-thaw',
56 'guest-get-time',
57 'guest-set-vcpus',
58 'guest-sync',
59 'guest-sync-delimited',
Eric Blake10d4d992015-05-04 09:05:23 -060060]
61
Eric Blake893e1f22015-12-01 22:20:57 -070062# Whitelist of entities allowed to violate case conventions
63case_whitelist = [
64 # From QMP:
65 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
66 'CpuInfoBase', # CPU, visible through query-cpu
67 'CpuInfoMIPS', # PC, visible through query-cpu
68 'CpuInfoTricore', # PC, visible through query-cpu
Eric Blake893e1f22015-12-01 22:20:57 -070069 'QapiErrorClass', # all members, visible through errors
70 'UuidInfo', # UUID, visible through query-uuid
71 'X86CPURegister32', # all members, visible indirectly through qom-get
72]
73
Eric Blake4dc2e692015-05-04 09:05:17 -060074enum_types = []
75struct_types = []
76union_types = []
77events = []
78all_names = {}
79
Markus Armbruster00e4b282015-06-10 10:04:36 +020080#
81# Parsing the schema into expressions
82#
83
Eric Blake437db252015-09-29 16:21:02 -060084
Lluís Vilanovaa719a272014-05-07 20:46:15 +020085def error_path(parent):
86 res = ""
87 while parent:
88 res = ("In file included from %s:%d:\n" % (parent['file'],
89 parent['line'])) + res
90 parent = parent['parent']
91 return res
92
Eric Blake437db252015-09-29 16:21:02 -060093
Markus Armbruster2caba362013-07-27 17:41:56 +020094class QAPISchemaError(Exception):
95 def __init__(self, schema, msg):
Eric Blake59b00542015-09-29 16:21:01 -060096 Exception.__init__(self)
Markus Armbruster54414042015-06-09 16:22:45 +020097 self.fname = schema.fname
Markus Armbruster2caba362013-07-27 17:41:56 +020098 self.msg = msg
Wenchao Xia515b9432014-03-04 18:44:33 -080099 self.col = 1
100 self.line = schema.line
101 for ch in schema.src[schema.line_pos:schema.pos]:
102 if ch == '\t':
Markus Armbruster2caba362013-07-27 17:41:56 +0200103 self.col = (self.col + 7) % 8 + 1
104 else:
105 self.col += 1
Markus Armbruster54414042015-06-09 16:22:45 +0200106 self.info = schema.incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +0200107
108 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200109 return error_path(self.info) + \
Markus Armbruster54414042015-06-09 16:22:45 +0200110 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
Markus Armbruster2caba362013-07-27 17:41:56 +0200111
Eric Blake437db252015-09-29 16:21:02 -0600112
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800113class QAPIExprError(Exception):
114 def __init__(self, expr_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -0600115 Exception.__init__(self)
Eric Blake7618b912015-10-12 22:22:22 -0600116 assert expr_info
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200117 self.info = expr_info
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800118 self.msg = msg
119
120 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200121 return error_path(self.info['parent']) + \
122 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800123
Eric Blake437db252015-09-29 16:21:02 -0600124
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200125class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500126
Eric Blake437db252015-09-29 16:21:02 -0600127 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200128 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200129 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200130 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200131 previously_included.append(abs_fname)
132 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200133 self.src = fp.read()
134 if self.src == '' or self.src[-1] != '\n':
135 self.src += '\n'
136 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800137 self.line = 1
138 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200139 self.exprs = []
140 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500141
Eric Blake437db252015-09-29 16:21:02 -0600142 while self.tok is not None:
Markus Armbruster54414042015-06-09 16:22:45 +0200143 expr_info = {'file': fname, 'line': self.line,
144 'parent': self.incl_info}
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200145 expr = self.get_expr(False)
146 if isinstance(expr, dict) and "include" in expr:
147 if len(expr) != 1:
Eric Blake437db252015-09-29 16:21:02 -0600148 raise QAPIExprError(expr_info,
149 "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200150 include = expr["include"]
151 if not isinstance(include, str):
152 raise QAPIExprError(expr_info,
Eric Blake7408fb62015-09-29 16:21:00 -0600153 "Value of 'include' must be a string")
Markus Armbruster54414042015-06-09 16:22:45 +0200154 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
155 include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200156 # catch inclusion cycle
157 inf = expr_info
158 while inf:
159 if incl_abs_fname == os.path.abspath(inf['file']):
Stefan Hajnoczi7ac9a9d2014-08-27 12:08:51 +0100160 raise QAPIExprError(expr_info, "Inclusion loop for %s"
161 % include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200162 inf = inf['parent']
Benoît Canet24fd8482014-05-16 12:51:56 +0200163 # skip multiple include of the same file
Markus Armbruster54414042015-06-09 16:22:45 +0200164 if incl_abs_fname in previously_included:
Benoît Canet24fd8482014-05-16 12:51:56 +0200165 continue
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200166 try:
Markus Armbruster54414042015-06-09 16:22:45 +0200167 fobj = open(incl_abs_fname, 'r')
Markus Armbruster291928a2015-12-18 08:52:41 +0100168 except IOError as e:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200169 raise QAPIExprError(expr_info,
170 '%s: %s' % (e.strerror, include))
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200171 exprs_include = QAPISchemaParser(fobj, previously_included,
172 expr_info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200173 self.exprs.extend(exprs_include.exprs)
174 else:
175 expr_elem = {'expr': expr,
176 'info': expr_info}
177 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500178
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200179 def accept(self):
180 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200181 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200182 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200183 self.cursor += 1
184 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500185
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200186 if self.tok == '#':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200187 self.cursor = self.src.find('\n', self.cursor)
Eric Blake8712fa52015-10-26 16:34:41 -0600188 elif self.tok in "{}:,[]":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200189 return
190 elif self.tok == "'":
191 string = ''
192 esc = False
193 while True:
194 ch = self.src[self.cursor]
195 self.cursor += 1
196 if ch == '\n':
Markus Armbruster2caba362013-07-27 17:41:56 +0200197 raise QAPISchemaError(self,
198 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200199 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600200 if ch == 'b':
201 string += '\b'
202 elif ch == 'f':
203 string += '\f'
204 elif ch == 'n':
205 string += '\n'
206 elif ch == 'r':
207 string += '\r'
208 elif ch == 't':
209 string += '\t'
210 elif ch == 'u':
211 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600212 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600213 ch = self.src[self.cursor]
214 self.cursor += 1
215 if ch not in "0123456789abcdefABCDEF":
216 raise QAPISchemaError(self,
217 '\\u escape needs 4 '
218 'hex digits')
219 value = (value << 4) + int(ch, 16)
220 # If Python 2 and 3 didn't disagree so much on
221 # how to handle Unicode, then we could allow
222 # Unicode string defaults. But most of QAPI is
223 # ASCII-only, so we aren't losing much for now.
224 if not value or value > 0x7f:
225 raise QAPISchemaError(self,
226 'For now, \\u escape '
227 'only supports non-zero '
228 'values up to \\u007f')
229 string += chr(value)
230 elif ch in "\\/'\"":
231 string += ch
232 else:
233 raise QAPISchemaError(self,
Eric Blake437db252015-09-29 16:21:02 -0600234 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200235 esc = False
236 elif ch == "\\":
237 esc = True
238 elif ch == "'":
239 self.val = string
240 return
241 else:
242 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200243 elif self.src.startswith("true", self.pos):
244 self.val = True
245 self.cursor += 3
246 return
247 elif self.src.startswith("false", self.pos):
248 self.val = False
249 self.cursor += 4
250 return
251 elif self.src.startswith("null", self.pos):
252 self.val = None
253 self.cursor += 3
254 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200255 elif self.tok == '\n':
256 if self.cursor == len(self.src):
257 self.tok = None
258 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800259 self.line += 1
260 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200261 elif not self.tok.isspace():
262 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500263
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200264 def get_members(self):
265 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200266 if self.tok == '}':
267 self.accept()
268 return expr
269 if self.tok != "'":
270 raise QAPISchemaError(self, 'Expected string or "}"')
271 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200272 key = self.val
273 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200274 if self.tok != ':':
275 raise QAPISchemaError(self, 'Expected ":"')
276 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800277 if key in expr:
278 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200279 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200280 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200281 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200282 return expr
283 if self.tok != ',':
284 raise QAPISchemaError(self, 'Expected "," or "}"')
285 self.accept()
286 if self.tok != "'":
287 raise QAPISchemaError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500288
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200289 def get_values(self):
290 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200291 if self.tok == ']':
292 self.accept()
293 return expr
Eric Blake437db252015-09-29 16:21:02 -0600294 if self.tok not in "{['tfn":
Fam Zhenge53188a2015-05-04 09:05:18 -0600295 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
296 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200297 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200298 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200299 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200300 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200301 return expr
302 if self.tok != ',':
303 raise QAPISchemaError(self, 'Expected "," or "]"')
304 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500305
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200306 def get_expr(self, nested):
307 if self.tok != '{' and not nested:
308 raise QAPISchemaError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200309 if self.tok == '{':
310 self.accept()
311 expr = self.get_members()
312 elif self.tok == '[':
313 self.accept()
314 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600315 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200316 expr = self.val
317 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200318 else:
319 raise QAPISchemaError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200320 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200321
Markus Armbruster00e4b282015-06-10 10:04:36 +0200322#
323# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200324# TODO fold into QAPISchema
325# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200326#
327
Eric Blake437db252015-09-29 16:21:02 -0600328
Eric Blake14f00c62016-03-03 09:16:43 -0700329def find_base_members(base):
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800330 base_struct_define = find_struct(base)
331 if not base_struct_define:
332 return None
333 return base_struct_define['data']
334
Eric Blake437db252015-09-29 16:21:02 -0600335
Eric Blake811d04f2015-05-04 09:05:10 -0600336# Return the qtype of an alternate branch, or None on error.
337def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600338 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600339 return builtin_types[qapi_type]
340 elif find_struct(qapi_type):
341 return "QTYPE_QDICT"
342 elif find_enum(qapi_type):
343 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600344 elif find_union(qapi_type):
345 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600346 return None
347
Eric Blake437db252015-09-29 16:21:02 -0600348
Wenchao Xiabceae762014-03-06 17:08:56 -0800349# Return the discriminator enum define if discriminator is specified as an
350# enum type, otherwise return None.
351def discriminator_find_enum_define(expr):
352 base = expr.get('base')
353 discriminator = expr.get('discriminator')
354
355 if not (discriminator and base):
356 return None
357
Eric Blake14f00c62016-03-03 09:16:43 -0700358 base_members = find_base_members(base)
359 if not base_members:
Wenchao Xiabceae762014-03-06 17:08:56 -0800360 return None
361
Eric Blake14f00c62016-03-03 09:16:43 -0700362 discriminator_type = base_members.get(discriminator)
Wenchao Xiabceae762014-03-06 17:08:56 -0800363 if not discriminator_type:
364 return None
365
366 return find_enum(discriminator_type)
367
Eric Blake437db252015-09-29 16:21:02 -0600368
Eric Blake59a92fe2015-11-18 01:52:56 -0700369# Names must be letters, numbers, -, and _. They must start with letter,
370# except for downstream extensions which must start with __RFQDN_.
371# Dots are only valid in the downstream extension prefix.
372valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
373 '[a-zA-Z][a-zA-Z0-9_-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600374
375
376def check_name(expr_info, source, name, allow_optional=False,
377 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600378 global valid_name
379 membername = name
380
381 if not isinstance(name, str):
382 raise QAPIExprError(expr_info,
383 "%s requires a string name" % source)
384 if name.startswith('*'):
385 membername = name[1:]
386 if not allow_optional:
387 raise QAPIExprError(expr_info,
388 "%s does not allow optional name '%s'"
389 % (source, name))
390 # Enum members can start with a digit, because the generated C
391 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700392 if enum_member and membername[0].isdigit():
393 membername = 'D' + membername
Eric Blake9fb081e2015-10-26 16:34:44 -0600394 # Reserve the entire 'q_' namespace for c_name()
395 if not valid_name.match(membername) or \
396 c_name(membername, False).startswith('q_'):
Eric Blakec9e0a792015-05-04 09:05:22 -0600397 raise QAPIExprError(expr_info,
398 "%s uses invalid name '%s'" % (source, name))
399
Eric Blake437db252015-09-29 16:21:02 -0600400
401def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200402 global all_names
403 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200404 # FIXME should reject names that differ only in '_' vs. '.'
405 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200406 if name in all_names:
407 raise QAPIExprError(info,
408 "%s '%s' is already defined"
409 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600410 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200411 raise QAPIExprError(info,
Eric Blake255960d2015-10-26 16:34:43 -0600412 "%s '%s' should not end in '%s'"
413 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200414 all_names[name] = meta
415
Eric Blake437db252015-09-29 16:21:02 -0600416
Markus Armbruster00e4b282015-06-10 10:04:36 +0200417def add_struct(definition, info):
418 global struct_types
419 name = definition['struct']
420 add_name(name, info, 'struct')
421 struct_types.append(definition)
422
Eric Blake437db252015-09-29 16:21:02 -0600423
Markus Armbruster00e4b282015-06-10 10:04:36 +0200424def find_struct(name):
425 global struct_types
426 for struct in struct_types:
427 if struct['struct'] == name:
428 return struct
429 return None
430
Eric Blake437db252015-09-29 16:21:02 -0600431
Markus Armbruster00e4b282015-06-10 10:04:36 +0200432def add_union(definition, info):
433 global union_types
434 name = definition['union']
435 add_name(name, info, 'union')
436 union_types.append(definition)
437
Eric Blake437db252015-09-29 16:21:02 -0600438
Markus Armbruster00e4b282015-06-10 10:04:36 +0200439def find_union(name):
440 global union_types
441 for union in union_types:
442 if union['union'] == name:
443 return union
444 return None
445
Eric Blake437db252015-09-29 16:21:02 -0600446
447def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200448 global enum_types
449 add_name(name, info, 'enum', implicit)
450 enum_types.append({"enum_name": name, "enum_values": enum_values})
451
Eric Blake437db252015-09-29 16:21:02 -0600452
Markus Armbruster00e4b282015-06-10 10:04:36 +0200453def find_enum(name):
454 global enum_types
455 for enum in enum_types:
456 if enum['enum_name'] == name:
457 return enum
458 return None
459
Markus Armbruster00e4b282015-06-10 10:04:36 +0200460
Eric Blake437db252015-09-29 16:21:02 -0600461def is_enum(name):
462 return find_enum(name) is not None
463
464
465def check_type(expr_info, source, value, allow_array=False,
466 allow_dict=False, allow_optional=False,
467 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600468 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600469
470 if value is None:
471 return
472
Eric Blakedd883c62015-05-04 09:05:21 -0600473 # Check if array type for value is okay
474 if isinstance(value, list):
475 if not allow_array:
476 raise QAPIExprError(expr_info,
477 "%s cannot be an array" % source)
478 if len(value) != 1 or not isinstance(value[0], str):
479 raise QAPIExprError(expr_info,
480 "%s: array type must contain single type name"
481 % source)
482 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600483
484 # Check if type name for value is okay
485 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600486 if value not in all_names:
Eric Blakedd883c62015-05-04 09:05:21 -0600487 raise QAPIExprError(expr_info,
488 "%s uses unknown type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200489 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600490 if not all_names[value] in allow_metas:
491 raise QAPIExprError(expr_info,
492 "%s cannot use %s type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200493 % (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600494 return
495
Eric Blakedd883c62015-05-04 09:05:21 -0600496 if not allow_dict:
497 raise QAPIExprError(expr_info,
498 "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200499
500 if not isinstance(value, OrderedDict):
501 raise QAPIExprError(expr_info,
502 "%s should be a dictionary or type name" % source)
503
504 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600505 for (key, arg) in value.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600506 check_name(expr_info, "Member of %s" % source, key,
507 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600508 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Eric Blake9fb081e2015-10-26 16:34:44 -0600509 raise QAPIExprError(expr_info,
510 "Member of %s uses reserved name '%s'"
511 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600512 # Todo: allow dictionaries to represent default values of
513 # an optional argument.
Eric Blakedd883c62015-05-04 09:05:21 -0600514 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200515 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600516 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600517 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600518
Eric Blake437db252015-09-29 16:21:02 -0600519
Eric Blakedd883c62015-05-04 09:05:21 -0600520def check_command(expr, expr_info):
521 name = expr['command']
Eric Blake2cbf0992015-05-04 09:05:24 -0600522
Eric Blakedd883c62015-05-04 09:05:21 -0600523 check_type(expr_info, "'data' for command '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600524 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200525 allow_metas=['struct'])
Eric Blake10d4d992015-05-04 09:05:23 -0600526 returns_meta = ['union', 'struct']
527 if name in returns_whitelist:
528 returns_meta += ['built-in', 'alternate', 'enum']
Eric Blakedd883c62015-05-04 09:05:21 -0600529 check_type(expr_info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200530 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200531 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600532
Eric Blake437db252015-09-29 16:21:02 -0600533
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200534def check_event(expr, expr_info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600535 global events
536 name = expr['event']
Eric Blake4dc2e692015-05-04 09:05:17 -0600537
Eric Blake4dc2e692015-05-04 09:05:17 -0600538 events.append(name)
Eric Blakedd883c62015-05-04 09:05:21 -0600539 check_type(expr_info, "'data' for event '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600540 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster315932b2015-07-01 10:12:24 +0200541 allow_metas=['struct'])
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200542
Eric Blake437db252015-09-29 16:21:02 -0600543
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800544def check_union(expr, expr_info):
545 name = expr['union']
546 base = expr.get('base')
547 discriminator = expr.get('discriminator')
548 members = expr['data']
549
Eric Blake811d04f2015-05-04 09:05:10 -0600550 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600551
552 # With no discriminator it is a simple union.
553 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600554 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600555 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600556 if base is not None:
557 raise QAPIExprError(expr_info,
Eric Blake811d04f2015-05-04 09:05:10 -0600558 "Simple union '%s' must not have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600559 % name)
560
561 # Else, it's a flat union.
562 else:
563 # The object must have a string member 'base'.
Eric Blake376863e2015-09-29 16:21:07 -0600564 check_type(expr_info, "'base' for union '%s'" % name,
565 base, allow_metas=['struct'])
566 if not base:
Eric Blake44bd1272015-05-04 09:05:08 -0600567 raise QAPIExprError(expr_info,
Eric Blake376863e2015-09-29 16:21:07 -0600568 "Flat union '%s' must have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600569 % name)
Eric Blake14f00c62016-03-03 09:16:43 -0700570 base_members = find_base_members(base)
571 assert base_members
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800572
Eric Blakec9e0a792015-05-04 09:05:22 -0600573 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600574 # member of the base struct.
Eric Blakec9e0a792015-05-04 09:05:22 -0600575 check_name(expr_info, "Discriminator of flat union '%s'" % name,
576 discriminator)
Eric Blake14f00c62016-03-03 09:16:43 -0700577 discriminator_type = base_members.get(discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800578 if not discriminator_type:
579 raise QAPIExprError(expr_info,
580 "Discriminator '%s' is not a member of base "
Eric Blakefd41dd42015-05-04 09:05:25 -0600581 "struct '%s'"
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800582 % (discriminator, base))
583 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600584 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800585 # Do not allow string discriminator
586 if not enum_define:
587 raise QAPIExprError(expr_info,
588 "Discriminator '%s' must be of enumeration "
589 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800590
Eric Blake02a57ae2016-02-17 23:48:16 -0700591 # Check every branch; don't allow an empty union
592 if len(members) == 0:
593 raise QAPIExprError(expr_info,
594 "Union '%s' cannot have empty 'data'" % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800595 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600596 check_name(expr_info, "Member of union '%s'" % name, key)
597
Eric Blake01cfbaa2015-12-01 22:20:58 -0700598 # Each value must name a known type
Eric Blakedd883c62015-05-04 09:05:21 -0600599 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200600 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600601
Eric Blake44bd1272015-05-04 09:05:08 -0600602 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700603 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600604 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600605 if key not in enum_define['enum_values']:
Eric Blake44bd1272015-05-04 09:05:08 -0600606 raise QAPIExprError(expr_info,
607 "Discriminator value '%s' is not found in "
608 "enum '%s'" %
609 (key, enum_define["enum_name"]))
610
Eric Blake437db252015-09-29 16:21:02 -0600611
Eric Blake811d04f2015-05-04 09:05:10 -0600612def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600613 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600614 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600615 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600616
Eric Blake02a57ae2016-02-17 23:48:16 -0700617 # Check every branch; require at least two branches
618 if len(members) < 2:
619 raise QAPIExprError(expr_info,
620 "Alternate '%s' should have at least two branches "
621 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600622 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600623 check_name(expr_info, "Member of alternate '%s'" % name, key)
624
Eric Blake811d04f2015-05-04 09:05:10 -0600625 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600626 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
627 value,
628 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600629 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700630 if not qtype:
631 raise QAPIExprError(expr_info,
632 "Alternate '%s' member '%s' cannot use "
633 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600634 if qtype in types_seen:
635 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600636 "Alternate '%s' member '%s' can't "
Eric Blake811d04f2015-05-04 09:05:10 -0600637 "be distinguished from member '%s'"
638 % (name, key, types_seen[qtype]))
639 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800640
Eric Blake437db252015-09-29 16:21:02 -0600641
Eric Blakecf393592015-05-04 09:05:04 -0600642def check_enum(expr, expr_info):
643 name = expr['enum']
644 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100645 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600646
647 if not isinstance(members, list):
648 raise QAPIExprError(expr_info,
649 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100650 if prefix is not None and not isinstance(prefix, str):
651 raise QAPIExprError(expr_info,
652 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600653 for member in members:
Eric Blake437db252015-09-29 16:21:02 -0600654 check_name(expr_info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600655 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600656
Eric Blake437db252015-09-29 16:21:02 -0600657
Eric Blakedd883c62015-05-04 09:05:21 -0600658def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600659 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600660 members = expr['data']
661
Eric Blakefd41dd42015-05-04 09:05:25 -0600662 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600663 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600664 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600665 allow_metas=['struct'])
666
Eric Blake437db252015-09-29 16:21:02 -0600667
Eric Blake0545f6b2015-05-04 09:05:15 -0600668def check_keys(expr_elem, meta, required, optional=[]):
669 expr = expr_elem['expr']
670 info = expr_elem['info']
671 name = expr[meta]
672 if not isinstance(name, str):
673 raise QAPIExprError(info,
674 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600675 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600676 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600677 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600678 raise QAPIExprError(info,
679 "Unknown key '%s' in %s '%s'"
680 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600681 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600682 raise QAPIExprError(info,
683 "'%s' of %s '%s' should only use false value"
684 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600685 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600686 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600687 raise QAPIExprError(info,
688 "Key '%s' is missing from %s '%s'"
689 % (key, meta, name))
690
Eric Blake437db252015-09-29 16:21:02 -0600691
Markus Armbruster4d076d62015-06-10 08:55:21 +0200692def check_exprs(exprs):
693 global all_names
694
695 # Learn the types and check for valid expression keys
696 for builtin in builtin_types.keys():
697 all_names[builtin] = 'built-in'
698 for expr_elem in exprs:
699 expr = expr_elem['expr']
700 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600701 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100702 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200703 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600704 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200705 check_keys(expr_elem, 'union', ['data'],
706 ['base', 'discriminator'])
707 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600708 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200709 check_keys(expr_elem, 'alternate', ['data'])
710 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600711 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200712 check_keys(expr_elem, 'struct', ['data'], ['base'])
713 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600714 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200715 check_keys(expr_elem, 'command', [],
716 ['data', 'returns', 'gen', 'success-response'])
717 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600718 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200719 check_keys(expr_elem, 'event', [], ['data'])
720 add_name(expr['event'], info, 'event')
721 else:
722 raise QAPIExprError(expr_elem['info'],
723 "Expression is missing metatype")
724
725 # Try again for hidden UnionKind enum
726 for expr_elem in exprs:
727 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600728 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200729 if not discriminator_find_enum_define(expr):
730 add_enum('%sKind' % expr['union'], expr_elem['info'],
731 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600732 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200733 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
734 implicit=True)
735
736 # Validate that exprs make sense
737 for expr_elem in exprs:
738 expr = expr_elem['expr']
739 info = expr_elem['info']
740
Eric Blake437db252015-09-29 16:21:02 -0600741 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200742 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600743 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200744 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600745 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200746 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600747 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200748 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600749 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200750 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600751 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200752 check_event(expr, info)
753 else:
754 assert False, 'unexpected meta type'
755
Markus Armbrusterac882192015-09-16 13:06:05 +0200756 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600757
Markus Armbrusterac882192015-09-16 13:06:05 +0200758
759#
760# Schema compiler frontend
761#
762
763class QAPISchemaEntity(object):
764 def __init__(self, name, info):
765 assert isinstance(name, str)
766 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -0600767 # For explicitly defined entities, info points to the (explicit)
768 # definition. For builtins (and their arrays), info is None.
769 # For implicitly defined entities, info points to a place that
770 # triggered the implicit definition (there may be more than one
771 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +0200772 self.info = info
773
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200774 def c_name(self):
775 return c_name(self.name)
776
Markus Armbrusterac882192015-09-16 13:06:05 +0200777 def check(self, schema):
778 pass
779
Eric Blake49823c42015-10-12 22:22:27 -0600780 def is_implicit(self):
781 return not self.info
782
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200783 def visit(self, visitor):
784 pass
785
786
787class QAPISchemaVisitor(object):
788 def visit_begin(self, schema):
789 pass
790
791 def visit_end(self):
792 pass
793
Eric Blake25a0d9c2015-10-12 22:22:21 -0600794 def visit_needed(self, entity):
795 # Default to visiting everything
796 return True
797
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200798 def visit_builtin_type(self, name, info, json_type):
799 pass
800
801 def visit_enum_type(self, name, info, values, prefix):
802 pass
803
804 def visit_array_type(self, name, info, element_type):
805 pass
806
807 def visit_object_type(self, name, info, base, members, variants):
808 pass
809
Markus Armbruster39a18152015-09-16 13:06:28 +0200810 def visit_object_type_flat(self, name, info, members, variants):
811 pass
812
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200813 def visit_alternate_type(self, name, info, variants):
814 pass
815
816 def visit_command(self, name, info, arg_type, ret_type,
817 gen, success_response):
818 pass
819
820 def visit_event(self, name, info, arg_type):
821 pass
822
Markus Armbrusterac882192015-09-16 13:06:05 +0200823
824class QAPISchemaType(QAPISchemaEntity):
Eric Blake4040d992016-03-17 16:48:28 -0600825 # Return the C type for common use.
826 # For the types we commonly box, this is a pointer type.
827 def c_type(self):
828 pass
829
830 # Return the C type to be used in a parameter list.
831 def c_param_type(self):
832 return self.c_type()
833
834 # Return the C type to be used where we suppress boxing.
835 def c_unboxed_type(self):
836 return self.c_type()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200837
838 def c_null(self):
839 return 'NULL'
840
841 def json_type(self):
842 pass
843
844 def alternate_qtype(self):
845 json2qtype = {
846 'string': 'QTYPE_QSTRING',
847 'number': 'QTYPE_QFLOAT',
848 'int': 'QTYPE_QINT',
849 'boolean': 'QTYPE_QBOOL',
850 'object': 'QTYPE_QDICT'
851 }
852 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200853
854
855class QAPISchemaBuiltinType(QAPISchemaType):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200856 def __init__(self, name, json_type, c_type, c_null):
Markus Armbrusterac882192015-09-16 13:06:05 +0200857 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200858 assert not c_type or isinstance(c_type, str)
859 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
860 'value')
861 self._json_type_name = json_type
862 self._c_type_name = c_type
863 self._c_null_val = c_null
864
865 def c_name(self):
866 return self.name
867
Eric Blake4040d992016-03-17 16:48:28 -0600868 def c_type(self):
869 return self._c_type_name
870
871 def c_param_type(self):
872 if self.name == 'str':
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200873 return 'const ' + self._c_type_name
874 return self._c_type_name
875
876 def c_null(self):
877 return self._c_null_val
878
879 def json_type(self):
880 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200881
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200882 def visit(self, visitor):
883 visitor.visit_builtin_type(self.name, self.info, self.json_type())
884
Markus Armbrusterac882192015-09-16 13:06:05 +0200885
886class QAPISchemaEnumType(QAPISchemaType):
887 def __init__(self, name, info, values, prefix):
888 QAPISchemaType.__init__(self, name, info)
889 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -0700890 assert isinstance(v, QAPISchemaMember)
891 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200892 assert prefix is None or isinstance(prefix, str)
893 self.values = values
894 self.prefix = prefix
895
896 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -0700897 seen = {}
898 for v in self.values:
899 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200900
Eric Blake99df5282015-10-12 22:22:32 -0600901 def is_implicit(self):
902 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -0600903 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -0600904
Eric Blake4040d992016-03-17 16:48:28 -0600905 def c_type(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200906 return c_name(self.name)
907
Eric Blake93bda4d2015-12-01 22:20:55 -0700908 def member_names(self):
909 return [v.name for v in self.values]
910
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200911 def c_null(self):
Eric Blake93bda4d2015-12-01 22:20:55 -0700912 return c_enum_const(self.name, (self.member_names() + ['_MAX'])[0],
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200913 self.prefix)
914
915 def json_type(self):
916 return 'string'
917
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200918 def visit(self, visitor):
919 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -0700920 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200921
Markus Armbrusterac882192015-09-16 13:06:05 +0200922
923class QAPISchemaArrayType(QAPISchemaType):
924 def __init__(self, name, info, element_type):
925 QAPISchemaType.__init__(self, name, info)
926 assert isinstance(element_type, str)
927 self._element_type_name = element_type
928 self.element_type = None
929
930 def check(self, schema):
931 self.element_type = schema.lookup_type(self._element_type_name)
932 assert self.element_type
933
Eric Blake99df5282015-10-12 22:22:32 -0600934 def is_implicit(self):
935 return True
936
Eric Blake4040d992016-03-17 16:48:28 -0600937 def c_type(self):
938 return c_name(self.name) + pointer_suffix
939
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200940 def json_type(self):
941 return 'array'
942
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200943 def visit(self, visitor):
944 visitor.visit_array_type(self.name, self.info, self.element_type)
945
Markus Armbrusterac882192015-09-16 13:06:05 +0200946
947class QAPISchemaObjectType(QAPISchemaType):
948 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -0700949 # struct has local_members, optional base, and no variants
950 # flat union has base, variants, and no local_members
951 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +0200952 QAPISchemaType.__init__(self, name, info)
953 assert base is None or isinstance(base, str)
954 for m in local_members:
955 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -0700956 m.set_owner(name)
957 if variants is not None:
958 assert isinstance(variants, QAPISchemaObjectTypeVariants)
959 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200960 self._base_name = base
961 self.base = None
962 self.local_members = local_members
963 self.variants = variants
964 self.members = None
965
966 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -0700967 if self.members is False: # check for cycles
968 raise QAPIExprError(self.info,
969 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200970 if self.members:
971 return
972 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -0700973 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +0200974 if self._base_name:
975 self.base = schema.lookup_type(self._base_name)
976 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +0200977 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700978 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200979 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -0700980 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700981 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700982 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +0200983 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -0700984 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700985 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -0700986 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200987
Eric Blake14f00c62016-03-03 09:16:43 -0700988 # Check that the members of this type do not cause duplicate JSON members,
Eric Blake27b60ab2015-11-18 01:52:51 -0700989 # and update seen to track the members seen so far. Report any errors
990 # on behalf of info, which is not necessarily self.info
991 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -0700992 assert not self.variants # not implemented
993 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -0700994 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -0700995
Eric Blake99df5282015-10-12 22:22:32 -0600996 def is_implicit(self):
997 # See QAPISchema._make_implicit_object_type()
998 return self.name[0] == ':'
999
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001000 def c_name(self):
Eric Blake49823c42015-10-12 22:22:27 -06001001 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001002 return QAPISchemaType.c_name(self)
1003
Eric Blake4040d992016-03-17 16:48:28 -06001004 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001005 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -07001006 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001007
Eric Blake4040d992016-03-17 16:48:28 -06001008 def c_unboxed_type(self):
1009 assert not self.is_implicit()
1010 return c_name(self.name)
1011
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001012 def json_type(self):
1013 return 'object'
1014
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001015 def visit(self, visitor):
1016 visitor.visit_object_type(self.name, self.info,
1017 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001018 visitor.visit_object_type_flat(self.name, self.info,
1019 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001020
Markus Armbrusterac882192015-09-16 13:06:05 +02001021
Eric Blaked44f9ac2015-12-01 22:20:54 -07001022class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001023 role = 'member'
1024
Eric Blaked44f9ac2015-12-01 22:20:54 -07001025 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001026 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001027 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001028 self.owner = None
1029
1030 def set_owner(self, name):
1031 assert not self.owner
1032 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001033
Eric Blake27b60ab2015-11-18 01:52:51 -07001034 def check_clash(self, info, seen):
1035 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001036 if cname.lower() != cname and self.owner not in case_whitelist:
1037 raise QAPIExprError(info,
1038 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001039 if cname in seen:
1040 raise QAPIExprError(info,
1041 "%s collides with %s"
1042 % (self.describe(), seen[cname].describe()))
1043 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001044
Eric Blake88d4ef82015-11-18 01:52:50 -07001045 def _pretty_owner(self):
1046 owner = self.owner
1047 if owner.startswith(':obj-'):
1048 # See QAPISchema._make_implicit_object_type() - reverse the
1049 # mapping there to create a nice human-readable description
1050 owner = owner[5:]
1051 if owner.endswith('-arg'):
1052 return '(parameter of %s)' % owner[:-4]
1053 else:
1054 assert owner.endswith('-wrapper')
1055 # Unreachable and not implemented
1056 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001057 if owner.endswith('Kind'):
1058 # See QAPISchema._make_implicit_enum_type()
1059 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001060 return '(%s of %s)' % (self.role, owner)
1061
1062 def describe(self):
1063 return "'%s' %s" % (self.name, self._pretty_owner())
1064
Markus Armbrusterac882192015-09-16 13:06:05 +02001065
Eric Blaked44f9ac2015-12-01 22:20:54 -07001066class QAPISchemaObjectTypeMember(QAPISchemaMember):
1067 def __init__(self, name, typ, optional):
1068 QAPISchemaMember.__init__(self, name)
1069 assert isinstance(typ, str)
1070 assert isinstance(optional, bool)
1071 self._type_name = typ
1072 self.type = None
1073 self.optional = optional
1074
1075 def check(self, schema):
1076 assert self.owner
1077 self.type = schema.lookup_type(self._type_name)
1078 assert self.type
1079
1080
Markus Armbrusterac882192015-09-16 13:06:05 +02001081class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001082 def __init__(self, tag_name, tag_member, variants):
1083 # Flat unions pass tag_name but not tag_member.
1084 # Simple unions and alternates pass tag_member but not tag_name.
1085 # After check(), tag_member is always set, and tag_name remains
1086 # a reliable witness of being used by a flat union.
1087 assert bool(tag_member) != bool(tag_name)
1088 assert (isinstance(tag_name, str) or
1089 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001090 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001091 for v in variants:
1092 assert isinstance(v, QAPISchemaObjectTypeVariant)
1093 self.tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001094 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001095 self.variants = variants
1096
Eric Blake88d4ef82015-11-18 01:52:50 -07001097 def set_owner(self, name):
1098 for v in self.variants:
1099 v.set_owner(name)
1100
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001101 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001102 if not self.tag_member: # flat union
Eric Blake27b60ab2015-11-18 01:52:51 -07001103 self.tag_member = seen[c_name(self.tag_name)]
1104 assert self.tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001105 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1106 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001107 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001108 # Union names must match enum values; alternate names are
1109 # checked separately. Use 'seen' to tell the two apart.
1110 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001111 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001112 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001113 v.type.check(schema)
1114
Eric Blake27b60ab2015-11-18 01:52:51 -07001115 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001116 for v in self.variants:
1117 # Reset seen map for each variant, since qapi names from one
1118 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001119 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001120 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001121
Eric Blake437db252015-09-29 16:21:02 -06001122
Markus Armbrusterac882192015-09-16 13:06:05 +02001123class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001124 role = 'branch'
1125
Markus Armbrusterac882192015-09-16 13:06:05 +02001126 def __init__(self, name, typ):
1127 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1128
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001129 # This function exists to support ugly simple union special cases
1130 # TODO get rid of them, and drop the function
1131 def simple_union_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001132 if (self.type.is_implicit() and
1133 isinstance(self.type, QAPISchemaObjectType)):
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001134 assert len(self.type.members) == 1
1135 assert not self.type.variants
1136 return self.type.members[0].type
1137 return None
1138
Markus Armbrusterac882192015-09-16 13:06:05 +02001139
1140class QAPISchemaAlternateType(QAPISchemaType):
1141 def __init__(self, name, info, variants):
1142 QAPISchemaType.__init__(self, name, info)
1143 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1144 assert not variants.tag_name
Eric Blake88d4ef82015-11-18 01:52:50 -07001145 variants.set_owner(name)
1146 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001147 self.variants = variants
1148
1149 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001150 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001151 # Not calling self.variants.check_clash(), because there's nothing
1152 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001153 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001154 # Alternate branch names have no relation to the tag enum values;
1155 # so we have to check for potential name collisions ourselves.
1156 seen = {}
1157 for v in self.variants.variants:
1158 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001159
Eric Blake4040d992016-03-17 16:48:28 -06001160 def c_type(self):
1161 return c_name(self.name) + pointer_suffix
1162
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001163 def json_type(self):
1164 return 'value'
1165
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001166 def visit(self, visitor):
1167 visitor.visit_alternate_type(self.name, self.info, self.variants)
1168
Markus Armbrusterac882192015-09-16 13:06:05 +02001169
1170class QAPISchemaCommand(QAPISchemaEntity):
1171 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1172 QAPISchemaEntity.__init__(self, name, info)
1173 assert not arg_type or isinstance(arg_type, str)
1174 assert not ret_type or isinstance(ret_type, str)
1175 self._arg_type_name = arg_type
1176 self.arg_type = None
1177 self._ret_type_name = ret_type
1178 self.ret_type = None
1179 self.gen = gen
1180 self.success_response = success_response
1181
1182 def check(self, schema):
1183 if self._arg_type_name:
1184 self.arg_type = schema.lookup_type(self._arg_type_name)
1185 assert isinstance(self.arg_type, QAPISchemaObjectType)
1186 assert not self.arg_type.variants # not implemented
1187 if self._ret_type_name:
1188 self.ret_type = schema.lookup_type(self._ret_type_name)
1189 assert isinstance(self.ret_type, QAPISchemaType)
1190
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001191 def visit(self, visitor):
1192 visitor.visit_command(self.name, self.info,
1193 self.arg_type, self.ret_type,
1194 self.gen, self.success_response)
1195
Markus Armbrusterac882192015-09-16 13:06:05 +02001196
1197class QAPISchemaEvent(QAPISchemaEntity):
1198 def __init__(self, name, info, arg_type):
1199 QAPISchemaEntity.__init__(self, name, info)
1200 assert not arg_type or isinstance(arg_type, str)
1201 self._arg_type_name = arg_type
1202 self.arg_type = None
1203
1204 def check(self, schema):
1205 if self._arg_type_name:
1206 self.arg_type = schema.lookup_type(self._arg_type_name)
1207 assert isinstance(self.arg_type, QAPISchemaObjectType)
1208 assert not self.arg_type.variants # not implemented
1209
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001210 def visit(self, visitor):
1211 visitor.visit_event(self.name, self.info, self.arg_type)
1212
Markus Armbrusterac882192015-09-16 13:06:05 +02001213
1214class QAPISchema(object):
1215 def __init__(self, fname):
1216 try:
1217 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001218 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001219 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001220 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001221 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001222 self._def_exprs()
1223 self.check()
Markus Armbruster291928a2015-12-18 08:52:41 +01001224 except (QAPISchemaError, QAPIExprError) as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001225 print >>sys.stderr, err
1226 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001227
Markus Armbrusterac882192015-09-16 13:06:05 +02001228 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001229 # Only the predefined types are allowed to not have info
1230 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001231 assert ent.name not in self._entity_dict
1232 self._entity_dict[ent.name] = ent
1233
1234 def lookup_entity(self, name, typ=None):
1235 ent = self._entity_dict.get(name)
1236 if typ and not isinstance(ent, typ):
1237 return None
1238 return ent
1239
1240 def lookup_type(self, name):
1241 return self.lookup_entity(name, QAPISchemaType)
1242
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001243 def _def_builtin_type(self, name, json_type, c_type, c_null):
1244 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1245 c_type, c_null))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001246 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1247 # qapi-types.h from a single .c, all arrays of builtins must be
1248 # declared in the first file whether or not they are used. Nicer
1249 # would be to use lazy instantiation, while figuring out how to
1250 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001251 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001252
1253 def _def_predefineds(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001254 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1255 ('number', 'number', 'double', '0'),
1256 ('int', 'int', 'int64_t', '0'),
1257 ('int8', 'int', 'int8_t', '0'),
1258 ('int16', 'int', 'int16_t', '0'),
1259 ('int32', 'int', 'int32_t', '0'),
1260 ('int64', 'int', 'int64_t', '0'),
1261 ('uint8', 'int', 'uint8_t', '0'),
1262 ('uint16', 'int', 'uint16_t', '0'),
1263 ('uint32', 'int', 'uint32_t', '0'),
1264 ('uint64', 'int', 'uint64_t', '0'),
1265 ('size', 'int', 'uint64_t', '0'),
1266 ('bool', 'boolean', 'bool', 'false'),
Markus Armbruster28770e02015-09-16 13:06:24 +02001267 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001268 self._def_builtin_type(*t)
Markus Armbruster39a18152015-09-16 13:06:28 +02001269 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1270 [], None)
1271 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001272 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1273 'qstring', 'qdict', 'qlist',
1274 'qfloat', 'qbool'])
1275 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001276 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001277
Eric Blake93bda4d2015-12-01 22:20:55 -07001278 def _make_enum_members(self, values):
1279 return [QAPISchemaMember(v) for v in values]
1280
Eric Blake99df5282015-10-12 22:22:32 -06001281 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001282 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001283 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001284 self._def_entity(QAPISchemaEnumType(
1285 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001286 return name
1287
Eric Blake99df5282015-10-12 22:22:32 -06001288 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001289 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001290 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001291 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001292 return name
1293
Eric Blake99df5282015-10-12 22:22:32 -06001294 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001295 if not members:
1296 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001297 # See also QAPISchemaObjectTypeMember._pretty_owner()
Markus Armbrusterac882192015-09-16 13:06:05 +02001298 name = ':obj-%s-%s' % (name, role)
1299 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001300 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001301 members, None))
1302 return name
1303
1304 def _def_enum_type(self, expr, info):
1305 name = expr['enum']
1306 data = expr['data']
1307 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001308 self._def_entity(QAPISchemaEnumType(
1309 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001310
Eric Blake99df5282015-10-12 22:22:32 -06001311 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001312 optional = False
1313 if name.startswith('*'):
1314 name = name[1:]
1315 optional = True
1316 if isinstance(typ, list):
1317 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001318 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001319 return QAPISchemaObjectTypeMember(name, typ, optional)
1320
Eric Blake99df5282015-10-12 22:22:32 -06001321 def _make_members(self, data, info):
1322 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001323 for (key, value) in data.iteritems()]
1324
1325 def _def_struct_type(self, expr, info):
1326 name = expr['struct']
1327 base = expr.get('base')
1328 data = expr['data']
1329 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001330 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001331 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001332
1333 def _make_variant(self, case, typ):
1334 return QAPISchemaObjectTypeVariant(case, typ)
1335
Eric Blake99df5282015-10-12 22:22:32 -06001336 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001337 if isinstance(typ, list):
1338 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001339 typ = self._make_array_type(typ[0], info)
1340 typ = self._make_implicit_object_type(
1341 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001342 return QAPISchemaObjectTypeVariant(case, typ)
1343
Markus Armbrusterac882192015-09-16 13:06:05 +02001344 def _def_union_type(self, expr, info):
1345 name = expr['union']
1346 data = expr['data']
1347 base = expr.get('base')
1348 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001349 tag_member = None
Markus Armbrusterac882192015-09-16 13:06:05 +02001350 if tag_name:
1351 variants = [self._make_variant(key, value)
1352 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001353 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001354 else:
Eric Blake99df5282015-10-12 22:22:32 -06001355 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001356 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001357 typ = self._make_implicit_enum_type(name, info,
1358 [v.name for v in variants])
1359 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001360 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001361 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001362 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001363 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001364 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001365 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001366
1367 def _def_alternate_type(self, expr, info):
1368 name = expr['alternate']
1369 data = expr['data']
1370 variants = [self._make_variant(key, value)
1371 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001372 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001373 self._def_entity(
1374 QAPISchemaAlternateType(name, info,
1375 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001376 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001377 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001378
1379 def _def_command(self, expr, info):
1380 name = expr['command']
1381 data = expr.get('data')
1382 rets = expr.get('returns')
1383 gen = expr.get('gen', True)
1384 success_response = expr.get('success-response', True)
1385 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001386 data = self._make_implicit_object_type(
1387 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001388 if isinstance(rets, list):
1389 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001390 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001391 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1392 success_response))
1393
1394 def _def_event(self, expr, info):
1395 name = expr['event']
1396 data = expr.get('data')
1397 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001398 data = self._make_implicit_object_type(
1399 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001400 self._def_entity(QAPISchemaEvent(name, info, data))
1401
1402 def _def_exprs(self):
1403 for expr_elem in self.exprs:
1404 expr = expr_elem['expr']
1405 info = expr_elem['info']
1406 if 'enum' in expr:
1407 self._def_enum_type(expr, info)
1408 elif 'struct' in expr:
1409 self._def_struct_type(expr, info)
1410 elif 'union' in expr:
1411 self._def_union_type(expr, info)
1412 elif 'alternate' in expr:
1413 self._def_alternate_type(expr, info)
1414 elif 'command' in expr:
1415 self._def_command(expr, info)
1416 elif 'event' in expr:
1417 self._def_event(expr, info)
1418 else:
1419 assert False
1420
1421 def check(self):
1422 for ent in self._entity_dict.values():
1423 ent.check(self)
1424
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001425 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001426 visitor.visit_begin(self)
1427 for (name, entity) in sorted(self._entity_dict.items()):
1428 if visitor.visit_needed(entity):
1429 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001430 visitor.visit_end()
1431
Markus Armbruster2caba362013-07-27 17:41:56 +02001432
Markus Armbruster00e4b282015-06-10 10:04:36 +02001433#
1434# Code generation helpers
1435#
1436
Michael Roth0f923be2011-07-19 14:50:39 -05001437def camel_case(name):
1438 new_name = ''
1439 first = True
1440 for ch in name:
1441 if ch in ['_', '-']:
1442 first = True
1443 elif first:
1444 new_name += ch.upper()
1445 first = False
1446 else:
1447 new_name += ch.lower()
1448 return new_name
1449
Eric Blake437db252015-09-29 16:21:02 -06001450
Markus Armbruster849bc532015-05-14 06:50:53 -06001451# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1452# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1453# ENUM24_Name -> ENUM24_NAME
1454def camel_to_upper(value):
1455 c_fun_str = c_name(value, False)
1456 if value.isupper():
1457 return c_fun_str
1458
1459 new_name = ''
1460 l = len(c_fun_str)
1461 for i in range(l):
1462 c = c_fun_str[i]
1463 # When c is upper and no "_" appears before, do more checks
1464 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001465 if i < l - 1 and c_fun_str[i + 1].islower():
1466 new_name += '_'
1467 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001468 new_name += '_'
1469 new_name += c
1470 return new_name.lstrip('_').upper()
1471
Eric Blake437db252015-09-29 16:21:02 -06001472
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001473def c_enum_const(type_name, const_name, prefix=None):
1474 if prefix is not None:
1475 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001476 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001477
Eric Blake18df5152015-05-14 06:50:48 -06001478c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001479
Eric Blake437db252015-09-29 16:21:02 -06001480
Eric Blakec6405b52015-05-14 06:50:55 -06001481# Map @name to a valid C identifier.
1482# If @protect, avoid returning certain ticklish identifiers (like
1483# C keywords) by prepending "q_".
1484#
1485# Used for converting 'name' from a 'name':'type' qapi definition
1486# into a generated struct member, as well as converting type names
1487# into substrings of a generated C function name.
1488# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1489# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001490def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001491 # ANSI X3J11/88-090, 3.1.1
1492 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001493 'default', 'do', 'double', 'else', 'enum', 'extern',
1494 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1495 'return', 'short', 'signed', 'sizeof', 'static',
1496 'struct', 'switch', 'typedef', 'union', 'unsigned',
1497 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001498 # ISO/IEC 9899:1999, 6.4.1
1499 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1500 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001501 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1502 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001503 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1504 # excluding _.*
1505 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001506 # C++ ISO/IEC 14882:2003 2.11
1507 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1508 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1509 'namespace', 'new', 'operator', 'private', 'protected',
1510 'public', 'reinterpret_cast', 'static_cast', 'template',
1511 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1512 'using', 'virtual', 'wchar_t',
1513 # alternative representations
1514 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1515 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001516 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001517 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001518 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001519 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1520 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001521 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001522 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001523
Amos Kong05dfb262014-06-10 19:25:53 +08001524eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001525pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001526
Eric Blake437db252015-09-29 16:21:02 -06001527
Michael Roth0f923be2011-07-19 14:50:39 -05001528def genindent(count):
1529 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001530 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001531 ret += " "
1532 return ret
1533
1534indent_level = 0
1535
Eric Blake437db252015-09-29 16:21:02 -06001536
Michael Roth0f923be2011-07-19 14:50:39 -05001537def push_indent(indent_amount=4):
1538 global indent_level
1539 indent_level += indent_amount
1540
Eric Blake437db252015-09-29 16:21:02 -06001541
Michael Roth0f923be2011-07-19 14:50:39 -05001542def pop_indent(indent_amount=4):
1543 global indent_level
1544 indent_level -= indent_amount
1545
Eric Blake437db252015-09-29 16:21:02 -06001546
Markus Armbruster77e703b2015-06-24 19:27:32 +02001547# Generate @code with @kwds interpolated.
1548# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001549def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001550 raw = code % kwds
1551 if indent_level:
1552 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001553 # re.subn() lacks flags support before Python 2.7, use re.compile()
1554 raw = re.subn(re.compile("^.", re.MULTILINE),
1555 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001556 raw = raw[0]
1557 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001558
Eric Blake437db252015-09-29 16:21:02 -06001559
Michael Roth0f923be2011-07-19 14:50:39 -05001560def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001561 if code[0] == '\n':
1562 code = code[1:]
1563 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001564
Michael Roth0f923be2011-07-19 14:50:39 -05001565
1566def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001567 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001568
Eric Blake437db252015-09-29 16:21:02 -06001569
Michael Rothc0afa9c2013-05-10 17:46:00 -05001570def guardstart(name):
1571 return mcgen('''
1572
1573#ifndef %(name)s
1574#define %(name)s
1575
1576''',
1577 name=guardname(name))
1578
Eric Blake437db252015-09-29 16:21:02 -06001579
Michael Rothc0afa9c2013-05-10 17:46:00 -05001580def guardend(name):
1581 return mcgen('''
1582
1583#endif /* %(name)s */
1584
1585''',
1586 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001587
Eric Blake437db252015-09-29 16:21:02 -06001588
Markus Armbrustere98859a2015-09-16 13:06:16 +02001589def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001590 ret = mcgen('''
1591
Markus Armbrustere98859a2015-09-16 13:06:16 +02001592const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001593''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001594 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001595 for value in values:
1596 index = c_enum_const(name, value, prefix)
1597 ret += mcgen('''
1598 [%(index)s] = "%(value)s",
1599''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001600 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001601
Eric Blake7fb1cf12015-11-18 01:52:57 -07001602 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001603 ret += mcgen('''
1604 [%(max_index)s] = NULL,
1605};
1606''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001607 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001608 return ret
1609
Eric Blake437db252015-09-29 16:21:02 -06001610
Markus Armbrustere98859a2015-09-16 13:06:16 +02001611def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001612 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001613 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001614
1615 ret = mcgen('''
1616
1617typedef enum %(c_name)s {
1618''',
1619 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001620
1621 i = 0
1622 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001623 ret += mcgen('''
1624 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001625''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001626 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001627 i=i)
1628 i += 1
1629
Markus Armbrustere98859a2015-09-16 13:06:16 +02001630 ret += mcgen('''
1631} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001632''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001633 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001634
Markus Armbrustere98859a2015-09-16 13:06:16 +02001635 ret += mcgen('''
1636
1637extern const char *const %(c_name)s_lookup[];
1638''',
1639 c_name=c_name(name))
1640 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001641
Eric Blake437db252015-09-29 16:21:02 -06001642
Markus Armbruster03b43672015-09-16 13:06:20 +02001643def gen_params(arg_type, extra):
1644 if not arg_type:
1645 return extra
1646 assert not arg_type.variants
1647 ret = ''
1648 sep = ''
1649 for memb in arg_type.members:
1650 ret += sep
1651 sep = ', '
1652 if memb.optional:
1653 ret += 'bool has_%s, ' % c_name(memb.name)
Eric Blake4040d992016-03-17 16:48:28 -06001654 ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001655 if extra:
1656 ret += sep + extra
1657 return ret
1658
Eric Blake1f353342015-09-29 16:21:13 -06001659
Eric Blake18bdbc32015-09-29 16:21:15 -06001660def gen_err_check(label='out', skiperr=False):
1661 if skiperr:
Eric Blake1f353342015-09-29 16:21:13 -06001662 return ''
1663 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001664 if (err) {
Eric Blake1f353342015-09-29 16:21:13 -06001665 goto %(label)s;
1666 }
1667''',
Eric Blake18bdbc32015-09-29 16:21:15 -06001668 label=label)
Eric Blake1f353342015-09-29 16:21:13 -06001669
1670
Eric Blake14f00c62016-03-03 09:16:43 -07001671def gen_visit_members(members, prefix='', need_cast=False, skiperr=False,
1672 label='out'):
Eric Blake82ca8e42015-09-29 16:21:14 -06001673 ret = ''
Eric Blake18bdbc32015-09-29 16:21:15 -06001674 if skiperr:
Eric Blake82ca8e42015-09-29 16:21:14 -06001675 errparg = 'NULL'
Eric Blake18bdbc32015-09-29 16:21:15 -06001676 else:
1677 errparg = '&err'
Eric Blake82ca8e42015-09-29 16:21:14 -06001678
1679 for memb in members:
1680 if memb.optional:
1681 ret += mcgen('''
Eric Blake51e72bc2016-01-29 06:48:54 -07001682 if (visit_optional(v, "%(name)s", &%(prefix)shas_%(c_name)s)) {
Eric Blake82ca8e42015-09-29 16:21:14 -06001683''',
1684 prefix=prefix, c_name=c_name(memb.name),
Eric Blakee4083112016-01-29 06:48:41 -07001685 name=memb.name)
Eric Blake82ca8e42015-09-29 16:21:14 -06001686 push_indent()
1687
1688 # Ugly: sometimes we need to cast away const
1689 if need_cast and memb.type.name == 'str':
1690 cast = '(char **)'
1691 else:
1692 cast = ''
1693
1694 ret += mcgen('''
Eric Blake51e72bc2016-01-29 06:48:54 -07001695 visit_type_%(c_type)s(v, "%(name)s", %(cast)s&%(prefix)s%(c_name)s, %(errp)s);
Eric Blake82ca8e42015-09-29 16:21:14 -06001696''',
1697 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1698 c_name=c_name(memb.name), name=memb.name,
1699 errp=errparg)
Eric Blakea16e3e52016-01-29 06:48:46 -07001700 ret += gen_err_check(skiperr=skiperr, label=label)
Eric Blake82ca8e42015-09-29 16:21:14 -06001701
1702 if memb.optional:
1703 pop_indent()
1704 ret += mcgen('''
1705 }
1706''')
1707 return ret
1708
1709
Markus Armbruster00e4b282015-06-10 10:04:36 +02001710#
1711# Common command line parsing
1712#
1713
Eric Blake437db252015-09-29 16:21:02 -06001714
1715def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001716
1717 try:
1718 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001719 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001720 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001721 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001722 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001723 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001724 sys.exit(1)
1725
1726 output_dir = ""
1727 prefix = ""
1728 do_c = False
1729 do_h = False
1730 extra_opts = []
1731
1732 for oa in opts:
1733 o, a = oa
1734 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001735 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1736 if match.end() != len(a):
1737 print >>sys.stderr, \
1738 "%s: 'funny character '%s' in argument of --prefix" \
1739 % (sys.argv[0], a[match.end()])
1740 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001741 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001742 elif o in ("-o", "--output-dir"):
1743 output_dir = a + "/"
1744 elif o in ("-c", "--source"):
1745 do_c = True
1746 elif o in ("-h", "--header"):
1747 do_h = True
1748 else:
1749 extra_opts.append(oa)
1750
1751 if not do_c and not do_h:
1752 do_c = True
1753 do_h = True
1754
Markus Armbruster16d80f62015-04-02 13:32:16 +02001755 if len(args) != 1:
1756 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001757 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001758 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001759
Markus Armbruster54414042015-06-09 16:22:45 +02001760 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001761
Markus Armbruster00e4b282015-06-10 10:04:36 +02001762#
1763# Generate output files with boilerplate
1764#
1765
Eric Blake437db252015-09-29 16:21:02 -06001766
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001767def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1768 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001769 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001770 c_file = output_dir + prefix + c_file
1771 h_file = output_dir + prefix + h_file
1772
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001773 if output_dir:
1774 try:
1775 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01001776 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001777 if e.errno != errno.EEXIST:
1778 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001779
1780 def maybe_open(really, name, opt):
1781 if really:
1782 return open(name, opt)
1783 else:
1784 import StringIO
1785 return StringIO.StringIO()
1786
1787 fdef = maybe_open(do_c, c_file, 'w')
1788 fdecl = maybe_open(do_h, h_file, 'w')
1789
1790 fdef.write(mcgen('''
1791/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1792%(comment)s
1793''',
Eric Blake437db252015-09-29 16:21:02 -06001794 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001795
1796 fdecl.write(mcgen('''
1797/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1798%(comment)s
1799#ifndef %(guard)s
1800#define %(guard)s
1801
1802''',
Eric Blake437db252015-09-29 16:21:02 -06001803 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001804
1805 return (fdef, fdecl)
1806
Eric Blake437db252015-09-29 16:21:02 -06001807
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001808def close_output(fdef, fdecl):
1809 fdecl.write('''
1810#endif
1811''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001812 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001813 fdef.close()