blob: 543b378d7e70b3653338da9b47b6349138f69d04 [file] [log] [blame]
Michael Roth0f923be2011-07-19 14:50:39 -05001#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
Eric Blakefe2a9302015-05-04 09:05:02 -06005# Copyright (c) 2013-2015 Red Hat Inc.
Michael Roth0f923be2011-07-19 14:50:39 -05006#
7# Authors:
8# Anthony Liguori <aliguori@us.ibm.com>
Markus Armbrusterc7a3f252013-07-27 17:41:55 +02009# Markus Armbruster <armbru@redhat.com>
Michael Roth0f923be2011-07-19 14:50:39 -050010#
Markus Armbruster678e48a2014-03-01 08:40:34 +010011# This work is licensed under the terms of the GNU GPL, version 2.
12# See the COPYING file in the top-level directory.
Michael Roth0f923be2011-07-19 14:50:39 -050013
Lluís Vilanovaa719a272014-05-07 20:46:15 +020014import re
Michael Roth0f923be2011-07-19 14:50:39 -050015from ordereddict import OrderedDict
Markus Armbruster12f8e1b2015-04-02 14:46:39 +020016import errno
Markus Armbruster2114f5a2015-04-02 13:12:21 +020017import getopt
Lluís Vilanova33aaad52014-05-02 15:52:35 +020018import os
Markus Armbruster2caba362013-07-27 17:41:56 +020019import sys
Markus Armbruster47299262015-05-14 06:50:47 -060020import string
Michael Roth0f923be2011-07-19 14:50:39 -050021
Eric Blakeb52c4b92015-05-04 09:05:00 -060022builtin_types = {
Kevin Wolf69dd62d2013-07-08 16:14:21 +020023 'str': 'QTYPE_QSTRING',
24 'int': 'QTYPE_QINT',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
27 'int8': 'QTYPE_QINT',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
Eric Blakecb17f792015-05-04 09:05:01 -060035 'size': 'QTYPE_QINT',
Markus Armbruster28770e02015-09-16 13:06:24 +020036 'any': None, # any qtype_code possible, actually
Kevin Wolf69dd62d2013-07-08 16:14:21 +020037}
38
Eric Blake10d4d992015-05-04 09:05:23 -060039# Whitelist of commands allowed to return a non-dictionary
40returns_whitelist = [
41 # From QMP:
42 'human-monitor-command',
Markus Armbruster6eb39372015-09-16 13:06:25 +020043 'qom-get',
Eric Blake10d4d992015-05-04 09:05:23 -060044 'query-migrate-cache-size',
45 'query-tpm-models',
46 'query-tpm-types',
47 'ringbuf-read',
48
49 # From QGA:
50 'guest-file-open',
51 'guest-fsfreeze-freeze',
52 'guest-fsfreeze-freeze-list',
53 'guest-fsfreeze-status',
54 'guest-fsfreeze-thaw',
55 'guest-get-time',
56 'guest-set-vcpus',
57 'guest-sync',
58 'guest-sync-delimited',
59
60 # From qapi-schema-test:
61 'user_def_cmd3',
62]
63
Eric Blake4dc2e692015-05-04 09:05:17 -060064enum_types = []
65struct_types = []
66union_types = []
67events = []
68all_names = {}
69
Markus Armbruster00e4b282015-06-10 10:04:36 +020070#
71# Parsing the schema into expressions
72#
73
Eric Blake437db252015-09-29 16:21:02 -060074
Lluís Vilanovaa719a272014-05-07 20:46:15 +020075def error_path(parent):
76 res = ""
77 while parent:
78 res = ("In file included from %s:%d:\n" % (parent['file'],
79 parent['line'])) + res
80 parent = parent['parent']
81 return res
82
Eric Blake437db252015-09-29 16:21:02 -060083
Markus Armbruster2caba362013-07-27 17:41:56 +020084class QAPISchemaError(Exception):
85 def __init__(self, schema, msg):
Eric Blake59b00542015-09-29 16:21:01 -060086 Exception.__init__(self)
Markus Armbruster54414042015-06-09 16:22:45 +020087 self.fname = schema.fname
Markus Armbruster2caba362013-07-27 17:41:56 +020088 self.msg = msg
Wenchao Xia515b9432014-03-04 18:44:33 -080089 self.col = 1
90 self.line = schema.line
91 for ch in schema.src[schema.line_pos:schema.pos]:
92 if ch == '\t':
Markus Armbruster2caba362013-07-27 17:41:56 +020093 self.col = (self.col + 7) % 8 + 1
94 else:
95 self.col += 1
Markus Armbruster54414042015-06-09 16:22:45 +020096 self.info = schema.incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +020097
98 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +020099 return error_path(self.info) + \
Markus Armbruster54414042015-06-09 16:22:45 +0200100 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
Markus Armbruster2caba362013-07-27 17:41:56 +0200101
Eric Blake437db252015-09-29 16:21:02 -0600102
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800103class QAPIExprError(Exception):
104 def __init__(self, expr_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -0600105 Exception.__init__(self)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200106 self.info = expr_info
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800107 self.msg = msg
108
109 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200110 return error_path(self.info['parent']) + \
111 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800112
Eric Blake437db252015-09-29 16:21:02 -0600113
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200114class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500115
Eric Blake437db252015-09-29 16:21:02 -0600116 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200117 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200118 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200119 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200120 previously_included.append(abs_fname)
121 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200122 self.src = fp.read()
123 if self.src == '' or self.src[-1] != '\n':
124 self.src += '\n'
125 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800126 self.line = 1
127 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200128 self.exprs = []
129 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500130
Eric Blake437db252015-09-29 16:21:02 -0600131 while self.tok is not None:
Markus Armbruster54414042015-06-09 16:22:45 +0200132 expr_info = {'file': fname, 'line': self.line,
133 'parent': self.incl_info}
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200134 expr = self.get_expr(False)
135 if isinstance(expr, dict) and "include" in expr:
136 if len(expr) != 1:
Eric Blake437db252015-09-29 16:21:02 -0600137 raise QAPIExprError(expr_info,
138 "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200139 include = expr["include"]
140 if not isinstance(include, str):
141 raise QAPIExprError(expr_info,
Eric Blake7408fb62015-09-29 16:21:00 -0600142 "Value of 'include' must be a string")
Markus Armbruster54414042015-06-09 16:22:45 +0200143 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
144 include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200145 # catch inclusion cycle
146 inf = expr_info
147 while inf:
148 if incl_abs_fname == os.path.abspath(inf['file']):
Stefan Hajnoczi7ac9a9d2014-08-27 12:08:51 +0100149 raise QAPIExprError(expr_info, "Inclusion loop for %s"
150 % include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200151 inf = inf['parent']
Benoît Canet24fd8482014-05-16 12:51:56 +0200152 # skip multiple include of the same file
Markus Armbruster54414042015-06-09 16:22:45 +0200153 if incl_abs_fname in previously_included:
Benoît Canet24fd8482014-05-16 12:51:56 +0200154 continue
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200155 try:
Markus Armbruster54414042015-06-09 16:22:45 +0200156 fobj = open(incl_abs_fname, 'r')
Luiz Capitulino34788812014-05-20 13:50:19 -0400157 except IOError, e:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200158 raise QAPIExprError(expr_info,
159 '%s: %s' % (e.strerror, include))
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200160 exprs_include = QAPISchemaParser(fobj, previously_included,
161 expr_info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200162 self.exprs.extend(exprs_include.exprs)
163 else:
164 expr_elem = {'expr': expr,
165 'info': expr_info}
166 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500167
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200168 def accept(self):
169 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200170 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200171 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200172 self.cursor += 1
173 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500174
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200175 if self.tok == '#':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200176 self.cursor = self.src.find('\n', self.cursor)
177 elif self.tok in ['{', '}', ':', ',', '[', ']']:
178 return
179 elif self.tok == "'":
180 string = ''
181 esc = False
182 while True:
183 ch = self.src[self.cursor]
184 self.cursor += 1
185 if ch == '\n':
Markus Armbruster2caba362013-07-27 17:41:56 +0200186 raise QAPISchemaError(self,
187 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200188 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600189 if ch == 'b':
190 string += '\b'
191 elif ch == 'f':
192 string += '\f'
193 elif ch == 'n':
194 string += '\n'
195 elif ch == 'r':
196 string += '\r'
197 elif ch == 't':
198 string += '\t'
199 elif ch == 'u':
200 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600201 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600202 ch = self.src[self.cursor]
203 self.cursor += 1
204 if ch not in "0123456789abcdefABCDEF":
205 raise QAPISchemaError(self,
206 '\\u escape needs 4 '
207 'hex digits')
208 value = (value << 4) + int(ch, 16)
209 # If Python 2 and 3 didn't disagree so much on
210 # how to handle Unicode, then we could allow
211 # Unicode string defaults. But most of QAPI is
212 # ASCII-only, so we aren't losing much for now.
213 if not value or value > 0x7f:
214 raise QAPISchemaError(self,
215 'For now, \\u escape '
216 'only supports non-zero '
217 'values up to \\u007f')
218 string += chr(value)
219 elif ch in "\\/'\"":
220 string += ch
221 else:
222 raise QAPISchemaError(self,
Eric Blake437db252015-09-29 16:21:02 -0600223 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200224 esc = False
225 elif ch == "\\":
226 esc = True
227 elif ch == "'":
228 self.val = string
229 return
230 else:
231 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200232 elif self.src.startswith("true", self.pos):
233 self.val = True
234 self.cursor += 3
235 return
236 elif self.src.startswith("false", self.pos):
237 self.val = False
238 self.cursor += 4
239 return
240 elif self.src.startswith("null", self.pos):
241 self.val = None
242 self.cursor += 3
243 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200244 elif self.tok == '\n':
245 if self.cursor == len(self.src):
246 self.tok = None
247 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800248 self.line += 1
249 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200250 elif not self.tok.isspace():
251 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500252
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200253 def get_members(self):
254 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200255 if self.tok == '}':
256 self.accept()
257 return expr
258 if self.tok != "'":
259 raise QAPISchemaError(self, 'Expected string or "}"')
260 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200261 key = self.val
262 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200263 if self.tok != ':':
264 raise QAPISchemaError(self, 'Expected ":"')
265 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800266 if key in expr:
267 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200268 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200269 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200270 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200271 return expr
272 if self.tok != ',':
273 raise QAPISchemaError(self, 'Expected "," or "}"')
274 self.accept()
275 if self.tok != "'":
276 raise QAPISchemaError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500277
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200278 def get_values(self):
279 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200280 if self.tok == ']':
281 self.accept()
282 return expr
Eric Blake437db252015-09-29 16:21:02 -0600283 if self.tok not in "{['tfn":
Fam Zhenge53188a2015-05-04 09:05:18 -0600284 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
285 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200286 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200287 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200288 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200289 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200290 return expr
291 if self.tok != ',':
292 raise QAPISchemaError(self, 'Expected "," or "]"')
293 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500294
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200295 def get_expr(self, nested):
296 if self.tok != '{' and not nested:
297 raise QAPISchemaError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200298 if self.tok == '{':
299 self.accept()
300 expr = self.get_members()
301 elif self.tok == '[':
302 self.accept()
303 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600304 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200305 expr = self.val
306 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200307 else:
308 raise QAPISchemaError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200309 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200310
Markus Armbruster00e4b282015-06-10 10:04:36 +0200311#
312# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200313# TODO fold into QAPISchema
314# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200315#
316
Eric Blake437db252015-09-29 16:21:02 -0600317
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800318def find_base_fields(base):
319 base_struct_define = find_struct(base)
320 if not base_struct_define:
321 return None
322 return base_struct_define['data']
323
Eric Blake437db252015-09-29 16:21:02 -0600324
Eric Blake811d04f2015-05-04 09:05:10 -0600325# Return the qtype of an alternate branch, or None on error.
326def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600327 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600328 return builtin_types[qapi_type]
329 elif find_struct(qapi_type):
330 return "QTYPE_QDICT"
331 elif find_enum(qapi_type):
332 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600333 elif find_union(qapi_type):
334 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600335 return None
336
Eric Blake437db252015-09-29 16:21:02 -0600337
Wenchao Xiabceae762014-03-06 17:08:56 -0800338# Return the discriminator enum define if discriminator is specified as an
339# enum type, otherwise return None.
340def discriminator_find_enum_define(expr):
341 base = expr.get('base')
342 discriminator = expr.get('discriminator')
343
344 if not (discriminator and base):
345 return None
346
347 base_fields = find_base_fields(base)
348 if not base_fields:
349 return None
350
351 discriminator_type = base_fields.get(discriminator)
352 if not discriminator_type:
353 return None
354
355 return find_enum(discriminator_type)
356
Eric Blake437db252015-09-29 16:21:02 -0600357
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200358# FIXME should enforce "other than downstream extensions [...], all
359# names should begin with a letter".
Eric Blakec9e0a792015-05-04 09:05:22 -0600360valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600361
362
363def check_name(expr_info, source, name, allow_optional=False,
364 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600365 global valid_name
366 membername = name
367
368 if not isinstance(name, str):
369 raise QAPIExprError(expr_info,
370 "%s requires a string name" % source)
371 if name.startswith('*'):
372 membername = name[1:]
373 if not allow_optional:
374 raise QAPIExprError(expr_info,
375 "%s does not allow optional name '%s'"
376 % (source, name))
377 # Enum members can start with a digit, because the generated C
378 # code always prefixes it with the enum name
379 if enum_member:
380 membername = '_' + membername
381 if not valid_name.match(membername):
382 raise QAPIExprError(expr_info,
383 "%s uses invalid name '%s'" % (source, name))
384
Eric Blake437db252015-09-29 16:21:02 -0600385
386def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200387 global all_names
388 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200389 # FIXME should reject names that differ only in '_' vs. '.'
390 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200391 if name in all_names:
392 raise QAPIExprError(info,
393 "%s '%s' is already defined"
394 % (all_names[name], name))
395 if not implicit and name[-4:] == 'Kind':
396 raise QAPIExprError(info,
397 "%s '%s' should not end in 'Kind'"
398 % (meta, name))
399 all_names[name] = meta
400
Eric Blake437db252015-09-29 16:21:02 -0600401
Markus Armbruster00e4b282015-06-10 10:04:36 +0200402def add_struct(definition, info):
403 global struct_types
404 name = definition['struct']
405 add_name(name, info, 'struct')
406 struct_types.append(definition)
407
Eric Blake437db252015-09-29 16:21:02 -0600408
Markus Armbruster00e4b282015-06-10 10:04:36 +0200409def find_struct(name):
410 global struct_types
411 for struct in struct_types:
412 if struct['struct'] == name:
413 return struct
414 return None
415
Eric Blake437db252015-09-29 16:21:02 -0600416
Markus Armbruster00e4b282015-06-10 10:04:36 +0200417def add_union(definition, info):
418 global union_types
419 name = definition['union']
420 add_name(name, info, 'union')
421 union_types.append(definition)
422
Eric Blake437db252015-09-29 16:21:02 -0600423
Markus Armbruster00e4b282015-06-10 10:04:36 +0200424def find_union(name):
425 global union_types
426 for union in union_types:
427 if union['union'] == name:
428 return union
429 return None
430
Eric Blake437db252015-09-29 16:21:02 -0600431
432def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200433 global enum_types
434 add_name(name, info, 'enum', implicit)
435 enum_types.append({"enum_name": name, "enum_values": enum_values})
436
Eric Blake437db252015-09-29 16:21:02 -0600437
Markus Armbruster00e4b282015-06-10 10:04:36 +0200438def find_enum(name):
439 global enum_types
440 for enum in enum_types:
441 if enum['enum_name'] == name:
442 return enum
443 return None
444
Markus Armbruster00e4b282015-06-10 10:04:36 +0200445
Eric Blake437db252015-09-29 16:21:02 -0600446def is_enum(name):
447 return find_enum(name) is not None
448
449
450def check_type(expr_info, source, value, allow_array=False,
451 allow_dict=False, allow_optional=False,
452 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600453 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600454
455 if value is None:
456 return
457
Eric Blakedd883c62015-05-04 09:05:21 -0600458 # Check if array type for value is okay
459 if isinstance(value, list):
460 if not allow_array:
461 raise QAPIExprError(expr_info,
462 "%s cannot be an array" % source)
463 if len(value) != 1 or not isinstance(value[0], str):
464 raise QAPIExprError(expr_info,
465 "%s: array type must contain single type name"
466 % source)
467 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600468
469 # Check if type name for value is okay
470 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600471 if value not in all_names:
Eric Blakedd883c62015-05-04 09:05:21 -0600472 raise QAPIExprError(expr_info,
473 "%s uses unknown type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200474 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600475 if not all_names[value] in allow_metas:
476 raise QAPIExprError(expr_info,
477 "%s cannot use %s type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200478 % (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600479 return
480
Eric Blakedd883c62015-05-04 09:05:21 -0600481 if not allow_dict:
482 raise QAPIExprError(expr_info,
483 "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200484
485 if not isinstance(value, OrderedDict):
486 raise QAPIExprError(expr_info,
487 "%s should be a dictionary or type name" % source)
488
489 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600490 for (key, arg) in value.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600491 check_name(expr_info, "Member of %s" % source, key,
492 allow_optional=allow_optional)
Eric Blake6b5abc72015-05-04 09:05:33 -0600493 # Todo: allow dictionaries to represent default values of
494 # an optional argument.
Eric Blakedd883c62015-05-04 09:05:21 -0600495 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200496 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600497 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600498 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600499
Eric Blake437db252015-09-29 16:21:02 -0600500
501def check_member_clash(expr_info, base_name, data, source=""):
Eric Blakeff55d722015-05-04 09:05:37 -0600502 base = find_struct(base_name)
503 assert base
504 base_members = base['data']
505 for key in data.keys():
506 if key.startswith('*'):
507 key = key[1:]
508 if key in base_members or "*" + key in base_members:
509 raise QAPIExprError(expr_info,
510 "Member name '%s'%s clashes with base '%s'"
511 % (key, source, base_name))
512 if base.get('base'):
513 check_member_clash(expr_info, base['base'], data, source)
514
Eric Blake437db252015-09-29 16:21:02 -0600515
Eric Blakedd883c62015-05-04 09:05:21 -0600516def check_command(expr, expr_info):
517 name = expr['command']
Eric Blake2cbf0992015-05-04 09:05:24 -0600518
Eric Blakedd883c62015-05-04 09:05:21 -0600519 check_type(expr_info, "'data' for command '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600520 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200521 allow_metas=['struct'])
Eric Blake10d4d992015-05-04 09:05:23 -0600522 returns_meta = ['union', 'struct']
523 if name in returns_whitelist:
524 returns_meta += ['built-in', 'alternate', 'enum']
Eric Blakedd883c62015-05-04 09:05:21 -0600525 check_type(expr_info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200526 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200527 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600528
Eric Blake437db252015-09-29 16:21:02 -0600529
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200530def check_event(expr, expr_info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600531 global events
532 name = expr['event']
Eric Blake4dc2e692015-05-04 09:05:17 -0600533
534 if name.upper() == 'MAX':
535 raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
536 events.append(name)
Eric Blakedd883c62015-05-04 09:05:21 -0600537 check_type(expr_info, "'data' for event '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600538 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster315932b2015-07-01 10:12:24 +0200539 allow_metas=['struct'])
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200540
Eric Blake437db252015-09-29 16:21:02 -0600541
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800542def check_union(expr, expr_info):
543 name = expr['union']
544 base = expr.get('base')
545 discriminator = expr.get('discriminator')
546 members = expr['data']
Eric Blake7b2a5c22015-09-29 16:21:04 -0600547 values = {'MAX': '(automatic)', 'KIND': '(automatic)'}
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800548
Eric Blake811d04f2015-05-04 09:05:10 -0600549 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600550
551 # With no discriminator it is a simple union.
552 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600553 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600554 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600555 if base is not None:
556 raise QAPIExprError(expr_info,
Eric Blake811d04f2015-05-04 09:05:10 -0600557 "Simple union '%s' must not have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600558 % name)
559
560 # Else, it's a flat union.
561 else:
562 # The object must have a string member 'base'.
Eric Blake376863e2015-09-29 16:21:07 -0600563 check_type(expr_info, "'base' for union '%s'" % name,
564 base, allow_metas=['struct'])
565 if not base:
Eric Blake44bd1272015-05-04 09:05:08 -0600566 raise QAPIExprError(expr_info,
Eric Blake376863e2015-09-29 16:21:07 -0600567 "Flat union '%s' must have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600568 % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800569 base_fields = find_base_fields(base)
Eric Blake376863e2015-09-29 16:21:07 -0600570 assert base_fields
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800571
Eric Blakec9e0a792015-05-04 09:05:22 -0600572 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600573 # member of the base struct.
Eric Blakec9e0a792015-05-04 09:05:22 -0600574 check_name(expr_info, "Discriminator of flat union '%s'" % name,
575 discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800576 discriminator_type = base_fields.get(discriminator)
577 if not discriminator_type:
578 raise QAPIExprError(expr_info,
579 "Discriminator '%s' is not a member of base "
Eric Blakefd41dd42015-05-04 09:05:25 -0600580 "struct '%s'"
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800581 % (discriminator, base))
582 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600583 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800584 # Do not allow string discriminator
585 if not enum_define:
586 raise QAPIExprError(expr_info,
587 "Discriminator '%s' must be of enumeration "
588 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800589
590 # Check every branch
591 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600592 check_name(expr_info, "Member of union '%s'" % name, key)
593
Eric Blakedd883c62015-05-04 09:05:21 -0600594 # Each value must name a known type; furthermore, in flat unions,
Eric Blakeff55d722015-05-04 09:05:37 -0600595 # branches must be a struct with no overlapping member names
Eric Blakedd883c62015-05-04 09:05:21 -0600596 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200597 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakeff55d722015-05-04 09:05:37 -0600598 if base:
599 branch_struct = find_struct(value)
600 assert branch_struct
601 check_member_clash(expr_info, base, branch_struct['data'],
602 " of branch '%s'" % key)
Eric Blakedd883c62015-05-04 09:05:21 -0600603
Eric Blake44bd1272015-05-04 09:05:08 -0600604 # If the discriminator names an enum type, then all members
Eric Blake7b2a5c22015-09-29 16:21:04 -0600605 # of 'data' must also be members of the enum type, which in turn
606 # must not collide with the discriminator name.
Eric Blake44bd1272015-05-04 09:05:08 -0600607 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600608 if key not in enum_define['enum_values']:
Eric Blake44bd1272015-05-04 09:05:08 -0600609 raise QAPIExprError(expr_info,
610 "Discriminator value '%s' is not found in "
611 "enum '%s'" %
612 (key, enum_define["enum_name"]))
Eric Blake7b2a5c22015-09-29 16:21:04 -0600613 if discriminator in enum_define['enum_values']:
614 raise QAPIExprError(expr_info,
615 "Discriminator name '%s' collides with "
616 "enum value in '%s'" %
617 (discriminator, enum_define["enum_name"]))
Eric Blake44bd1272015-05-04 09:05:08 -0600618
619 # Otherwise, check for conflicts in the generated enum
620 else:
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600621 c_key = camel_to_upper(key)
Eric Blake44bd1272015-05-04 09:05:08 -0600622 if c_key in values:
623 raise QAPIExprError(expr_info,
624 "Union '%s' member '%s' clashes with '%s'"
625 % (name, key, values[c_key]))
626 values[c_key] = key
627
Eric Blake437db252015-09-29 16:21:02 -0600628
Eric Blake811d04f2015-05-04 09:05:10 -0600629def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600630 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600631 members = expr['data']
Eric Blake437db252015-09-29 16:21:02 -0600632 values = {'MAX': '(automatic)'}
Eric Blake811d04f2015-05-04 09:05:10 -0600633 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600634
Eric Blake811d04f2015-05-04 09:05:10 -0600635 # Check every branch
636 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600637 check_name(expr_info, "Member of alternate '%s'" % name, key)
638
Eric Blake811d04f2015-05-04 09:05:10 -0600639 # Check for conflicts in the generated enum
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600640 c_key = camel_to_upper(key)
Eric Blake811d04f2015-05-04 09:05:10 -0600641 if c_key in values:
642 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600643 "Alternate '%s' member '%s' clashes with '%s'"
644 % (name, key, values[c_key]))
Eric Blake811d04f2015-05-04 09:05:10 -0600645 values[c_key] = key
646
647 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600648 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
649 value,
650 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600651 qtype = find_alternate_member_qtype(value)
Eric Blakedd883c62015-05-04 09:05:21 -0600652 assert qtype
Eric Blake811d04f2015-05-04 09:05:10 -0600653 if qtype in types_seen:
654 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600655 "Alternate '%s' member '%s' can't "
Eric Blake811d04f2015-05-04 09:05:10 -0600656 "be distinguished from member '%s'"
657 % (name, key, types_seen[qtype]))
658 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800659
Eric Blake437db252015-09-29 16:21:02 -0600660
Eric Blakecf393592015-05-04 09:05:04 -0600661def check_enum(expr, expr_info):
662 name = expr['enum']
663 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100664 prefix = expr.get('prefix')
Eric Blake437db252015-09-29 16:21:02 -0600665 values = {'MAX': '(automatic)'}
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)
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600676 key = camel_to_upper(member)
Eric Blakecf393592015-05-04 09:05:04 -0600677 if key in values:
678 raise QAPIExprError(expr_info,
679 "Enum '%s' member '%s' clashes with '%s'"
680 % (name, member, values[key]))
681 values[key] = member
682
Eric Blake437db252015-09-29 16:21:02 -0600683
Eric Blakedd883c62015-05-04 09:05:21 -0600684def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600685 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600686 members = expr['data']
687
Eric Blakefd41dd42015-05-04 09:05:25 -0600688 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600689 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600690 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600691 allow_metas=['struct'])
Eric Blakeff55d722015-05-04 09:05:37 -0600692 if expr.get('base'):
693 check_member_clash(expr_info, expr['base'], expr['data'])
Eric Blakedd883c62015-05-04 09:05:21 -0600694
Eric Blake437db252015-09-29 16:21:02 -0600695
Eric Blake0545f6b2015-05-04 09:05:15 -0600696def check_keys(expr_elem, meta, required, optional=[]):
697 expr = expr_elem['expr']
698 info = expr_elem['info']
699 name = expr[meta]
700 if not isinstance(name, str):
701 raise QAPIExprError(info,
702 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600703 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600704 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600705 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600706 raise QAPIExprError(info,
707 "Unknown key '%s' in %s '%s'"
708 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600709 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600710 raise QAPIExprError(info,
711 "'%s' of %s '%s' should only use false value"
712 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600713 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600714 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600715 raise QAPIExprError(info,
716 "Key '%s' is missing from %s '%s'"
717 % (key, meta, name))
718
Eric Blake437db252015-09-29 16:21:02 -0600719
Markus Armbruster4d076d62015-06-10 08:55:21 +0200720def check_exprs(exprs):
721 global all_names
722
723 # Learn the types and check for valid expression keys
724 for builtin in builtin_types.keys():
725 all_names[builtin] = 'built-in'
726 for expr_elem in exprs:
727 expr = expr_elem['expr']
728 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600729 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100730 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200731 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600732 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200733 check_keys(expr_elem, 'union', ['data'],
734 ['base', 'discriminator'])
735 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600736 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200737 check_keys(expr_elem, 'alternate', ['data'])
738 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600739 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200740 check_keys(expr_elem, 'struct', ['data'], ['base'])
741 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600742 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200743 check_keys(expr_elem, 'command', [],
744 ['data', 'returns', 'gen', 'success-response'])
745 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600746 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200747 check_keys(expr_elem, 'event', [], ['data'])
748 add_name(expr['event'], info, 'event')
749 else:
750 raise QAPIExprError(expr_elem['info'],
751 "Expression is missing metatype")
752
753 # Try again for hidden UnionKind enum
754 for expr_elem in exprs:
755 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600756 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200757 if not discriminator_find_enum_define(expr):
758 add_enum('%sKind' % expr['union'], expr_elem['info'],
759 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600760 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200761 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
762 implicit=True)
763
764 # Validate that exprs make sense
765 for expr_elem in exprs:
766 expr = expr_elem['expr']
767 info = expr_elem['info']
768
Eric Blake437db252015-09-29 16:21:02 -0600769 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200770 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600771 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200772 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600773 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200774 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600775 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200776 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600777 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200778 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600779 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200780 check_event(expr, info)
781 else:
782 assert False, 'unexpected meta type'
783
Markus Armbrusterac882192015-09-16 13:06:05 +0200784 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600785
Markus Armbrusterac882192015-09-16 13:06:05 +0200786
787#
788# Schema compiler frontend
789#
790
791class QAPISchemaEntity(object):
792 def __init__(self, name, info):
793 assert isinstance(name, str)
794 self.name = name
795 self.info = info
796
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200797 def c_name(self):
798 return c_name(self.name)
799
Markus Armbrusterac882192015-09-16 13:06:05 +0200800 def check(self, schema):
801 pass
802
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200803 def visit(self, visitor):
804 pass
805
806
807class QAPISchemaVisitor(object):
808 def visit_begin(self, schema):
809 pass
810
811 def visit_end(self):
812 pass
813
Eric Blake25a0d9c2015-10-12 22:22:21 -0600814 def visit_needed(self, entity):
815 # Default to visiting everything
816 return True
817
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200818 def visit_builtin_type(self, name, info, json_type):
819 pass
820
821 def visit_enum_type(self, name, info, values, prefix):
822 pass
823
824 def visit_array_type(self, name, info, element_type):
825 pass
826
827 def visit_object_type(self, name, info, base, members, variants):
828 pass
829
Markus Armbruster39a18152015-09-16 13:06:28 +0200830 def visit_object_type_flat(self, name, info, members, variants):
831 pass
832
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200833 def visit_alternate_type(self, name, info, variants):
834 pass
835
836 def visit_command(self, name, info, arg_type, ret_type,
837 gen, success_response):
838 pass
839
840 def visit_event(self, name, info, arg_type):
841 pass
842
Markus Armbrusterac882192015-09-16 13:06:05 +0200843
844class QAPISchemaType(QAPISchemaEntity):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200845 def c_type(self, is_param=False):
846 return c_name(self.name) + pointer_suffix
847
848 def c_null(self):
849 return 'NULL'
850
851 def json_type(self):
852 pass
853
854 def alternate_qtype(self):
855 json2qtype = {
856 'string': 'QTYPE_QSTRING',
857 'number': 'QTYPE_QFLOAT',
858 'int': 'QTYPE_QINT',
859 'boolean': 'QTYPE_QBOOL',
860 'object': 'QTYPE_QDICT'
861 }
862 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200863
864
865class QAPISchemaBuiltinType(QAPISchemaType):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200866 def __init__(self, name, json_type, c_type, c_null):
Markus Armbrusterac882192015-09-16 13:06:05 +0200867 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200868 assert not c_type or isinstance(c_type, str)
869 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
870 'value')
871 self._json_type_name = json_type
872 self._c_type_name = c_type
873 self._c_null_val = c_null
874
875 def c_name(self):
876 return self.name
877
878 def c_type(self, is_param=False):
879 if is_param and self.name == 'str':
880 return 'const ' + self._c_type_name
881 return self._c_type_name
882
883 def c_null(self):
884 return self._c_null_val
885
886 def json_type(self):
887 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200888
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200889 def visit(self, visitor):
890 visitor.visit_builtin_type(self.name, self.info, self.json_type())
891
Markus Armbrusterac882192015-09-16 13:06:05 +0200892
893class QAPISchemaEnumType(QAPISchemaType):
894 def __init__(self, name, info, values, prefix):
895 QAPISchemaType.__init__(self, name, info)
896 for v in values:
897 assert isinstance(v, str)
898 assert prefix is None or isinstance(prefix, str)
899 self.values = values
900 self.prefix = prefix
901
902 def check(self, schema):
903 assert len(set(self.values)) == len(self.values)
904
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200905 def c_type(self, is_param=False):
906 return c_name(self.name)
907
908 def c_null(self):
909 return c_enum_const(self.name, (self.values + ['MAX'])[0],
910 self.prefix)
911
912 def json_type(self):
913 return 'string'
914
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200915 def visit(self, visitor):
916 visitor.visit_enum_type(self.name, self.info,
917 self.values, self.prefix)
918
Markus Armbrusterac882192015-09-16 13:06:05 +0200919
920class QAPISchemaArrayType(QAPISchemaType):
921 def __init__(self, name, info, element_type):
922 QAPISchemaType.__init__(self, name, info)
923 assert isinstance(element_type, str)
924 self._element_type_name = element_type
925 self.element_type = None
926
927 def check(self, schema):
928 self.element_type = schema.lookup_type(self._element_type_name)
929 assert self.element_type
930
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200931 def json_type(self):
932 return 'array'
933
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200934 def visit(self, visitor):
935 visitor.visit_array_type(self.name, self.info, self.element_type)
936
Markus Armbrusterac882192015-09-16 13:06:05 +0200937
938class QAPISchemaObjectType(QAPISchemaType):
939 def __init__(self, name, info, base, local_members, variants):
940 QAPISchemaType.__init__(self, name, info)
941 assert base is None or isinstance(base, str)
942 for m in local_members:
943 assert isinstance(m, QAPISchemaObjectTypeMember)
944 assert (variants is None or
945 isinstance(variants, QAPISchemaObjectTypeVariants))
946 self._base_name = base
947 self.base = None
948 self.local_members = local_members
949 self.variants = variants
950 self.members = None
951
952 def check(self, schema):
953 assert self.members is not False # not running in cycles
954 if self.members:
955 return
956 self.members = False # mark as being checked
957 if self._base_name:
958 self.base = schema.lookup_type(self._base_name)
959 assert isinstance(self.base, QAPISchemaObjectType)
960 assert not self.base.variants # not implemented
961 self.base.check(schema)
962 members = list(self.base.members)
963 else:
964 members = []
965 seen = {}
966 for m in members:
967 seen[m.name] = m
968 for m in self.local_members:
969 m.check(schema, members, seen)
970 if self.variants:
971 self.variants.check(schema, members, seen)
972 self.members = members
973
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200974 def c_name(self):
975 assert self.info
976 return QAPISchemaType.c_name(self)
977
978 def c_type(self, is_param=False):
979 assert self.info
980 return QAPISchemaType.c_type(self)
981
982 def json_type(self):
983 return 'object'
984
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200985 def visit(self, visitor):
986 visitor.visit_object_type(self.name, self.info,
987 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +0200988 visitor.visit_object_type_flat(self.name, self.info,
989 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200990
Markus Armbrusterac882192015-09-16 13:06:05 +0200991
992class QAPISchemaObjectTypeMember(object):
993 def __init__(self, name, typ, optional):
994 assert isinstance(name, str)
995 assert isinstance(typ, str)
996 assert isinstance(optional, bool)
997 self.name = name
998 self._type_name = typ
999 self.type = None
1000 self.optional = optional
1001
1002 def check(self, schema, all_members, seen):
1003 assert self.name not in seen
1004 self.type = schema.lookup_type(self._type_name)
1005 assert self.type
1006 all_members.append(self)
1007 seen[self.name] = self
1008
1009
1010class QAPISchemaObjectTypeVariants(object):
1011 def __init__(self, tag_name, tag_enum, variants):
1012 assert tag_name is None or isinstance(tag_name, str)
1013 assert tag_enum is None or isinstance(tag_enum, str)
1014 for v in variants:
1015 assert isinstance(v, QAPISchemaObjectTypeVariant)
1016 self.tag_name = tag_name
1017 if tag_name:
1018 assert not tag_enum
1019 self.tag_member = None
1020 else:
1021 self.tag_member = QAPISchemaObjectTypeMember('type', tag_enum,
1022 False)
1023 self.variants = variants
1024
1025 def check(self, schema, members, seen):
1026 if self.tag_name:
1027 self.tag_member = seen[self.tag_name]
1028 else:
1029 self.tag_member.check(schema, members, seen)
1030 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1031 for v in self.variants:
1032 vseen = dict(seen)
1033 v.check(schema, self.tag_member.type, vseen)
1034
Eric Blake437db252015-09-29 16:21:02 -06001035
Markus Armbrusterac882192015-09-16 13:06:05 +02001036class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1037 def __init__(self, name, typ):
1038 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1039
1040 def check(self, schema, tag_type, seen):
1041 QAPISchemaObjectTypeMember.check(self, schema, [], seen)
1042 assert self.name in tag_type.values
1043
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001044 # This function exists to support ugly simple union special cases
1045 # TODO get rid of them, and drop the function
1046 def simple_union_type(self):
1047 if isinstance(self.type, QAPISchemaObjectType) and not self.type.info:
1048 assert len(self.type.members) == 1
1049 assert not self.type.variants
1050 return self.type.members[0].type
1051 return None
1052
Markus Armbrusterac882192015-09-16 13:06:05 +02001053
1054class QAPISchemaAlternateType(QAPISchemaType):
1055 def __init__(self, name, info, variants):
1056 QAPISchemaType.__init__(self, name, info)
1057 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1058 assert not variants.tag_name
1059 self.variants = variants
1060
1061 def check(self, schema):
1062 self.variants.check(schema, [], {})
1063
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001064 def json_type(self):
1065 return 'value'
1066
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001067 def visit(self, visitor):
1068 visitor.visit_alternate_type(self.name, self.info, self.variants)
1069
Markus Armbrusterac882192015-09-16 13:06:05 +02001070
1071class QAPISchemaCommand(QAPISchemaEntity):
1072 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1073 QAPISchemaEntity.__init__(self, name, info)
1074 assert not arg_type or isinstance(arg_type, str)
1075 assert not ret_type or isinstance(ret_type, str)
1076 self._arg_type_name = arg_type
1077 self.arg_type = None
1078 self._ret_type_name = ret_type
1079 self.ret_type = None
1080 self.gen = gen
1081 self.success_response = success_response
1082
1083 def check(self, schema):
1084 if self._arg_type_name:
1085 self.arg_type = schema.lookup_type(self._arg_type_name)
1086 assert isinstance(self.arg_type, QAPISchemaObjectType)
1087 assert not self.arg_type.variants # not implemented
1088 if self._ret_type_name:
1089 self.ret_type = schema.lookup_type(self._ret_type_name)
1090 assert isinstance(self.ret_type, QAPISchemaType)
1091
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001092 def visit(self, visitor):
1093 visitor.visit_command(self.name, self.info,
1094 self.arg_type, self.ret_type,
1095 self.gen, self.success_response)
1096
Markus Armbrusterac882192015-09-16 13:06:05 +02001097
1098class QAPISchemaEvent(QAPISchemaEntity):
1099 def __init__(self, name, info, arg_type):
1100 QAPISchemaEntity.__init__(self, name, info)
1101 assert not arg_type or isinstance(arg_type, str)
1102 self._arg_type_name = arg_type
1103 self.arg_type = None
1104
1105 def check(self, schema):
1106 if self._arg_type_name:
1107 self.arg_type = schema.lookup_type(self._arg_type_name)
1108 assert isinstance(self.arg_type, QAPISchemaObjectType)
1109 assert not self.arg_type.variants # not implemented
1110
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001111 def visit(self, visitor):
1112 visitor.visit_event(self.name, self.info, self.arg_type)
1113
Markus Armbrusterac882192015-09-16 13:06:05 +02001114
1115class QAPISchema(object):
1116 def __init__(self, fname):
1117 try:
1118 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1119 except (QAPISchemaError, QAPIExprError), err:
1120 print >>sys.stderr, err
1121 exit(1)
1122 self._entity_dict = {}
1123 self._def_predefineds()
1124 self._def_exprs()
1125 self.check()
1126
Markus Armbrusterac882192015-09-16 13:06:05 +02001127 def _def_entity(self, ent):
1128 assert ent.name not in self._entity_dict
1129 self._entity_dict[ent.name] = ent
1130
1131 def lookup_entity(self, name, typ=None):
1132 ent = self._entity_dict.get(name)
1133 if typ and not isinstance(ent, typ):
1134 return None
1135 return ent
1136
1137 def lookup_type(self, name):
1138 return self.lookup_entity(name, QAPISchemaType)
1139
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001140 def _def_builtin_type(self, name, json_type, c_type, c_null):
1141 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1142 c_type, c_null))
Markus Armbruster28770e02015-09-16 13:06:24 +02001143 self._make_array_type(name) # TODO really needed?
Markus Armbrusterac882192015-09-16 13:06:05 +02001144
1145 def _def_predefineds(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001146 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1147 ('number', 'number', 'double', '0'),
1148 ('int', 'int', 'int64_t', '0'),
1149 ('int8', 'int', 'int8_t', '0'),
1150 ('int16', 'int', 'int16_t', '0'),
1151 ('int32', 'int', 'int32_t', '0'),
1152 ('int64', 'int', 'int64_t', '0'),
1153 ('uint8', 'int', 'uint8_t', '0'),
1154 ('uint16', 'int', 'uint16_t', '0'),
1155 ('uint32', 'int', 'uint32_t', '0'),
1156 ('uint64', 'int', 'uint64_t', '0'),
1157 ('size', 'int', 'uint64_t', '0'),
1158 ('bool', 'boolean', 'bool', 'false'),
Markus Armbruster28770e02015-09-16 13:06:24 +02001159 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001160 self._def_builtin_type(*t)
Markus Armbruster39a18152015-09-16 13:06:28 +02001161 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1162 [], None)
1163 self._def_entity(self.the_empty_object_type)
Markus Armbrusterac882192015-09-16 13:06:05 +02001164
1165 def _make_implicit_enum_type(self, name, values):
1166 name = name + 'Kind'
1167 self._def_entity(QAPISchemaEnumType(name, None, values, None))
1168 return name
1169
1170 def _make_array_type(self, element_type):
1171 name = element_type + 'List'
1172 if not self.lookup_type(name):
1173 self._def_entity(QAPISchemaArrayType(name, None, element_type))
1174 return name
1175
1176 def _make_implicit_object_type(self, name, role, members):
1177 if not members:
1178 return None
1179 name = ':obj-%s-%s' % (name, role)
1180 if not self.lookup_entity(name, QAPISchemaObjectType):
1181 self._def_entity(QAPISchemaObjectType(name, None, None,
1182 members, None))
1183 return name
1184
1185 def _def_enum_type(self, expr, info):
1186 name = expr['enum']
1187 data = expr['data']
1188 prefix = expr.get('prefix')
1189 self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
1190 self._make_array_type(name) # TODO really needed?
1191
1192 def _make_member(self, name, typ):
1193 optional = False
1194 if name.startswith('*'):
1195 name = name[1:]
1196 optional = True
1197 if isinstance(typ, list):
1198 assert len(typ) == 1
1199 typ = self._make_array_type(typ[0])
1200 return QAPISchemaObjectTypeMember(name, typ, optional)
1201
1202 def _make_members(self, data):
1203 return [self._make_member(key, value)
1204 for (key, value) in data.iteritems()]
1205
1206 def _def_struct_type(self, expr, info):
1207 name = expr['struct']
1208 base = expr.get('base')
1209 data = expr['data']
1210 self._def_entity(QAPISchemaObjectType(name, info, base,
1211 self._make_members(data),
1212 None))
1213 self._make_array_type(name) # TODO really needed?
1214
1215 def _make_variant(self, case, typ):
1216 return QAPISchemaObjectTypeVariant(case, typ)
1217
1218 def _make_simple_variant(self, case, typ):
1219 if isinstance(typ, list):
1220 assert len(typ) == 1
1221 typ = self._make_array_type(typ[0])
1222 typ = self._make_implicit_object_type(typ, 'wrapper',
1223 [self._make_member('data', typ)])
1224 return QAPISchemaObjectTypeVariant(case, typ)
1225
1226 def _make_tag_enum(self, type_name, variants):
1227 return self._make_implicit_enum_type(type_name,
1228 [v.name for v in variants])
1229
1230 def _def_union_type(self, expr, info):
1231 name = expr['union']
1232 data = expr['data']
1233 base = expr.get('base')
1234 tag_name = expr.get('discriminator')
1235 tag_enum = None
1236 if tag_name:
1237 variants = [self._make_variant(key, value)
1238 for (key, value) in data.iteritems()]
1239 else:
1240 variants = [self._make_simple_variant(key, value)
1241 for (key, value) in data.iteritems()]
1242 tag_enum = self._make_tag_enum(name, variants)
1243 self._def_entity(
1244 QAPISchemaObjectType(name, info, base,
1245 self._make_members(OrderedDict()),
1246 QAPISchemaObjectTypeVariants(tag_name,
1247 tag_enum,
1248 variants)))
1249 self._make_array_type(name) # TODO really needed?
1250
1251 def _def_alternate_type(self, expr, info):
1252 name = expr['alternate']
1253 data = expr['data']
1254 variants = [self._make_variant(key, value)
1255 for (key, value) in data.iteritems()]
1256 tag_enum = self._make_tag_enum(name, variants)
1257 self._def_entity(
1258 QAPISchemaAlternateType(name, info,
1259 QAPISchemaObjectTypeVariants(None,
1260 tag_enum,
1261 variants)))
1262 self._make_array_type(name) # TODO really needed?
1263
1264 def _def_command(self, expr, info):
1265 name = expr['command']
1266 data = expr.get('data')
1267 rets = expr.get('returns')
1268 gen = expr.get('gen', True)
1269 success_response = expr.get('success-response', True)
1270 if isinstance(data, OrderedDict):
1271 data = self._make_implicit_object_type(name, 'arg',
1272 self._make_members(data))
1273 if isinstance(rets, list):
1274 assert len(rets) == 1
1275 rets = self._make_array_type(rets[0])
1276 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1277 success_response))
1278
1279 def _def_event(self, expr, info):
1280 name = expr['event']
1281 data = expr.get('data')
1282 if isinstance(data, OrderedDict):
1283 data = self._make_implicit_object_type(name, 'arg',
1284 self._make_members(data))
1285 self._def_entity(QAPISchemaEvent(name, info, data))
1286
1287 def _def_exprs(self):
1288 for expr_elem in self.exprs:
1289 expr = expr_elem['expr']
1290 info = expr_elem['info']
1291 if 'enum' in expr:
1292 self._def_enum_type(expr, info)
1293 elif 'struct' in expr:
1294 self._def_struct_type(expr, info)
1295 elif 'union' in expr:
1296 self._def_union_type(expr, info)
1297 elif 'alternate' in expr:
1298 self._def_alternate_type(expr, info)
1299 elif 'command' in expr:
1300 self._def_command(expr, info)
1301 elif 'event' in expr:
1302 self._def_event(expr, info)
1303 else:
1304 assert False
1305
1306 def check(self):
1307 for ent in self._entity_dict.values():
1308 ent.check(self)
1309
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001310 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001311 visitor.visit_begin(self)
1312 for (name, entity) in sorted(self._entity_dict.items()):
1313 if visitor.visit_needed(entity):
1314 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001315 visitor.visit_end()
1316
Markus Armbruster2caba362013-07-27 17:41:56 +02001317
Markus Armbruster00e4b282015-06-10 10:04:36 +02001318#
1319# Code generation helpers
1320#
1321
Michael Roth0f923be2011-07-19 14:50:39 -05001322def camel_case(name):
1323 new_name = ''
1324 first = True
1325 for ch in name:
1326 if ch in ['_', '-']:
1327 first = True
1328 elif first:
1329 new_name += ch.upper()
1330 first = False
1331 else:
1332 new_name += ch.lower()
1333 return new_name
1334
Eric Blake437db252015-09-29 16:21:02 -06001335
Markus Armbruster849bc532015-05-14 06:50:53 -06001336# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1337# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1338# ENUM24_Name -> ENUM24_NAME
1339def camel_to_upper(value):
1340 c_fun_str = c_name(value, False)
1341 if value.isupper():
1342 return c_fun_str
1343
1344 new_name = ''
1345 l = len(c_fun_str)
1346 for i in range(l):
1347 c = c_fun_str[i]
1348 # When c is upper and no "_" appears before, do more checks
1349 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001350 if i < l - 1 and c_fun_str[i + 1].islower():
1351 new_name += '_'
1352 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001353 new_name += '_'
1354 new_name += c
1355 return new_name.lstrip('_').upper()
1356
Eric Blake437db252015-09-29 16:21:02 -06001357
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001358def c_enum_const(type_name, const_name, prefix=None):
1359 if prefix is not None:
1360 type_name = prefix
Markus Armbruster849bc532015-05-14 06:50:53 -06001361 return camel_to_upper(type_name + '_' + const_name)
1362
Eric Blake18df5152015-05-14 06:50:48 -06001363c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001364
Eric Blake437db252015-09-29 16:21:02 -06001365
Eric Blakec6405b52015-05-14 06:50:55 -06001366# Map @name to a valid C identifier.
1367# If @protect, avoid returning certain ticklish identifiers (like
1368# C keywords) by prepending "q_".
1369#
1370# Used for converting 'name' from a 'name':'type' qapi definition
1371# into a generated struct member, as well as converting type names
1372# into substrings of a generated C function name.
1373# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1374# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001375def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001376 # ANSI X3J11/88-090, 3.1.1
1377 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001378 'default', 'do', 'double', 'else', 'enum', 'extern',
1379 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1380 'return', 'short', 'signed', 'sizeof', 'static',
1381 'struct', 'switch', 'typedef', 'union', 'unsigned',
1382 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001383 # ISO/IEC 9899:1999, 6.4.1
1384 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1385 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001386 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1387 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001388 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1389 # excluding _.*
1390 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001391 # C++ ISO/IEC 14882:2003 2.11
1392 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1393 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1394 'namespace', 'new', 'operator', 'private', 'protected',
1395 'public', 'reinterpret_cast', 'static_cast', 'template',
1396 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1397 'using', 'virtual', 'wchar_t',
1398 # alternative representations
1399 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1400 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001401 # namespace pollution:
Max Reitz8592a542013-12-20 19:28:18 +01001402 polluted_words = set(['unix', 'errno'])
Eric Blake437db252015-09-29 16:21:02 -06001403 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1404 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001405 return "q_" + name
Eric Blake18df5152015-05-14 06:50:48 -06001406 return name.translate(c_name_trans)
Michael Roth0f923be2011-07-19 14:50:39 -05001407
Amos Kong05dfb262014-06-10 19:25:53 +08001408eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001409pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001410
Eric Blake437db252015-09-29 16:21:02 -06001411
Michael Roth0f923be2011-07-19 14:50:39 -05001412def genindent(count):
1413 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001414 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001415 ret += " "
1416 return ret
1417
1418indent_level = 0
1419
Eric Blake437db252015-09-29 16:21:02 -06001420
Michael Roth0f923be2011-07-19 14:50:39 -05001421def push_indent(indent_amount=4):
1422 global indent_level
1423 indent_level += indent_amount
1424
Eric Blake437db252015-09-29 16:21:02 -06001425
Michael Roth0f923be2011-07-19 14:50:39 -05001426def pop_indent(indent_amount=4):
1427 global indent_level
1428 indent_level -= indent_amount
1429
Eric Blake437db252015-09-29 16:21:02 -06001430
Markus Armbruster77e703b2015-06-24 19:27:32 +02001431# Generate @code with @kwds interpolated.
1432# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001433def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001434 raw = code % kwds
1435 if indent_level:
1436 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001437 # re.subn() lacks flags support before Python 2.7, use re.compile()
1438 raw = re.subn(re.compile("^.", re.MULTILINE),
1439 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001440 raw = raw[0]
1441 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001442
Eric Blake437db252015-09-29 16:21:02 -06001443
Michael Roth0f923be2011-07-19 14:50:39 -05001444def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001445 if code[0] == '\n':
1446 code = code[1:]
1447 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001448
Michael Roth0f923be2011-07-19 14:50:39 -05001449
1450def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001451 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001452
Eric Blake437db252015-09-29 16:21:02 -06001453
Michael Rothc0afa9c2013-05-10 17:46:00 -05001454def guardstart(name):
1455 return mcgen('''
1456
1457#ifndef %(name)s
1458#define %(name)s
1459
1460''',
1461 name=guardname(name))
1462
Eric Blake437db252015-09-29 16:21:02 -06001463
Michael Rothc0afa9c2013-05-10 17:46:00 -05001464def guardend(name):
1465 return mcgen('''
1466
1467#endif /* %(name)s */
1468
1469''',
1470 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001471
Eric Blake437db252015-09-29 16:21:02 -06001472
Markus Armbrustere98859a2015-09-16 13:06:16 +02001473def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001474 ret = mcgen('''
1475
Markus Armbrustere98859a2015-09-16 13:06:16 +02001476const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001477''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001478 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001479 for value in values:
1480 index = c_enum_const(name, value, prefix)
1481 ret += mcgen('''
1482 [%(index)s] = "%(value)s",
1483''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001484 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001485
1486 max_index = c_enum_const(name, 'MAX', prefix)
1487 ret += mcgen('''
1488 [%(max_index)s] = NULL,
1489};
1490''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001491 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001492 return ret
1493
Eric Blake437db252015-09-29 16:21:02 -06001494
Markus Armbrustere98859a2015-09-16 13:06:16 +02001495def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001496 # append automatically generated _MAX value
Markus Armbrustere98859a2015-09-16 13:06:16 +02001497 enum_values = values + ['MAX']
1498
1499 ret = mcgen('''
1500
1501typedef enum %(c_name)s {
1502''',
1503 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001504
1505 i = 0
1506 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001507 ret += mcgen('''
1508 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001509''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001510 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001511 i=i)
1512 i += 1
1513
Markus Armbrustere98859a2015-09-16 13:06:16 +02001514 ret += mcgen('''
1515} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001516''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001517 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001518
Markus Armbrustere98859a2015-09-16 13:06:16 +02001519 ret += mcgen('''
1520
1521extern const char *const %(c_name)s_lookup[];
1522''',
1523 c_name=c_name(name))
1524 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001525
Eric Blake437db252015-09-29 16:21:02 -06001526
Markus Armbruster03b43672015-09-16 13:06:20 +02001527def gen_params(arg_type, extra):
1528 if not arg_type:
1529 return extra
1530 assert not arg_type.variants
1531 ret = ''
1532 sep = ''
1533 for memb in arg_type.members:
1534 ret += sep
1535 sep = ', '
1536 if memb.optional:
1537 ret += 'bool has_%s, ' % c_name(memb.name)
1538 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1539 if extra:
1540 ret += sep + extra
1541 return ret
1542
Eric Blake1f353342015-09-29 16:21:13 -06001543
Eric Blake18bdbc32015-09-29 16:21:15 -06001544def gen_err_check(label='out', skiperr=False):
1545 if skiperr:
Eric Blake1f353342015-09-29 16:21:13 -06001546 return ''
1547 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001548 if (err) {
Eric Blake1f353342015-09-29 16:21:13 -06001549 goto %(label)s;
1550 }
1551''',
Eric Blake18bdbc32015-09-29 16:21:15 -06001552 label=label)
Eric Blake1f353342015-09-29 16:21:13 -06001553
1554
Eric Blake18bdbc32015-09-29 16:21:15 -06001555def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
Eric Blake82ca8e42015-09-29 16:21:14 -06001556 ret = ''
Eric Blake18bdbc32015-09-29 16:21:15 -06001557 if skiperr:
Eric Blake82ca8e42015-09-29 16:21:14 -06001558 errparg = 'NULL'
Eric Blake18bdbc32015-09-29 16:21:15 -06001559 else:
1560 errparg = '&err'
Eric Blake82ca8e42015-09-29 16:21:14 -06001561
1562 for memb in members:
1563 if memb.optional:
1564 ret += mcgen('''
1565 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1566''',
1567 prefix=prefix, c_name=c_name(memb.name),
1568 name=memb.name, errp=errparg)
Eric Blake18bdbc32015-09-29 16:21:15 -06001569 ret += gen_err_check(skiperr=skiperr)
Eric Blake82ca8e42015-09-29 16:21:14 -06001570 ret += mcgen('''
1571 if (%(prefix)shas_%(c_name)s) {
1572''',
1573 prefix=prefix, c_name=c_name(memb.name))
1574 push_indent()
1575
1576 # Ugly: sometimes we need to cast away const
1577 if need_cast and memb.type.name == 'str':
1578 cast = '(char **)'
1579 else:
1580 cast = ''
1581
1582 ret += mcgen('''
1583 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1584''',
1585 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1586 c_name=c_name(memb.name), name=memb.name,
1587 errp=errparg)
Eric Blake18bdbc32015-09-29 16:21:15 -06001588 ret += gen_err_check(skiperr=skiperr)
Eric Blake82ca8e42015-09-29 16:21:14 -06001589
1590 if memb.optional:
1591 pop_indent()
1592 ret += mcgen('''
1593 }
1594''')
1595 return ret
1596
1597
Markus Armbruster00e4b282015-06-10 10:04:36 +02001598#
1599# Common command line parsing
1600#
1601
Eric Blake437db252015-09-29 16:21:02 -06001602
1603def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001604
1605 try:
1606 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001607 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001608 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001609 "output-dir="] + extra_long_options)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001610 except getopt.GetoptError, err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001611 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001612 sys.exit(1)
1613
1614 output_dir = ""
1615 prefix = ""
1616 do_c = False
1617 do_h = False
1618 extra_opts = []
1619
1620 for oa in opts:
1621 o, a = oa
1622 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001623 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1624 if match.end() != len(a):
1625 print >>sys.stderr, \
1626 "%s: 'funny character '%s' in argument of --prefix" \
1627 % (sys.argv[0], a[match.end()])
1628 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001629 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001630 elif o in ("-o", "--output-dir"):
1631 output_dir = a + "/"
1632 elif o in ("-c", "--source"):
1633 do_c = True
1634 elif o in ("-h", "--header"):
1635 do_h = True
1636 else:
1637 extra_opts.append(oa)
1638
1639 if not do_c and not do_h:
1640 do_c = True
1641 do_h = True
1642
Markus Armbruster16d80f62015-04-02 13:32:16 +02001643 if len(args) != 1:
1644 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001645 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001646 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001647
Markus Armbruster54414042015-06-09 16:22:45 +02001648 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001649
Markus Armbruster00e4b282015-06-10 10:04:36 +02001650#
1651# Generate output files with boilerplate
1652#
1653
Eric Blake437db252015-09-29 16:21:02 -06001654
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001655def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1656 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001657 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001658 c_file = output_dir + prefix + c_file
1659 h_file = output_dir + prefix + h_file
1660
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001661 if output_dir:
1662 try:
1663 os.makedirs(output_dir)
1664 except os.error, e:
1665 if e.errno != errno.EEXIST:
1666 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001667
1668 def maybe_open(really, name, opt):
1669 if really:
1670 return open(name, opt)
1671 else:
1672 import StringIO
1673 return StringIO.StringIO()
1674
1675 fdef = maybe_open(do_c, c_file, 'w')
1676 fdecl = maybe_open(do_h, h_file, 'w')
1677
1678 fdef.write(mcgen('''
1679/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1680%(comment)s
1681''',
Eric Blake437db252015-09-29 16:21:02 -06001682 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001683
1684 fdecl.write(mcgen('''
1685/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1686%(comment)s
1687#ifndef %(guard)s
1688#define %(guard)s
1689
1690''',
Eric Blake437db252015-09-29 16:21:02 -06001691 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001692
1693 return (fdef, fdecl)
1694
Eric Blake437db252015-09-29 16:21:02 -06001695
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001696def close_output(fdef, fdecl):
1697 fdecl.write('''
1698#endif
1699''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001700 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001701 fdef.close()