blob: 21bc32fda3d1e1d59f76d7b22c126deea236ea8c [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
Eric Blake893e1f22015-12-01 22:20:57 -070066 'CpuInfoMIPS', # PC, visible through query-cpu
67 'CpuInfoTricore', # PC, visible through query-cpu
Eric Blake893e1f22015-12-01 22:20:57 -070068 'QapiErrorClass', # all members, visible through errors
69 'UuidInfo', # UUID, visible through query-uuid
70 'X86CPURegister32', # all members, visible indirectly through qom-get
Eric Blake3666a972016-03-17 16:48:40 -060071 'q_obj_CpuInfo-base', # CPU, visible through query-cpu
Eric Blake893e1f22015-12-01 22:20:57 -070072]
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):
Eric Blakeac4338f2016-03-17 16:48:39 -0600330 if isinstance(base, dict):
331 return base
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800332 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
Eric Blake14f00c62016-03-03 09:16:43 -0700360 base_members = find_base_members(base)
361 if not base_members:
Wenchao Xiabceae762014-03-06 17:08:56 -0800362 return None
363
Eric Blake14f00c62016-03-03 09:16:43 -0700364 discriminator_type = base_members.get(discriminator)
Wenchao Xiabceae762014-03-06 17:08:56 -0800365 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 Blake75996972016-03-17 16:48:29 -0600396 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
397 # and 'q_obj_*' implicit type names.
Eric Blake9fb081e2015-10-26 16:34:44 -0600398 if not valid_name.match(membername) or \
399 c_name(membername, False).startswith('q_'):
Eric Blakec9e0a792015-05-04 09:05:22 -0600400 raise QAPIExprError(expr_info,
401 "%s uses invalid name '%s'" % (source, name))
402
Eric Blake437db252015-09-29 16:21:02 -0600403
404def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200405 global all_names
406 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200407 # FIXME should reject names that differ only in '_' vs. '.'
408 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200409 if name in all_names:
410 raise QAPIExprError(info,
411 "%s '%s' is already defined"
412 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600413 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200414 raise QAPIExprError(info,
Eric Blake255960d2015-10-26 16:34:43 -0600415 "%s '%s' should not end in '%s'"
416 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200417 all_names[name] = meta
418
Eric Blake437db252015-09-29 16:21:02 -0600419
Markus Armbruster00e4b282015-06-10 10:04:36 +0200420def add_struct(definition, info):
421 global struct_types
422 name = definition['struct']
423 add_name(name, info, 'struct')
424 struct_types.append(definition)
425
Eric Blake437db252015-09-29 16:21:02 -0600426
Markus Armbruster00e4b282015-06-10 10:04:36 +0200427def find_struct(name):
428 global struct_types
429 for struct in struct_types:
430 if struct['struct'] == name:
431 return struct
432 return None
433
Eric Blake437db252015-09-29 16:21:02 -0600434
Markus Armbruster00e4b282015-06-10 10:04:36 +0200435def add_union(definition, info):
436 global union_types
437 name = definition['union']
438 add_name(name, info, 'union')
439 union_types.append(definition)
440
Eric Blake437db252015-09-29 16:21:02 -0600441
Markus Armbruster00e4b282015-06-10 10:04:36 +0200442def find_union(name):
443 global union_types
444 for union in union_types:
445 if union['union'] == name:
446 return union
447 return None
448
Eric Blake437db252015-09-29 16:21:02 -0600449
450def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200451 global enum_types
452 add_name(name, info, 'enum', implicit)
453 enum_types.append({"enum_name": name, "enum_values": enum_values})
454
Eric Blake437db252015-09-29 16:21:02 -0600455
Markus Armbruster00e4b282015-06-10 10:04:36 +0200456def find_enum(name):
457 global enum_types
458 for enum in enum_types:
459 if enum['enum_name'] == name:
460 return enum
461 return None
462
Markus Armbruster00e4b282015-06-10 10:04:36 +0200463
Eric Blake437db252015-09-29 16:21:02 -0600464def is_enum(name):
465 return find_enum(name) is not None
466
467
468def check_type(expr_info, source, value, allow_array=False,
469 allow_dict=False, allow_optional=False,
470 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600471 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600472
473 if value is None:
474 return
475
Eric Blakedd883c62015-05-04 09:05:21 -0600476 # Check if array type for value is okay
477 if isinstance(value, list):
478 if not allow_array:
479 raise QAPIExprError(expr_info,
480 "%s cannot be an array" % source)
481 if len(value) != 1 or not isinstance(value[0], str):
482 raise QAPIExprError(expr_info,
483 "%s: array type must contain single type name"
484 % source)
485 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600486
487 # Check if type name for value is okay
488 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600489 if value not in all_names:
Eric Blakedd883c62015-05-04 09:05:21 -0600490 raise QAPIExprError(expr_info,
491 "%s uses unknown type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200492 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600493 if not all_names[value] in allow_metas:
494 raise QAPIExprError(expr_info,
495 "%s cannot use %s type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200496 % (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600497 return
498
Eric Blakedd883c62015-05-04 09:05:21 -0600499 if not allow_dict:
500 raise QAPIExprError(expr_info,
501 "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200502
503 if not isinstance(value, OrderedDict):
504 raise QAPIExprError(expr_info,
505 "%s should be a dictionary or type name" % source)
506
507 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600508 for (key, arg) in value.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600509 check_name(expr_info, "Member of %s" % source, key,
510 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600511 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Eric Blake9fb081e2015-10-26 16:34:44 -0600512 raise QAPIExprError(expr_info,
513 "Member of %s uses reserved name '%s'"
514 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600515 # Todo: allow dictionaries to represent default values of
516 # an optional argument.
Eric Blakedd883c62015-05-04 09:05:21 -0600517 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200518 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600519 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600520 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600521
Eric Blake437db252015-09-29 16:21:02 -0600522
Eric Blakedd883c62015-05-04 09:05:21 -0600523def check_command(expr, expr_info):
524 name = expr['command']
Eric Blakec8184082016-07-13 21:50:20 -0600525 boxed = expr.get('boxed', False)
Eric Blake2cbf0992015-05-04 09:05:24 -0600526
Eric Blakec8184082016-07-13 21:50:20 -0600527 args_meta = ['struct']
528 if boxed:
529 args_meta += ['union', 'alternate']
Eric Blakedd883c62015-05-04 09:05:21 -0600530 check_type(expr_info, "'data' for command '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600531 expr.get('data'), allow_dict=not boxed, allow_optional=True,
532 allow_metas=args_meta)
Eric Blake10d4d992015-05-04 09:05:23 -0600533 returns_meta = ['union', 'struct']
534 if name in returns_whitelist:
535 returns_meta += ['built-in', 'alternate', 'enum']
Eric Blakedd883c62015-05-04 09:05:21 -0600536 check_type(expr_info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200537 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200538 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600539
Eric Blake437db252015-09-29 16:21:02 -0600540
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200541def check_event(expr, expr_info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600542 global events
543 name = expr['event']
Eric Blakec8184082016-07-13 21:50:20 -0600544 boxed = expr.get('boxed', False)
Eric Blake4dc2e692015-05-04 09:05:17 -0600545
Eric Blakec8184082016-07-13 21:50:20 -0600546 meta = ['struct']
547 if boxed:
548 meta += ['union', 'alternate']
Eric Blake4dc2e692015-05-04 09:05:17 -0600549 events.append(name)
Eric Blakedd883c62015-05-04 09:05:21 -0600550 check_type(expr_info, "'data' for event '%s'" % name,
Eric Blakec8184082016-07-13 21:50:20 -0600551 expr.get('data'), allow_dict=not boxed, allow_optional=True,
552 allow_metas=meta)
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200553
Eric Blake437db252015-09-29 16:21:02 -0600554
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800555def check_union(expr, expr_info):
556 name = expr['union']
557 base = expr.get('base')
558 discriminator = expr.get('discriminator')
559 members = expr['data']
560
Eric Blake811d04f2015-05-04 09:05:10 -0600561 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600562
563 # With no discriminator it is a simple union.
564 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600565 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600566 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600567 if base is not None:
568 raise QAPIExprError(expr_info,
Eric Blake811d04f2015-05-04 09:05:10 -0600569 "Simple union '%s' must not have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600570 % name)
571
572 # Else, it's a flat union.
573 else:
Eric Blakeac4338f2016-03-17 16:48:39 -0600574 # The object must have a string or dictionary 'base'.
Eric Blake376863e2015-09-29 16:21:07 -0600575 check_type(expr_info, "'base' for union '%s'" % name,
Eric Blakeac4338f2016-03-17 16:48:39 -0600576 base, allow_dict=True, allow_optional=True,
577 allow_metas=['struct'])
Eric Blake376863e2015-09-29 16:21:07 -0600578 if not base:
Eric Blake44bd1272015-05-04 09:05:08 -0600579 raise QAPIExprError(expr_info,
Eric Blake376863e2015-09-29 16:21:07 -0600580 "Flat union '%s' must have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600581 % name)
Eric Blake14f00c62016-03-03 09:16:43 -0700582 base_members = find_base_members(base)
583 assert base_members
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800584
Eric Blakec9e0a792015-05-04 09:05:22 -0600585 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600586 # member of the base struct.
Eric Blakec9e0a792015-05-04 09:05:22 -0600587 check_name(expr_info, "Discriminator of flat union '%s'" % name,
588 discriminator)
Eric Blake14f00c62016-03-03 09:16:43 -0700589 discriminator_type = base_members.get(discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800590 if not discriminator_type:
591 raise QAPIExprError(expr_info,
592 "Discriminator '%s' is not a member of base "
Eric Blakefd41dd42015-05-04 09:05:25 -0600593 "struct '%s'"
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800594 % (discriminator, base))
595 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600596 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800597 # Do not allow string discriminator
598 if not enum_define:
599 raise QAPIExprError(expr_info,
600 "Discriminator '%s' must be of enumeration "
601 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800602
Eric Blake02a57ae2016-02-17 23:48:16 -0700603 # Check every branch; don't allow an empty union
604 if len(members) == 0:
605 raise QAPIExprError(expr_info,
606 "Union '%s' cannot have empty 'data'" % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800607 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600608 check_name(expr_info, "Member of union '%s'" % name, key)
609
Eric Blake01cfbaa2015-12-01 22:20:58 -0700610 # Each value must name a known type
Eric Blakedd883c62015-05-04 09:05:21 -0600611 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200612 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600613
Eric Blake44bd1272015-05-04 09:05:08 -0600614 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700615 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600616 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600617 if key not in enum_define['enum_values']:
Eric Blake44bd1272015-05-04 09:05:08 -0600618 raise QAPIExprError(expr_info,
619 "Discriminator value '%s' is not found in "
620 "enum '%s'" %
621 (key, enum_define["enum_name"]))
622
Eric Blaked0b18232016-07-13 21:50:13 -0600623 # If discriminator is user-defined, ensure all values are covered
624 if enum_define:
625 for value in enum_define['enum_values']:
626 if value not in members.keys():
627 raise QAPIExprError(expr_info,
628 "Union '%s' data missing '%s' branch"
629 % (name, value))
630
Eric Blake437db252015-09-29 16:21:02 -0600631
Eric Blake811d04f2015-05-04 09:05:10 -0600632def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600633 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600634 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600635 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600636
Eric Blake02a57ae2016-02-17 23:48:16 -0700637 # Check every branch; require at least two branches
638 if len(members) < 2:
639 raise QAPIExprError(expr_info,
640 "Alternate '%s' should have at least two branches "
641 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600642 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600643 check_name(expr_info, "Member of alternate '%s'" % name, key)
644
Eric Blake811d04f2015-05-04 09:05:10 -0600645 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600646 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
647 value,
648 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600649 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700650 if not qtype:
651 raise QAPIExprError(expr_info,
652 "Alternate '%s' member '%s' cannot use "
653 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600654 if qtype in types_seen:
655 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600656 "Alternate '%s' member '%s' can't "
Eric Blake811d04f2015-05-04 09:05:10 -0600657 "be distinguished from member '%s'"
658 % (name, key, types_seen[qtype]))
659 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800660
Eric Blake437db252015-09-29 16:21:02 -0600661
Eric Blakecf393592015-05-04 09:05:04 -0600662def check_enum(expr, expr_info):
663 name = expr['enum']
664 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100665 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600666
667 if not isinstance(members, list):
668 raise QAPIExprError(expr_info,
669 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100670 if prefix is not None and not isinstance(prefix, str):
671 raise QAPIExprError(expr_info,
672 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600673 for member in members:
Eric Blake437db252015-09-29 16:21:02 -0600674 check_name(expr_info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600675 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600676
Eric Blake437db252015-09-29 16:21:02 -0600677
Eric Blakedd883c62015-05-04 09:05:21 -0600678def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600679 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600680 members = expr['data']
681
Eric Blakefd41dd42015-05-04 09:05:25 -0600682 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600683 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600684 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600685 allow_metas=['struct'])
686
Eric Blake437db252015-09-29 16:21:02 -0600687
Eric Blake0545f6b2015-05-04 09:05:15 -0600688def check_keys(expr_elem, meta, required, optional=[]):
689 expr = expr_elem['expr']
690 info = expr_elem['info']
691 name = expr[meta]
692 if not isinstance(name, str):
693 raise QAPIExprError(info,
694 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600695 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600696 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600697 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600698 raise QAPIExprError(info,
699 "Unknown key '%s' in %s '%s'"
700 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600701 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600702 raise QAPIExprError(info,
703 "'%s' of %s '%s' should only use false value"
704 % (key, meta, name))
Eric Blakec8184082016-07-13 21:50:20 -0600705 if key == 'boxed' and value is not True:
706 raise QAPIExprError(info,
707 "'%s' of %s '%s' should only use true value"
708 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600709 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600710 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600711 raise QAPIExprError(info,
712 "Key '%s' is missing from %s '%s'"
713 % (key, meta, name))
714
Eric Blake437db252015-09-29 16:21:02 -0600715
Markus Armbruster4d076d62015-06-10 08:55:21 +0200716def check_exprs(exprs):
717 global all_names
718
719 # Learn the types and check for valid expression keys
720 for builtin in builtin_types.keys():
721 all_names[builtin] = 'built-in'
722 for expr_elem in exprs:
723 expr = expr_elem['expr']
724 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600725 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100726 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200727 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600728 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200729 check_keys(expr_elem, 'union', ['data'],
730 ['base', 'discriminator'])
731 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600732 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200733 check_keys(expr_elem, 'alternate', ['data'])
734 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600735 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200736 check_keys(expr_elem, 'struct', ['data'], ['base'])
737 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600738 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200739 check_keys(expr_elem, 'command', [],
Eric Blakec8184082016-07-13 21:50:20 -0600740 ['data', 'returns', 'gen', 'success-response', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200741 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600742 elif 'event' in expr:
Eric Blakec8184082016-07-13 21:50:20 -0600743 check_keys(expr_elem, 'event', [], ['data', 'boxed'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200744 add_name(expr['event'], info, 'event')
745 else:
746 raise QAPIExprError(expr_elem['info'],
747 "Expression is missing metatype")
748
749 # Try again for hidden UnionKind enum
750 for expr_elem in exprs:
751 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600752 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200753 if not discriminator_find_enum_define(expr):
754 add_enum('%sKind' % expr['union'], expr_elem['info'],
755 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600756 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200757 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
758 implicit=True)
759
760 # Validate that exprs make sense
761 for expr_elem in exprs:
762 expr = expr_elem['expr']
763 info = expr_elem['info']
764
Eric Blake437db252015-09-29 16:21:02 -0600765 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200766 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600767 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200768 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600769 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200770 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600771 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200772 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600773 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200774 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600775 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200776 check_event(expr, info)
777 else:
778 assert False, 'unexpected meta type'
779
Markus Armbrusterac882192015-09-16 13:06:05 +0200780 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600781
Markus Armbrusterac882192015-09-16 13:06:05 +0200782
783#
784# Schema compiler frontend
785#
786
787class QAPISchemaEntity(object):
788 def __init__(self, name, info):
789 assert isinstance(name, str)
790 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -0600791 # For explicitly defined entities, info points to the (explicit)
792 # definition. For builtins (and their arrays), info is None.
793 # For implicitly defined entities, info points to a place that
794 # triggered the implicit definition (there may be more than one
795 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +0200796 self.info = info
797
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200798 def c_name(self):
799 return c_name(self.name)
800
Markus Armbrusterac882192015-09-16 13:06:05 +0200801 def check(self, schema):
802 pass
803
Eric Blake49823c42015-10-12 22:22:27 -0600804 def is_implicit(self):
805 return not self.info
806
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200807 def visit(self, visitor):
808 pass
809
810
811class QAPISchemaVisitor(object):
812 def visit_begin(self, schema):
813 pass
814
815 def visit_end(self):
816 pass
817
Eric Blake25a0d9c2015-10-12 22:22:21 -0600818 def visit_needed(self, entity):
819 # Default to visiting everything
820 return True
821
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200822 def visit_builtin_type(self, name, info, json_type):
823 pass
824
825 def visit_enum_type(self, name, info, values, prefix):
826 pass
827
828 def visit_array_type(self, name, info, element_type):
829 pass
830
831 def visit_object_type(self, name, info, base, members, variants):
832 pass
833
Markus Armbruster39a18152015-09-16 13:06:28 +0200834 def visit_object_type_flat(self, name, info, members, variants):
835 pass
836
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200837 def visit_alternate_type(self, name, info, variants):
838 pass
839
840 def visit_command(self, name, info, arg_type, ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -0600841 gen, success_response, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200842 pass
843
Eric Blake48825ca2016-07-13 21:50:19 -0600844 def visit_event(self, name, info, arg_type, boxed):
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200845 pass
846
Markus Armbrusterac882192015-09-16 13:06:05 +0200847
848class QAPISchemaType(QAPISchemaEntity):
Eric Blake4040d992016-03-17 16:48:28 -0600849 # Return the C type for common use.
850 # For the types we commonly box, this is a pointer type.
851 def c_type(self):
852 pass
853
854 # Return the C type to be used in a parameter list.
855 def c_param_type(self):
856 return self.c_type()
857
858 # Return the C type to be used where we suppress boxing.
859 def c_unboxed_type(self):
860 return self.c_type()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200861
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200862 def json_type(self):
863 pass
864
865 def alternate_qtype(self):
866 json2qtype = {
867 'string': 'QTYPE_QSTRING',
868 'number': 'QTYPE_QFLOAT',
869 'int': 'QTYPE_QINT',
870 'boolean': 'QTYPE_QBOOL',
871 'object': 'QTYPE_QDICT'
872 }
873 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200874
875
876class QAPISchemaBuiltinType(QAPISchemaType):
Eric Blake861877a2016-03-17 16:48:36 -0600877 def __init__(self, name, json_type, c_type):
Markus Armbrusterac882192015-09-16 13:06:05 +0200878 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200879 assert not c_type or isinstance(c_type, str)
880 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
881 'value')
882 self._json_type_name = json_type
883 self._c_type_name = c_type
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200884
885 def c_name(self):
886 return self.name
887
Eric Blake4040d992016-03-17 16:48:28 -0600888 def c_type(self):
889 return self._c_type_name
890
891 def c_param_type(self):
892 if self.name == 'str':
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200893 return 'const ' + self._c_type_name
894 return self._c_type_name
895
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200896 def json_type(self):
897 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200898
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200899 def visit(self, visitor):
900 visitor.visit_builtin_type(self.name, self.info, self.json_type())
901
Markus Armbrusterac882192015-09-16 13:06:05 +0200902
903class QAPISchemaEnumType(QAPISchemaType):
904 def __init__(self, name, info, values, prefix):
905 QAPISchemaType.__init__(self, name, info)
906 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -0700907 assert isinstance(v, QAPISchemaMember)
908 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200909 assert prefix is None or isinstance(prefix, str)
910 self.values = values
911 self.prefix = prefix
912
913 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -0700914 seen = {}
915 for v in self.values:
916 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200917
Eric Blake99df5282015-10-12 22:22:32 -0600918 def is_implicit(self):
919 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -0600920 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -0600921
Eric Blake4040d992016-03-17 16:48:28 -0600922 def c_type(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200923 return c_name(self.name)
924
Eric Blake93bda4d2015-12-01 22:20:55 -0700925 def member_names(self):
926 return [v.name for v in self.values]
927
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200928 def json_type(self):
929 return 'string'
930
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200931 def visit(self, visitor):
932 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -0700933 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200934
Markus Armbrusterac882192015-09-16 13:06:05 +0200935
936class QAPISchemaArrayType(QAPISchemaType):
937 def __init__(self, name, info, element_type):
938 QAPISchemaType.__init__(self, name, info)
939 assert isinstance(element_type, str)
940 self._element_type_name = element_type
941 self.element_type = None
942
943 def check(self, schema):
944 self.element_type = schema.lookup_type(self._element_type_name)
945 assert self.element_type
946
Eric Blake99df5282015-10-12 22:22:32 -0600947 def is_implicit(self):
948 return True
949
Eric Blake4040d992016-03-17 16:48:28 -0600950 def c_type(self):
951 return c_name(self.name) + pointer_suffix
952
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200953 def json_type(self):
954 return 'array'
955
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200956 def visit(self, visitor):
957 visitor.visit_array_type(self.name, self.info, self.element_type)
958
Markus Armbrusterac882192015-09-16 13:06:05 +0200959
960class QAPISchemaObjectType(QAPISchemaType):
961 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -0700962 # struct has local_members, optional base, and no variants
963 # flat union has base, variants, and no local_members
964 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +0200965 QAPISchemaType.__init__(self, name, info)
966 assert base is None or isinstance(base, str)
967 for m in local_members:
968 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -0700969 m.set_owner(name)
970 if variants is not None:
971 assert isinstance(variants, QAPISchemaObjectTypeVariants)
972 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200973 self._base_name = base
974 self.base = None
975 self.local_members = local_members
976 self.variants = variants
977 self.members = None
978
979 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -0700980 if self.members is False: # check for cycles
981 raise QAPIExprError(self.info,
982 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200983 if self.members:
984 return
985 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -0700986 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +0200987 if self._base_name:
988 self.base = schema.lookup_type(self._base_name)
989 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +0200990 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700991 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200992 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -0700993 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700994 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700995 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +0200996 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -0700997 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700998 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -0700999 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001000
Eric Blake14f00c62016-03-03 09:16:43 -07001001 # Check that the members of this type do not cause duplicate JSON members,
Eric Blake27b60ab2015-11-18 01:52:51 -07001002 # and update seen to track the members seen so far. Report any errors
1003 # on behalf of info, which is not necessarily self.info
1004 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -07001005 assert not self.variants # not implemented
1006 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -07001007 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -07001008
Eric Blake99df5282015-10-12 22:22:32 -06001009 def is_implicit(self):
Eric Blake75996972016-03-17 16:48:29 -06001010 # See QAPISchema._make_implicit_object_type(), as well as
1011 # _def_predefineds()
1012 return self.name.startswith('q_')
Eric Blake99df5282015-10-12 22:22:32 -06001013
Eric Blakeb6167702016-07-13 21:50:16 -06001014 def is_empty(self):
1015 assert self.members is not None
1016 return not self.members and not self.variants
1017
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001018 def c_name(self):
Eric Blakecd50a252016-07-13 21:50:14 -06001019 assert self.name != 'q_empty'
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001020 return QAPISchemaType.c_name(self)
1021
Eric Blake4040d992016-03-17 16:48:28 -06001022 def c_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001023 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -07001024 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001025
Eric Blake4040d992016-03-17 16:48:28 -06001026 def c_unboxed_type(self):
Eric Blake4040d992016-03-17 16:48:28 -06001027 return c_name(self.name)
1028
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001029 def json_type(self):
1030 return 'object'
1031
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001032 def visit(self, visitor):
1033 visitor.visit_object_type(self.name, self.info,
1034 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001035 visitor.visit_object_type_flat(self.name, self.info,
1036 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001037
Markus Armbrusterac882192015-09-16 13:06:05 +02001038
Eric Blaked44f9ac2015-12-01 22:20:54 -07001039class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001040 role = 'member'
1041
Eric Blaked44f9ac2015-12-01 22:20:54 -07001042 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001043 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001044 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001045 self.owner = None
1046
1047 def set_owner(self, name):
1048 assert not self.owner
1049 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001050
Eric Blake27b60ab2015-11-18 01:52:51 -07001051 def check_clash(self, info, seen):
1052 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001053 if cname.lower() != cname and self.owner not in case_whitelist:
1054 raise QAPIExprError(info,
1055 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001056 if cname in seen:
1057 raise QAPIExprError(info,
1058 "%s collides with %s"
1059 % (self.describe(), seen[cname].describe()))
1060 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001061
Eric Blake88d4ef82015-11-18 01:52:50 -07001062 def _pretty_owner(self):
1063 owner = self.owner
Eric Blake75996972016-03-17 16:48:29 -06001064 if owner.startswith('q_obj_'):
Eric Blake88d4ef82015-11-18 01:52:50 -07001065 # See QAPISchema._make_implicit_object_type() - reverse the
1066 # mapping there to create a nice human-readable description
Eric Blake75996972016-03-17 16:48:29 -06001067 owner = owner[6:]
Eric Blake88d4ef82015-11-18 01:52:50 -07001068 if owner.endswith('-arg'):
1069 return '(parameter of %s)' % owner[:-4]
Eric Blakeac4338f2016-03-17 16:48:39 -06001070 elif owner.endswith('-base'):
1071 return '(base of %s)' % owner[:-5]
Eric Blake88d4ef82015-11-18 01:52:50 -07001072 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))
Eric Blake02a57ae2016-02-17 23:48:16 -07001109 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001110 for v in variants:
1111 assert isinstance(v, QAPISchemaObjectTypeVariant)
Eric Blakeda9cb192016-07-13 21:50:15 -06001112 self._tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001113 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001114 self.variants = variants
1115
Eric Blake88d4ef82015-11-18 01:52:50 -07001116 def set_owner(self, name):
1117 for v in self.variants:
1118 v.set_owner(name)
1119
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001120 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001121 if not self.tag_member: # flat union
Eric Blakeda9cb192016-07-13 21:50:15 -06001122 self.tag_member = seen[c_name(self._tag_name)]
1123 assert self._tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001124 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1125 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001126 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001127 # Union names must match enum values; alternate names are
1128 # checked separately. Use 'seen' to tell the two apart.
1129 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001130 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001131 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001132 v.type.check(schema)
1133
Eric Blake27b60ab2015-11-18 01:52:51 -07001134 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001135 for v in self.variants:
1136 # Reset seen map for each variant, since qapi names from one
1137 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001138 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001139 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001140
Eric Blake437db252015-09-29 16:21:02 -06001141
Markus Armbrusterac882192015-09-16 13:06:05 +02001142class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001143 role = 'branch'
1144
Markus Armbrusterac882192015-09-16 13:06:05 +02001145 def __init__(self, name, typ):
1146 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1147
Markus Armbrusterac882192015-09-16 13:06:05 +02001148
1149class QAPISchemaAlternateType(QAPISchemaType):
1150 def __init__(self, name, info, variants):
1151 QAPISchemaType.__init__(self, name, info)
1152 assert isinstance(variants, QAPISchemaObjectTypeVariants)
Eric Blakeda9cb192016-07-13 21:50:15 -06001153 assert variants.tag_member
Eric Blake88d4ef82015-11-18 01:52:50 -07001154 variants.set_owner(name)
1155 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001156 self.variants = variants
1157
1158 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001159 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001160 # Not calling self.variants.check_clash(), because there's nothing
1161 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001162 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001163 # Alternate branch names have no relation to the tag enum values;
1164 # so we have to check for potential name collisions ourselves.
1165 seen = {}
1166 for v in self.variants.variants:
1167 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001168
Eric Blake4040d992016-03-17 16:48:28 -06001169 def c_type(self):
1170 return c_name(self.name) + pointer_suffix
1171
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001172 def json_type(self):
1173 return 'value'
1174
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001175 def visit(self, visitor):
1176 visitor.visit_alternate_type(self.name, self.info, self.variants)
1177
Eric Blakec8184082016-07-13 21:50:20 -06001178 def is_empty(self):
1179 return False
1180
Markus Armbrusterac882192015-09-16 13:06:05 +02001181
1182class QAPISchemaCommand(QAPISchemaEntity):
Eric Blake48825ca2016-07-13 21:50:19 -06001183 def __init__(self, name, info, arg_type, ret_type, gen, success_response,
1184 boxed):
Markus Armbrusterac882192015-09-16 13:06:05 +02001185 QAPISchemaEntity.__init__(self, name, info)
1186 assert not arg_type or isinstance(arg_type, str)
1187 assert not ret_type or isinstance(ret_type, str)
1188 self._arg_type_name = arg_type
1189 self.arg_type = None
1190 self._ret_type_name = ret_type
1191 self.ret_type = None
1192 self.gen = gen
1193 self.success_response = success_response
Eric Blake48825ca2016-07-13 21:50:19 -06001194 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001195
1196 def check(self, schema):
1197 if self._arg_type_name:
1198 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001199 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1200 isinstance(self.arg_type, QAPISchemaAlternateType))
1201 self.arg_type.check(schema)
1202 if self.boxed:
1203 if self.arg_type.is_empty():
1204 raise QAPIExprError(self.info,
1205 "Cannot use 'boxed' with empty type")
1206 else:
1207 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1208 assert not self.arg_type.variants
1209 elif self.boxed:
1210 raise QAPIExprError(self.info,
1211 "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001212 if self._ret_type_name:
1213 self.ret_type = schema.lookup_type(self._ret_type_name)
1214 assert isinstance(self.ret_type, QAPISchemaType)
1215
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001216 def visit(self, visitor):
1217 visitor.visit_command(self.name, self.info,
1218 self.arg_type, self.ret_type,
Eric Blake48825ca2016-07-13 21:50:19 -06001219 self.gen, self.success_response, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001220
Markus Armbrusterac882192015-09-16 13:06:05 +02001221
1222class QAPISchemaEvent(QAPISchemaEntity):
Eric Blake48825ca2016-07-13 21:50:19 -06001223 def __init__(self, name, info, arg_type, boxed):
Markus Armbrusterac882192015-09-16 13:06:05 +02001224 QAPISchemaEntity.__init__(self, name, info)
1225 assert not arg_type or isinstance(arg_type, str)
1226 self._arg_type_name = arg_type
1227 self.arg_type = None
Eric Blake48825ca2016-07-13 21:50:19 -06001228 self.boxed = boxed
Markus Armbrusterac882192015-09-16 13:06:05 +02001229
1230 def check(self, schema):
1231 if self._arg_type_name:
1232 self.arg_type = schema.lookup_type(self._arg_type_name)
Eric Blakec8184082016-07-13 21:50:20 -06001233 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1234 isinstance(self.arg_type, QAPISchemaAlternateType))
1235 self.arg_type.check(schema)
1236 if self.boxed:
1237 if self.arg_type.is_empty():
1238 raise QAPIExprError(self.info,
1239 "Cannot use 'boxed' with empty type")
1240 else:
1241 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1242 assert not self.arg_type.variants
1243 elif self.boxed:
1244 raise QAPIExprError(self.info,
1245 "Use of 'boxed' requires 'data'")
Markus Armbrusterac882192015-09-16 13:06:05 +02001246
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001247 def visit(self, visitor):
Eric Blake48825ca2016-07-13 21:50:19 -06001248 visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001249
Markus Armbrusterac882192015-09-16 13:06:05 +02001250
1251class QAPISchema(object):
1252 def __init__(self, fname):
1253 try:
1254 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001255 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001256 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001257 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001258 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001259 self._def_exprs()
1260 self.check()
Markus Armbruster291928a2015-12-18 08:52:41 +01001261 except (QAPISchemaError, QAPIExprError) as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001262 print >>sys.stderr, err
1263 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001264
Markus Armbrusterac882192015-09-16 13:06:05 +02001265 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001266 # Only the predefined types are allowed to not have info
1267 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001268 assert ent.name not in self._entity_dict
1269 self._entity_dict[ent.name] = ent
1270
1271 def lookup_entity(self, name, typ=None):
1272 ent = self._entity_dict.get(name)
1273 if typ and not isinstance(ent, typ):
1274 return None
1275 return ent
1276
1277 def lookup_type(self, name):
1278 return self.lookup_entity(name, QAPISchemaType)
1279
Eric Blake861877a2016-03-17 16:48:36 -06001280 def _def_builtin_type(self, name, json_type, c_type):
1281 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001282 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1283 # qapi-types.h from a single .c, all arrays of builtins must be
1284 # declared in the first file whether or not they are used. Nicer
1285 # would be to use lazy instantiation, while figuring out how to
1286 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001287 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001288
1289 def _def_predefineds(self):
Eric Blake861877a2016-03-17 16:48:36 -06001290 for t in [('str', 'string', 'char' + pointer_suffix),
1291 ('number', 'number', 'double'),
1292 ('int', 'int', 'int64_t'),
1293 ('int8', 'int', 'int8_t'),
1294 ('int16', 'int', 'int16_t'),
1295 ('int32', 'int', 'int32_t'),
1296 ('int64', 'int', 'int64_t'),
1297 ('uint8', 'int', 'uint8_t'),
1298 ('uint16', 'int', 'uint16_t'),
1299 ('uint32', 'int', 'uint32_t'),
1300 ('uint64', 'int', 'uint64_t'),
1301 ('size', 'int', 'uint64_t'),
1302 ('bool', 'boolean', 'bool'),
1303 ('any', 'value', 'QObject' + pointer_suffix)]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001304 self._def_builtin_type(*t)
Eric Blake75996972016-03-17 16:48:29 -06001305 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1306 None, [], None)
Markus Armbruster39a18152015-09-16 13:06:28 +02001307 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001308 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1309 'qstring', 'qdict', 'qlist',
1310 'qfloat', 'qbool'])
1311 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001312 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001313
Eric Blake93bda4d2015-12-01 22:20:55 -07001314 def _make_enum_members(self, values):
1315 return [QAPISchemaMember(v) for v in values]
1316
Eric Blake99df5282015-10-12 22:22:32 -06001317 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001318 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001319 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001320 self._def_entity(QAPISchemaEnumType(
1321 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001322 return name
1323
Eric Blake99df5282015-10-12 22:22:32 -06001324 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001325 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001326 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001327 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001328 return name
1329
Eric Blake99df5282015-10-12 22:22:32 -06001330 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001331 if not members:
1332 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001333 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake75996972016-03-17 16:48:29 -06001334 name = 'q_obj_%s-%s' % (name, role)
Markus Armbrusterac882192015-09-16 13:06:05 +02001335 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001336 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001337 members, None))
1338 return name
1339
1340 def _def_enum_type(self, expr, info):
1341 name = expr['enum']
1342 data = expr['data']
1343 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001344 self._def_entity(QAPISchemaEnumType(
1345 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001346
Eric Blake99df5282015-10-12 22:22:32 -06001347 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001348 optional = False
1349 if name.startswith('*'):
1350 name = name[1:]
1351 optional = True
1352 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)
Markus Armbrusterac882192015-09-16 13:06:05 +02001355 return QAPISchemaObjectTypeMember(name, typ, optional)
1356
Eric Blake99df5282015-10-12 22:22:32 -06001357 def _make_members(self, data, info):
1358 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001359 for (key, value) in data.iteritems()]
1360
1361 def _def_struct_type(self, expr, info):
1362 name = expr['struct']
1363 base = expr.get('base')
1364 data = expr['data']
1365 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001366 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001367 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001368
1369 def _make_variant(self, case, typ):
1370 return QAPISchemaObjectTypeVariant(case, typ)
1371
Eric Blake99df5282015-10-12 22:22:32 -06001372 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001373 if isinstance(typ, list):
1374 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001375 typ = self._make_array_type(typ[0], info)
1376 typ = self._make_implicit_object_type(
1377 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001378 return QAPISchemaObjectTypeVariant(case, typ)
1379
Markus Armbrusterac882192015-09-16 13:06:05 +02001380 def _def_union_type(self, expr, info):
1381 name = expr['union']
1382 data = expr['data']
1383 base = expr.get('base')
1384 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001385 tag_member = None
Eric Blakeac4338f2016-03-17 16:48:39 -06001386 if isinstance(base, dict):
1387 base = (self._make_implicit_object_type(
1388 name, info, 'base', self._make_members(base, info)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001389 if tag_name:
1390 variants = [self._make_variant(key, value)
1391 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001392 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001393 else:
Eric Blake99df5282015-10-12 22:22:32 -06001394 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001395 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001396 typ = self._make_implicit_enum_type(name, info,
1397 [v.name for v in variants])
1398 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001399 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001400 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001401 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001402 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001403 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001404 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001405
1406 def _def_alternate_type(self, expr, info):
1407 name = expr['alternate']
1408 data = expr['data']
1409 variants = [self._make_variant(key, value)
1410 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001411 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001412 self._def_entity(
1413 QAPISchemaAlternateType(name, info,
1414 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001415 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001416 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001417
1418 def _def_command(self, expr, info):
1419 name = expr['command']
1420 data = expr.get('data')
1421 rets = expr.get('returns')
1422 gen = expr.get('gen', True)
1423 success_response = expr.get('success-response', True)
Eric Blake48825ca2016-07-13 21:50:19 -06001424 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001425 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001426 data = self._make_implicit_object_type(
1427 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001428 if isinstance(rets, list):
1429 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001430 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001431 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
Eric Blake48825ca2016-07-13 21:50:19 -06001432 success_response, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001433
1434 def _def_event(self, expr, info):
1435 name = expr['event']
1436 data = expr.get('data')
Eric Blake48825ca2016-07-13 21:50:19 -06001437 boxed = expr.get('boxed', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001438 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001439 data = self._make_implicit_object_type(
1440 name, info, 'arg', self._make_members(data, info))
Eric Blake48825ca2016-07-13 21:50:19 -06001441 self._def_entity(QAPISchemaEvent(name, info, data, boxed))
Markus Armbrusterac882192015-09-16 13:06:05 +02001442
1443 def _def_exprs(self):
1444 for expr_elem in self.exprs:
1445 expr = expr_elem['expr']
1446 info = expr_elem['info']
1447 if 'enum' in expr:
1448 self._def_enum_type(expr, info)
1449 elif 'struct' in expr:
1450 self._def_struct_type(expr, info)
1451 elif 'union' in expr:
1452 self._def_union_type(expr, info)
1453 elif 'alternate' in expr:
1454 self._def_alternate_type(expr, info)
1455 elif 'command' in expr:
1456 self._def_command(expr, info)
1457 elif 'event' in expr:
1458 self._def_event(expr, info)
1459 else:
1460 assert False
1461
1462 def check(self):
1463 for ent in self._entity_dict.values():
1464 ent.check(self)
1465
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001466 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001467 visitor.visit_begin(self)
1468 for (name, entity) in sorted(self._entity_dict.items()):
1469 if visitor.visit_needed(entity):
1470 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001471 visitor.visit_end()
1472
Markus Armbruster2caba362013-07-27 17:41:56 +02001473
Markus Armbruster00e4b282015-06-10 10:04:36 +02001474#
1475# Code generation helpers
1476#
1477
Michael Roth0f923be2011-07-19 14:50:39 -05001478def camel_case(name):
1479 new_name = ''
1480 first = True
1481 for ch in name:
1482 if ch in ['_', '-']:
1483 first = True
1484 elif first:
1485 new_name += ch.upper()
1486 first = False
1487 else:
1488 new_name += ch.lower()
1489 return new_name
1490
Eric Blake437db252015-09-29 16:21:02 -06001491
Markus Armbruster849bc532015-05-14 06:50:53 -06001492# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1493# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1494# ENUM24_Name -> ENUM24_NAME
1495def camel_to_upper(value):
1496 c_fun_str = c_name(value, False)
1497 if value.isupper():
1498 return c_fun_str
1499
1500 new_name = ''
1501 l = len(c_fun_str)
1502 for i in range(l):
1503 c = c_fun_str[i]
1504 # When c is upper and no "_" appears before, do more checks
1505 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001506 if i < l - 1 and c_fun_str[i + 1].islower():
1507 new_name += '_'
1508 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001509 new_name += '_'
1510 new_name += c
1511 return new_name.lstrip('_').upper()
1512
Eric Blake437db252015-09-29 16:21:02 -06001513
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001514def c_enum_const(type_name, const_name, prefix=None):
1515 if prefix is not None:
1516 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001517 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001518
Eric Blake18df5152015-05-14 06:50:48 -06001519c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001520
Eric Blake437db252015-09-29 16:21:02 -06001521
Eric Blakec6405b52015-05-14 06:50:55 -06001522# Map @name to a valid C identifier.
1523# If @protect, avoid returning certain ticklish identifiers (like
1524# C keywords) by prepending "q_".
1525#
1526# Used for converting 'name' from a 'name':'type' qapi definition
1527# into a generated struct member, as well as converting type names
1528# into substrings of a generated C function name.
1529# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1530# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001531def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001532 # ANSI X3J11/88-090, 3.1.1
1533 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001534 'default', 'do', 'double', 'else', 'enum', 'extern',
1535 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1536 'return', 'short', 'signed', 'sizeof', 'static',
1537 'struct', 'switch', 'typedef', 'union', 'unsigned',
1538 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001539 # ISO/IEC 9899:1999, 6.4.1
1540 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1541 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001542 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1543 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001544 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1545 # excluding _.*
1546 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001547 # C++ ISO/IEC 14882:2003 2.11
1548 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1549 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1550 'namespace', 'new', 'operator', 'private', 'protected',
1551 'public', 'reinterpret_cast', 'static_cast', 'template',
1552 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1553 'using', 'virtual', 'wchar_t',
1554 # alternative representations
1555 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1556 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001557 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001558 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001559 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001560 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1561 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001562 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001563 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001564
Amos Kong05dfb262014-06-10 19:25:53 +08001565eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001566pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001567
Eric Blake437db252015-09-29 16:21:02 -06001568
Michael Roth0f923be2011-07-19 14:50:39 -05001569def genindent(count):
1570 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001571 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001572 ret += " "
1573 return ret
1574
1575indent_level = 0
1576
Eric Blake437db252015-09-29 16:21:02 -06001577
Michael Roth0f923be2011-07-19 14:50:39 -05001578def push_indent(indent_amount=4):
1579 global indent_level
1580 indent_level += indent_amount
1581
Eric Blake437db252015-09-29 16:21:02 -06001582
Michael Roth0f923be2011-07-19 14:50:39 -05001583def pop_indent(indent_amount=4):
1584 global indent_level
1585 indent_level -= indent_amount
1586
Eric Blake437db252015-09-29 16:21:02 -06001587
Markus Armbruster77e703b2015-06-24 19:27:32 +02001588# Generate @code with @kwds interpolated.
1589# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001590def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001591 raw = code % kwds
1592 if indent_level:
1593 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001594 # re.subn() lacks flags support before Python 2.7, use re.compile()
1595 raw = re.subn(re.compile("^.", re.MULTILINE),
1596 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001597 raw = raw[0]
1598 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001599
Eric Blake437db252015-09-29 16:21:02 -06001600
Michael Roth0f923be2011-07-19 14:50:39 -05001601def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001602 if code[0] == '\n':
1603 code = code[1:]
1604 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001605
Michael Roth0f923be2011-07-19 14:50:39 -05001606
1607def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001608 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001609
Eric Blake437db252015-09-29 16:21:02 -06001610
Michael Rothc0afa9c2013-05-10 17:46:00 -05001611def guardstart(name):
1612 return mcgen('''
1613
1614#ifndef %(name)s
1615#define %(name)s
1616
1617''',
1618 name=guardname(name))
1619
Eric Blake437db252015-09-29 16:21:02 -06001620
Michael Rothc0afa9c2013-05-10 17:46:00 -05001621def guardend(name):
1622 return mcgen('''
1623
1624#endif /* %(name)s */
1625
1626''',
1627 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001628
Eric Blake437db252015-09-29 16:21:02 -06001629
Markus Armbrustere98859a2015-09-16 13:06:16 +02001630def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001631 ret = mcgen('''
1632
Markus Armbrustere98859a2015-09-16 13:06:16 +02001633const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001634''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001635 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001636 for value in values:
1637 index = c_enum_const(name, value, prefix)
1638 ret += mcgen('''
1639 [%(index)s] = "%(value)s",
1640''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001641 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001642
Eric Blake7fb1cf12015-11-18 01:52:57 -07001643 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001644 ret += mcgen('''
1645 [%(max_index)s] = NULL,
1646};
1647''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001648 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001649 return ret
1650
Eric Blake437db252015-09-29 16:21:02 -06001651
Markus Armbrustere98859a2015-09-16 13:06:16 +02001652def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001653 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001654 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001655
1656 ret = mcgen('''
1657
1658typedef enum %(c_name)s {
1659''',
1660 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001661
1662 i = 0
1663 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001664 ret += mcgen('''
1665 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001666''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001667 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001668 i=i)
1669 i += 1
1670
Markus Armbrustere98859a2015-09-16 13:06:16 +02001671 ret += mcgen('''
1672} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001673''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001674 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001675
Markus Armbrustere98859a2015-09-16 13:06:16 +02001676 ret += mcgen('''
1677
1678extern const char *const %(c_name)s_lookup[];
1679''',
1680 c_name=c_name(name))
1681 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001682
Eric Blake437db252015-09-29 16:21:02 -06001683
Eric Blake48825ca2016-07-13 21:50:19 -06001684def gen_params(arg_type, boxed, extra):
Markus Armbruster03b43672015-09-16 13:06:20 +02001685 if not arg_type:
Eric Blakec8184082016-07-13 21:50:20 -06001686 assert not boxed
Markus Armbruster03b43672015-09-16 13:06:20 +02001687 return extra
Markus Armbruster03b43672015-09-16 13:06:20 +02001688 ret = ''
1689 sep = ''
Eric Blake48825ca2016-07-13 21:50:19 -06001690 if boxed:
Eric Blakec8184082016-07-13 21:50:20 -06001691 ret += '%s arg' % arg_type.c_param_type()
1692 sep = ', '
Eric Blake48825ca2016-07-13 21:50:19 -06001693 else:
1694 assert not arg_type.variants
1695 for memb in arg_type.members:
1696 ret += sep
1697 sep = ', '
1698 if memb.optional:
1699 ret += 'bool has_%s, ' % c_name(memb.name)
1700 ret += '%s %s' % (memb.type.c_param_type(),
1701 c_name(memb.name))
Markus Armbruster03b43672015-09-16 13:06:20 +02001702 if extra:
1703 ret += sep + extra
1704 return ret
1705
Eric Blake1f353342015-09-29 16:21:13 -06001706
Markus Armbruster00e4b282015-06-10 10:04:36 +02001707#
1708# Common command line parsing
1709#
1710
Eric Blake437db252015-09-29 16:21:02 -06001711
1712def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001713
1714 try:
1715 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001716 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001717 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001718 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001719 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001720 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001721 sys.exit(1)
1722
1723 output_dir = ""
1724 prefix = ""
1725 do_c = False
1726 do_h = False
1727 extra_opts = []
1728
1729 for oa in opts:
1730 o, a = oa
1731 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001732 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1733 if match.end() != len(a):
1734 print >>sys.stderr, \
1735 "%s: 'funny character '%s' in argument of --prefix" \
1736 % (sys.argv[0], a[match.end()])
1737 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001738 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001739 elif o in ("-o", "--output-dir"):
1740 output_dir = a + "/"
1741 elif o in ("-c", "--source"):
1742 do_c = True
1743 elif o in ("-h", "--header"):
1744 do_h = True
1745 else:
1746 extra_opts.append(oa)
1747
1748 if not do_c and not do_h:
1749 do_c = True
1750 do_h = True
1751
Markus Armbruster16d80f62015-04-02 13:32:16 +02001752 if len(args) != 1:
1753 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001754 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001755 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001756
Markus Armbruster54414042015-06-09 16:22:45 +02001757 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001758
Markus Armbruster00e4b282015-06-10 10:04:36 +02001759#
1760# Generate output files with boilerplate
1761#
1762
Eric Blake437db252015-09-29 16:21:02 -06001763
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001764def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1765 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001766 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001767 c_file = output_dir + prefix + c_file
1768 h_file = output_dir + prefix + h_file
1769
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001770 if output_dir:
1771 try:
1772 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01001773 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001774 if e.errno != errno.EEXIST:
1775 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001776
1777 def maybe_open(really, name, opt):
1778 if really:
1779 return open(name, opt)
1780 else:
1781 import StringIO
1782 return StringIO.StringIO()
1783
1784 fdef = maybe_open(do_c, c_file, 'w')
1785 fdecl = maybe_open(do_h, h_file, 'w')
1786
1787 fdef.write(mcgen('''
1788/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1789%(comment)s
1790''',
Eric Blake437db252015-09-29 16:21:02 -06001791 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001792
1793 fdecl.write(mcgen('''
1794/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1795%(comment)s
1796#ifndef %(guard)s
1797#define %(guard)s
1798
1799''',
Eric Blake437db252015-09-29 16:21:02 -06001800 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001801
1802 return (fdef, fdecl)
1803
Eric Blake437db252015-09-29 16:21:02 -06001804
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001805def close_output(fdef, fdecl):
1806 fdecl.write('''
1807#endif
1808''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001809 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001810 fdef.close()