blob: 4573599d7ce0049180ce2c2166cd59c76415e4ba [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)
Eric Blake7618b912015-10-12 22:22:22 -0600106 assert expr_info
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200107 self.info = expr_info
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800108 self.msg = msg
109
110 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200111 return error_path(self.info['parent']) + \
112 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800113
Eric Blake437db252015-09-29 16:21:02 -0600114
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200115class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500116
Eric Blake437db252015-09-29 16:21:02 -0600117 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200118 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200119 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200120 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200121 previously_included.append(abs_fname)
122 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200123 self.src = fp.read()
124 if self.src == '' or self.src[-1] != '\n':
125 self.src += '\n'
126 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800127 self.line = 1
128 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200129 self.exprs = []
130 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500131
Eric Blake437db252015-09-29 16:21:02 -0600132 while self.tok is not None:
Markus Armbruster54414042015-06-09 16:22:45 +0200133 expr_info = {'file': fname, 'line': self.line,
134 'parent': self.incl_info}
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200135 expr = self.get_expr(False)
136 if isinstance(expr, dict) and "include" in expr:
137 if len(expr) != 1:
Eric Blake437db252015-09-29 16:21:02 -0600138 raise QAPIExprError(expr_info,
139 "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200140 include = expr["include"]
141 if not isinstance(include, str):
142 raise QAPIExprError(expr_info,
Eric Blake7408fb62015-09-29 16:21:00 -0600143 "Value of 'include' must be a string")
Markus Armbruster54414042015-06-09 16:22:45 +0200144 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
145 include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200146 # catch inclusion cycle
147 inf = expr_info
148 while inf:
149 if incl_abs_fname == os.path.abspath(inf['file']):
Stefan Hajnoczi7ac9a9d2014-08-27 12:08:51 +0100150 raise QAPIExprError(expr_info, "Inclusion loop for %s"
151 % include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200152 inf = inf['parent']
Benoît Canet24fd8482014-05-16 12:51:56 +0200153 # skip multiple include of the same file
Markus Armbruster54414042015-06-09 16:22:45 +0200154 if incl_abs_fname in previously_included:
Benoît Canet24fd8482014-05-16 12:51:56 +0200155 continue
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200156 try:
Markus Armbruster54414042015-06-09 16:22:45 +0200157 fobj = open(incl_abs_fname, 'r')
Luiz Capitulino34788812014-05-20 13:50:19 -0400158 except IOError, e:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200159 raise QAPIExprError(expr_info,
160 '%s: %s' % (e.strerror, include))
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200161 exprs_include = QAPISchemaParser(fobj, previously_included,
162 expr_info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200163 self.exprs.extend(exprs_include.exprs)
164 else:
165 expr_elem = {'expr': expr,
166 'info': expr_info}
167 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500168
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200169 def accept(self):
170 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200171 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200172 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200173 self.cursor += 1
174 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500175
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200176 if self.tok == '#':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200177 self.cursor = self.src.find('\n', self.cursor)
178 elif self.tok in ['{', '}', ':', ',', '[', ']']:
179 return
180 elif self.tok == "'":
181 string = ''
182 esc = False
183 while True:
184 ch = self.src[self.cursor]
185 self.cursor += 1
186 if ch == '\n':
Markus Armbruster2caba362013-07-27 17:41:56 +0200187 raise QAPISchemaError(self,
188 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200189 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600190 if ch == 'b':
191 string += '\b'
192 elif ch == 'f':
193 string += '\f'
194 elif ch == 'n':
195 string += '\n'
196 elif ch == 'r':
197 string += '\r'
198 elif ch == 't':
199 string += '\t'
200 elif ch == 'u':
201 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600202 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600203 ch = self.src[self.cursor]
204 self.cursor += 1
205 if ch not in "0123456789abcdefABCDEF":
206 raise QAPISchemaError(self,
207 '\\u escape needs 4 '
208 'hex digits')
209 value = (value << 4) + int(ch, 16)
210 # If Python 2 and 3 didn't disagree so much on
211 # how to handle Unicode, then we could allow
212 # Unicode string defaults. But most of QAPI is
213 # ASCII-only, so we aren't losing much for now.
214 if not value or value > 0x7f:
215 raise QAPISchemaError(self,
216 'For now, \\u escape '
217 'only supports non-zero '
218 'values up to \\u007f')
219 string += chr(value)
220 elif ch in "\\/'\"":
221 string += ch
222 else:
223 raise QAPISchemaError(self,
Eric Blake437db252015-09-29 16:21:02 -0600224 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200225 esc = False
226 elif ch == "\\":
227 esc = True
228 elif ch == "'":
229 self.val = string
230 return
231 else:
232 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200233 elif self.src.startswith("true", self.pos):
234 self.val = True
235 self.cursor += 3
236 return
237 elif self.src.startswith("false", self.pos):
238 self.val = False
239 self.cursor += 4
240 return
241 elif self.src.startswith("null", self.pos):
242 self.val = None
243 self.cursor += 3
244 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200245 elif self.tok == '\n':
246 if self.cursor == len(self.src):
247 self.tok = None
248 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800249 self.line += 1
250 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200251 elif not self.tok.isspace():
252 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500253
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200254 def get_members(self):
255 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200256 if self.tok == '}':
257 self.accept()
258 return expr
259 if self.tok != "'":
260 raise QAPISchemaError(self, 'Expected string or "}"')
261 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200262 key = self.val
263 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200264 if self.tok != ':':
265 raise QAPISchemaError(self, 'Expected ":"')
266 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800267 if key in expr:
268 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200269 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200270 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200271 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200272 return expr
273 if self.tok != ',':
274 raise QAPISchemaError(self, 'Expected "," or "}"')
275 self.accept()
276 if self.tok != "'":
277 raise QAPISchemaError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500278
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200279 def get_values(self):
280 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200281 if self.tok == ']':
282 self.accept()
283 return expr
Eric Blake437db252015-09-29 16:21:02 -0600284 if self.tok not in "{['tfn":
Fam Zhenge53188a2015-05-04 09:05:18 -0600285 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
286 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200287 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200288 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200289 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200290 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200291 return expr
292 if self.tok != ',':
293 raise QAPISchemaError(self, 'Expected "," or "]"')
294 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500295
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200296 def get_expr(self, nested):
297 if self.tok != '{' and not nested:
298 raise QAPISchemaError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200299 if self.tok == '{':
300 self.accept()
301 expr = self.get_members()
302 elif self.tok == '[':
303 self.accept()
304 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600305 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200306 expr = self.val
307 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200308 else:
309 raise QAPISchemaError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200310 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200311
Markus Armbruster00e4b282015-06-10 10:04:36 +0200312#
313# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200314# TODO fold into QAPISchema
315# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200316#
317
Eric Blake437db252015-09-29 16:21:02 -0600318
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800319def find_base_fields(base):
320 base_struct_define = find_struct(base)
321 if not base_struct_define:
322 return None
323 return base_struct_define['data']
324
Eric Blake437db252015-09-29 16:21:02 -0600325
Eric Blake811d04f2015-05-04 09:05:10 -0600326# Return the qtype of an alternate branch, or None on error.
327def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600328 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600329 return builtin_types[qapi_type]
330 elif find_struct(qapi_type):
331 return "QTYPE_QDICT"
332 elif find_enum(qapi_type):
333 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600334 elif find_union(qapi_type):
335 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600336 return None
337
Eric Blake437db252015-09-29 16:21:02 -0600338
Wenchao Xiabceae762014-03-06 17:08:56 -0800339# Return the discriminator enum define if discriminator is specified as an
340# enum type, otherwise return None.
341def discriminator_find_enum_define(expr):
342 base = expr.get('base')
343 discriminator = expr.get('discriminator')
344
345 if not (discriminator and base):
346 return None
347
348 base_fields = find_base_fields(base)
349 if not base_fields:
350 return None
351
352 discriminator_type = base_fields.get(discriminator)
353 if not discriminator_type:
354 return None
355
356 return find_enum(discriminator_type)
357
Eric Blake437db252015-09-29 16:21:02 -0600358
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200359# FIXME should enforce "other than downstream extensions [...], all
360# names should begin with a letter".
Eric Blakec9e0a792015-05-04 09:05:22 -0600361valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600362
363
364def check_name(expr_info, source, name, allow_optional=False,
365 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600366 global valid_name
367 membername = name
368
369 if not isinstance(name, str):
370 raise QAPIExprError(expr_info,
371 "%s requires a string name" % source)
372 if name.startswith('*'):
373 membername = name[1:]
374 if not allow_optional:
375 raise QAPIExprError(expr_info,
376 "%s does not allow optional name '%s'"
377 % (source, name))
378 # Enum members can start with a digit, because the generated C
379 # code always prefixes it with the enum name
380 if enum_member:
381 membername = '_' + membername
382 if not valid_name.match(membername):
383 raise QAPIExprError(expr_info,
384 "%s uses invalid name '%s'" % (source, name))
385
Eric Blake437db252015-09-29 16:21:02 -0600386
387def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200388 global all_names
389 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200390 # FIXME should reject names that differ only in '_' vs. '.'
391 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200392 if name in all_names:
393 raise QAPIExprError(info,
394 "%s '%s' is already defined"
395 % (all_names[name], name))
396 if not implicit and name[-4:] == 'Kind':
397 raise QAPIExprError(info,
398 "%s '%s' should not end in 'Kind'"
399 % (meta, name))
400 all_names[name] = meta
401
Eric Blake437db252015-09-29 16:21:02 -0600402
Markus Armbruster00e4b282015-06-10 10:04:36 +0200403def add_struct(definition, info):
404 global struct_types
405 name = definition['struct']
406 add_name(name, info, 'struct')
407 struct_types.append(definition)
408
Eric Blake437db252015-09-29 16:21:02 -0600409
Markus Armbruster00e4b282015-06-10 10:04:36 +0200410def find_struct(name):
411 global struct_types
412 for struct in struct_types:
413 if struct['struct'] == name:
414 return struct
415 return None
416
Eric Blake437db252015-09-29 16:21:02 -0600417
Markus Armbruster00e4b282015-06-10 10:04:36 +0200418def add_union(definition, info):
419 global union_types
420 name = definition['union']
421 add_name(name, info, 'union')
422 union_types.append(definition)
423
Eric Blake437db252015-09-29 16:21:02 -0600424
Markus Armbruster00e4b282015-06-10 10:04:36 +0200425def find_union(name):
426 global union_types
427 for union in union_types:
428 if union['union'] == name:
429 return union
430 return None
431
Eric Blake437db252015-09-29 16:21:02 -0600432
433def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200434 global enum_types
435 add_name(name, info, 'enum', implicit)
436 enum_types.append({"enum_name": name, "enum_values": enum_values})
437
Eric Blake437db252015-09-29 16:21:02 -0600438
Markus Armbruster00e4b282015-06-10 10:04:36 +0200439def find_enum(name):
440 global enum_types
441 for enum in enum_types:
442 if enum['enum_name'] == name:
443 return enum
444 return None
445
Markus Armbruster00e4b282015-06-10 10:04:36 +0200446
Eric Blake437db252015-09-29 16:21:02 -0600447def is_enum(name):
448 return find_enum(name) is not None
449
450
451def check_type(expr_info, source, value, allow_array=False,
452 allow_dict=False, allow_optional=False,
453 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600454 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600455
456 if value is None:
457 return
458
Eric Blakedd883c62015-05-04 09:05:21 -0600459 # Check if array type for value is okay
460 if isinstance(value, list):
461 if not allow_array:
462 raise QAPIExprError(expr_info,
463 "%s cannot be an array" % source)
464 if len(value) != 1 or not isinstance(value[0], str):
465 raise QAPIExprError(expr_info,
466 "%s: array type must contain single type name"
467 % source)
468 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600469
470 # Check if type name for value is okay
471 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600472 if value not in all_names:
Eric Blakedd883c62015-05-04 09:05:21 -0600473 raise QAPIExprError(expr_info,
474 "%s uses unknown type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200475 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600476 if not all_names[value] in allow_metas:
477 raise QAPIExprError(expr_info,
478 "%s cannot use %s type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200479 % (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600480 return
481
Eric Blakedd883c62015-05-04 09:05:21 -0600482 if not allow_dict:
483 raise QAPIExprError(expr_info,
484 "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200485
486 if not isinstance(value, OrderedDict):
487 raise QAPIExprError(expr_info,
488 "%s should be a dictionary or type name" % source)
489
490 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600491 for (key, arg) in value.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600492 check_name(expr_info, "Member of %s" % source, key,
493 allow_optional=allow_optional)
Eric Blake6b5abc72015-05-04 09:05:33 -0600494 # Todo: allow dictionaries to represent default values of
495 # an optional argument.
Eric Blakedd883c62015-05-04 09:05:21 -0600496 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200497 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600498 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600499 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600500
Eric Blake437db252015-09-29 16:21:02 -0600501
502def check_member_clash(expr_info, base_name, data, source=""):
Eric Blakeff55d722015-05-04 09:05:37 -0600503 base = find_struct(base_name)
504 assert base
505 base_members = base['data']
506 for key in data.keys():
507 if key.startswith('*'):
508 key = key[1:]
509 if key in base_members or "*" + key in base_members:
510 raise QAPIExprError(expr_info,
511 "Member name '%s'%s clashes with base '%s'"
512 % (key, source, base_name))
513 if base.get('base'):
514 check_member_clash(expr_info, base['base'], data, source)
515
Eric Blake437db252015-09-29 16:21:02 -0600516
Eric Blakedd883c62015-05-04 09:05:21 -0600517def check_command(expr, expr_info):
518 name = expr['command']
Eric Blake2cbf0992015-05-04 09:05:24 -0600519
Eric Blakedd883c62015-05-04 09:05:21 -0600520 check_type(expr_info, "'data' for command '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600521 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200522 allow_metas=['struct'])
Eric Blake10d4d992015-05-04 09:05:23 -0600523 returns_meta = ['union', 'struct']
524 if name in returns_whitelist:
525 returns_meta += ['built-in', 'alternate', 'enum']
Eric Blakedd883c62015-05-04 09:05:21 -0600526 check_type(expr_info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200527 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200528 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600529
Eric Blake437db252015-09-29 16:21:02 -0600530
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200531def check_event(expr, expr_info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600532 global events
533 name = expr['event']
Eric Blake4dc2e692015-05-04 09:05:17 -0600534
535 if name.upper() == 'MAX':
536 raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
537 events.append(name)
Eric Blakedd883c62015-05-04 09:05:21 -0600538 check_type(expr_info, "'data' for event '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600539 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster315932b2015-07-01 10:12:24 +0200540 allow_metas=['struct'])
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200541
Eric Blake437db252015-09-29 16:21:02 -0600542
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800543def check_union(expr, expr_info):
544 name = expr['union']
545 base = expr.get('base')
546 discriminator = expr.get('discriminator')
547 members = expr['data']
Eric Blake7b2a5c22015-09-29 16:21:04 -0600548 values = {'MAX': '(automatic)', 'KIND': '(automatic)'}
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800549
Eric Blake811d04f2015-05-04 09:05:10 -0600550 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600551
552 # With no discriminator it is a simple union.
553 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600554 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600555 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600556 if base is not None:
557 raise QAPIExprError(expr_info,
Eric Blake811d04f2015-05-04 09:05:10 -0600558 "Simple union '%s' must not have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600559 % name)
560
561 # Else, it's a flat union.
562 else:
563 # The object must have a string member 'base'.
Eric Blake376863e2015-09-29 16:21:07 -0600564 check_type(expr_info, "'base' for union '%s'" % name,
565 base, allow_metas=['struct'])
566 if not base:
Eric Blake44bd1272015-05-04 09:05:08 -0600567 raise QAPIExprError(expr_info,
Eric Blake376863e2015-09-29 16:21:07 -0600568 "Flat union '%s' must have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600569 % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800570 base_fields = find_base_fields(base)
Eric Blake376863e2015-09-29 16:21:07 -0600571 assert base_fields
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800572
Eric Blakec9e0a792015-05-04 09:05:22 -0600573 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600574 # member of the base struct.
Eric Blakec9e0a792015-05-04 09:05:22 -0600575 check_name(expr_info, "Discriminator of flat union '%s'" % name,
576 discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800577 discriminator_type = base_fields.get(discriminator)
578 if not discriminator_type:
579 raise QAPIExprError(expr_info,
580 "Discriminator '%s' is not a member of base "
Eric Blakefd41dd42015-05-04 09:05:25 -0600581 "struct '%s'"
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800582 % (discriminator, base))
583 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600584 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800585 # Do not allow string discriminator
586 if not enum_define:
587 raise QAPIExprError(expr_info,
588 "Discriminator '%s' must be of enumeration "
589 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800590
591 # Check every branch
592 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600593 check_name(expr_info, "Member of union '%s'" % name, key)
594
Eric Blakedd883c62015-05-04 09:05:21 -0600595 # Each value must name a known type; furthermore, in flat unions,
Eric Blakeff55d722015-05-04 09:05:37 -0600596 # branches must be a struct with no overlapping member names
Eric Blakedd883c62015-05-04 09:05:21 -0600597 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200598 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakeff55d722015-05-04 09:05:37 -0600599 if base:
600 branch_struct = find_struct(value)
601 assert branch_struct
602 check_member_clash(expr_info, base, branch_struct['data'],
603 " of branch '%s'" % key)
Eric Blakedd883c62015-05-04 09:05:21 -0600604
Eric Blake44bd1272015-05-04 09:05:08 -0600605 # If the discriminator names an enum type, then all members
Eric Blake7b2a5c22015-09-29 16:21:04 -0600606 # of 'data' must also be members of the enum type, which in turn
607 # must not collide with the discriminator name.
Eric Blake44bd1272015-05-04 09:05:08 -0600608 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600609 if key not in enum_define['enum_values']:
Eric Blake44bd1272015-05-04 09:05:08 -0600610 raise QAPIExprError(expr_info,
611 "Discriminator value '%s' is not found in "
612 "enum '%s'" %
613 (key, enum_define["enum_name"]))
Eric Blake7b2a5c22015-09-29 16:21:04 -0600614 if discriminator in enum_define['enum_values']:
615 raise QAPIExprError(expr_info,
616 "Discriminator name '%s' collides with "
617 "enum value in '%s'" %
618 (discriminator, enum_define["enum_name"]))
Eric Blake44bd1272015-05-04 09:05:08 -0600619
620 # Otherwise, check for conflicts in the generated enum
621 else:
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600622 c_key = camel_to_upper(key)
Eric Blake44bd1272015-05-04 09:05:08 -0600623 if c_key in values:
624 raise QAPIExprError(expr_info,
625 "Union '%s' member '%s' clashes with '%s'"
626 % (name, key, values[c_key]))
627 values[c_key] = key
628
Eric Blake437db252015-09-29 16:21:02 -0600629
Eric Blake811d04f2015-05-04 09:05:10 -0600630def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600631 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600632 members = expr['data']
Eric Blake437db252015-09-29 16:21:02 -0600633 values = {'MAX': '(automatic)'}
Eric Blake811d04f2015-05-04 09:05:10 -0600634 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600635
Eric Blake811d04f2015-05-04 09:05:10 -0600636 # Check every branch
637 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600638 check_name(expr_info, "Member of alternate '%s'" % name, key)
639
Eric Blake811d04f2015-05-04 09:05:10 -0600640 # Check for conflicts in the generated enum
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600641 c_key = camel_to_upper(key)
Eric Blake811d04f2015-05-04 09:05:10 -0600642 if c_key in values:
643 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600644 "Alternate '%s' member '%s' clashes with '%s'"
645 % (name, key, values[c_key]))
Eric Blake811d04f2015-05-04 09:05:10 -0600646 values[c_key] = key
647
648 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600649 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
650 value,
651 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600652 qtype = find_alternate_member_qtype(value)
Eric Blakedd883c62015-05-04 09:05:21 -0600653 assert qtype
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 Blake437db252015-09-29 16:21:02 -0600666 values = {'MAX': '(automatic)'}
Eric Blakecf393592015-05-04 09:05:04 -0600667
668 if not isinstance(members, list):
669 raise QAPIExprError(expr_info,
670 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100671 if prefix is not None and not isinstance(prefix, str):
672 raise QAPIExprError(expr_info,
673 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600674 for member in members:
Eric Blake437db252015-09-29 16:21:02 -0600675 check_name(expr_info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600676 enum_member=True)
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600677 key = camel_to_upper(member)
Eric Blakecf393592015-05-04 09:05:04 -0600678 if key in values:
679 raise QAPIExprError(expr_info,
680 "Enum '%s' member '%s' clashes with '%s'"
681 % (name, member, values[key]))
682 values[key] = member
683
Eric Blake437db252015-09-29 16:21:02 -0600684
Eric Blakedd883c62015-05-04 09:05:21 -0600685def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600686 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600687 members = expr['data']
688
Eric Blakefd41dd42015-05-04 09:05:25 -0600689 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600690 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600691 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600692 allow_metas=['struct'])
Eric Blakeff55d722015-05-04 09:05:37 -0600693 if expr.get('base'):
694 check_member_clash(expr_info, expr['base'], expr['data'])
Eric Blakedd883c62015-05-04 09:05:21 -0600695
Eric Blake437db252015-09-29 16:21:02 -0600696
Eric Blake0545f6b2015-05-04 09:05:15 -0600697def check_keys(expr_elem, meta, required, optional=[]):
698 expr = expr_elem['expr']
699 info = expr_elem['info']
700 name = expr[meta]
701 if not isinstance(name, str):
702 raise QAPIExprError(info,
703 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600704 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600705 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600706 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600707 raise QAPIExprError(info,
708 "Unknown key '%s' in %s '%s'"
709 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600710 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600711 raise QAPIExprError(info,
712 "'%s' of %s '%s' should only use false value"
713 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600714 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600715 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600716 raise QAPIExprError(info,
717 "Key '%s' is missing from %s '%s'"
718 % (key, meta, name))
719
Eric Blake437db252015-09-29 16:21:02 -0600720
Markus Armbruster4d076d62015-06-10 08:55:21 +0200721def check_exprs(exprs):
722 global all_names
723
724 # Learn the types and check for valid expression keys
725 for builtin in builtin_types.keys():
726 all_names[builtin] = 'built-in'
727 for expr_elem in exprs:
728 expr = expr_elem['expr']
729 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600730 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100731 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200732 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600733 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200734 check_keys(expr_elem, 'union', ['data'],
735 ['base', 'discriminator'])
736 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600737 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200738 check_keys(expr_elem, 'alternate', ['data'])
739 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600740 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200741 check_keys(expr_elem, 'struct', ['data'], ['base'])
742 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600743 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200744 check_keys(expr_elem, 'command', [],
745 ['data', 'returns', 'gen', 'success-response'])
746 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600747 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200748 check_keys(expr_elem, 'event', [], ['data'])
749 add_name(expr['event'], info, 'event')
750 else:
751 raise QAPIExprError(expr_elem['info'],
752 "Expression is missing metatype")
753
754 # Try again for hidden UnionKind enum
755 for expr_elem in exprs:
756 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600757 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200758 if not discriminator_find_enum_define(expr):
759 add_enum('%sKind' % expr['union'], expr_elem['info'],
760 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600761 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200762 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
763 implicit=True)
764
765 # Validate that exprs make sense
766 for expr_elem in exprs:
767 expr = expr_elem['expr']
768 info = expr_elem['info']
769
Eric Blake437db252015-09-29 16:21:02 -0600770 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200771 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600772 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200773 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600774 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200775 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600776 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200777 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600778 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200779 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600780 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200781 check_event(expr, info)
782 else:
783 assert False, 'unexpected meta type'
784
Markus Armbrusterac882192015-09-16 13:06:05 +0200785 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600786
Markus Armbrusterac882192015-09-16 13:06:05 +0200787
788#
789# Schema compiler frontend
790#
791
792class QAPISchemaEntity(object):
793 def __init__(self, name, info):
794 assert isinstance(name, str)
795 self.name = name
796 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
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200804 def visit(self, visitor):
805 pass
806
807
808class QAPISchemaVisitor(object):
809 def visit_begin(self, schema):
810 pass
811
812 def visit_end(self):
813 pass
814
Eric Blake25a0d9c2015-10-12 22:22:21 -0600815 def visit_needed(self, entity):
816 # Default to visiting everything
817 return True
818
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200819 def visit_builtin_type(self, name, info, json_type):
820 pass
821
822 def visit_enum_type(self, name, info, values, prefix):
823 pass
824
825 def visit_array_type(self, name, info, element_type):
826 pass
827
828 def visit_object_type(self, name, info, base, members, variants):
829 pass
830
Markus Armbruster39a18152015-09-16 13:06:28 +0200831 def visit_object_type_flat(self, name, info, members, variants):
832 pass
833
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200834 def visit_alternate_type(self, name, info, variants):
835 pass
836
837 def visit_command(self, name, info, arg_type, ret_type,
838 gen, success_response):
839 pass
840
841 def visit_event(self, name, info, arg_type):
842 pass
843
Markus Armbrusterac882192015-09-16 13:06:05 +0200844
845class QAPISchemaType(QAPISchemaEntity):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200846 def c_type(self, is_param=False):
847 return c_name(self.name) + pointer_suffix
848
849 def c_null(self):
850 return 'NULL'
851
852 def json_type(self):
853 pass
854
855 def alternate_qtype(self):
856 json2qtype = {
857 'string': 'QTYPE_QSTRING',
858 'number': 'QTYPE_QFLOAT',
859 'int': 'QTYPE_QINT',
860 'boolean': 'QTYPE_QBOOL',
861 'object': 'QTYPE_QDICT'
862 }
863 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200864
865
866class QAPISchemaBuiltinType(QAPISchemaType):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200867 def __init__(self, name, json_type, c_type, c_null):
Markus Armbrusterac882192015-09-16 13:06:05 +0200868 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200869 assert not c_type or isinstance(c_type, str)
870 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
871 'value')
872 self._json_type_name = json_type
873 self._c_type_name = c_type
874 self._c_null_val = c_null
875
876 def c_name(self):
877 return self.name
878
879 def c_type(self, is_param=False):
880 if is_param and self.name == 'str':
881 return 'const ' + self._c_type_name
882 return self._c_type_name
883
884 def c_null(self):
885 return self._c_null_val
886
887 def json_type(self):
888 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200889
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200890 def visit(self, visitor):
891 visitor.visit_builtin_type(self.name, self.info, self.json_type())
892
Markus Armbrusterac882192015-09-16 13:06:05 +0200893
894class QAPISchemaEnumType(QAPISchemaType):
895 def __init__(self, name, info, values, prefix):
896 QAPISchemaType.__init__(self, name, info)
897 for v in values:
898 assert isinstance(v, str)
899 assert prefix is None or isinstance(prefix, str)
900 self.values = values
901 self.prefix = prefix
902
903 def check(self, schema):
904 assert len(set(self.values)) == len(self.values)
905
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200906 def c_type(self, is_param=False):
907 return c_name(self.name)
908
909 def c_null(self):
910 return c_enum_const(self.name, (self.values + ['MAX'])[0],
911 self.prefix)
912
913 def json_type(self):
914 return 'string'
915
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200916 def visit(self, visitor):
917 visitor.visit_enum_type(self.name, self.info,
918 self.values, self.prefix)
919
Markus Armbrusterac882192015-09-16 13:06:05 +0200920
921class QAPISchemaArrayType(QAPISchemaType):
922 def __init__(self, name, info, element_type):
923 QAPISchemaType.__init__(self, name, info)
924 assert isinstance(element_type, str)
925 self._element_type_name = element_type
926 self.element_type = None
927
928 def check(self, schema):
929 self.element_type = schema.lookup_type(self._element_type_name)
930 assert self.element_type
931
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200932 def json_type(self):
933 return 'array'
934
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200935 def visit(self, visitor):
936 visitor.visit_array_type(self.name, self.info, self.element_type)
937
Markus Armbrusterac882192015-09-16 13:06:05 +0200938
939class QAPISchemaObjectType(QAPISchemaType):
940 def __init__(self, name, info, base, local_members, variants):
941 QAPISchemaType.__init__(self, name, info)
942 assert base is None or isinstance(base, str)
943 for m in local_members:
944 assert isinstance(m, QAPISchemaObjectTypeMember)
945 assert (variants is None or
946 isinstance(variants, QAPISchemaObjectTypeVariants))
947 self._base_name = base
948 self.base = None
949 self.local_members = local_members
950 self.variants = variants
951 self.members = None
952
953 def check(self, schema):
954 assert self.members is not False # not running in cycles
955 if self.members:
956 return
957 self.members = False # mark as being checked
958 if self._base_name:
959 self.base = schema.lookup_type(self._base_name)
960 assert isinstance(self.base, QAPISchemaObjectType)
961 assert not self.base.variants # not implemented
962 self.base.check(schema)
963 members = list(self.base.members)
964 else:
965 members = []
966 seen = {}
967 for m in members:
Eric Blake7618b912015-10-12 22:22:22 -0600968 assert c_name(m.name) not in seen
Markus Armbrusterac882192015-09-16 13:06:05 +0200969 seen[m.name] = m
970 for m in self.local_members:
971 m.check(schema, members, seen)
972 if self.variants:
973 self.variants.check(schema, members, seen)
974 self.members = members
975
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200976 def c_name(self):
977 assert self.info
978 return QAPISchemaType.c_name(self)
979
980 def c_type(self, is_param=False):
981 assert self.info
982 return QAPISchemaType.c_type(self)
983
984 def json_type(self):
985 return 'object'
986
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200987 def visit(self, visitor):
988 visitor.visit_object_type(self.name, self.info,
989 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +0200990 visitor.visit_object_type_flat(self.name, self.info,
991 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200992
Markus Armbrusterac882192015-09-16 13:06:05 +0200993
994class QAPISchemaObjectTypeMember(object):
995 def __init__(self, name, typ, optional):
996 assert isinstance(name, str)
997 assert isinstance(typ, str)
998 assert isinstance(optional, bool)
999 self.name = name
1000 self._type_name = typ
1001 self.type = None
1002 self.optional = optional
1003
1004 def check(self, schema, all_members, seen):
1005 assert self.name not in seen
1006 self.type = schema.lookup_type(self._type_name)
1007 assert self.type
1008 all_members.append(self)
1009 seen[self.name] = self
1010
1011
1012class QAPISchemaObjectTypeVariants(object):
1013 def __init__(self, tag_name, tag_enum, variants):
1014 assert tag_name is None or isinstance(tag_name, str)
1015 assert tag_enum is None or isinstance(tag_enum, str)
1016 for v in variants:
1017 assert isinstance(v, QAPISchemaObjectTypeVariant)
1018 self.tag_name = tag_name
1019 if tag_name:
1020 assert not tag_enum
1021 self.tag_member = None
1022 else:
1023 self.tag_member = QAPISchemaObjectTypeMember('type', tag_enum,
1024 False)
1025 self.variants = variants
1026
1027 def check(self, schema, members, seen):
1028 if self.tag_name:
1029 self.tag_member = seen[self.tag_name]
1030 else:
1031 self.tag_member.check(schema, members, seen)
1032 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1033 for v in self.variants:
1034 vseen = dict(seen)
1035 v.check(schema, self.tag_member.type, vseen)
1036
Eric Blake437db252015-09-29 16:21:02 -06001037
Markus Armbrusterac882192015-09-16 13:06:05 +02001038class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1039 def __init__(self, name, typ):
1040 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1041
1042 def check(self, schema, tag_type, seen):
1043 QAPISchemaObjectTypeMember.check(self, schema, [], seen)
1044 assert self.name in tag_type.values
1045
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001046 # This function exists to support ugly simple union special cases
1047 # TODO get rid of them, and drop the function
1048 def simple_union_type(self):
1049 if isinstance(self.type, QAPISchemaObjectType) and not self.type.info:
1050 assert len(self.type.members) == 1
1051 assert not self.type.variants
1052 return self.type.members[0].type
1053 return None
1054
Markus Armbrusterac882192015-09-16 13:06:05 +02001055
1056class QAPISchemaAlternateType(QAPISchemaType):
1057 def __init__(self, name, info, variants):
1058 QAPISchemaType.__init__(self, name, info)
1059 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1060 assert not variants.tag_name
1061 self.variants = variants
1062
1063 def check(self, schema):
1064 self.variants.check(schema, [], {})
1065
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001066 def json_type(self):
1067 return 'value'
1068
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001069 def visit(self, visitor):
1070 visitor.visit_alternate_type(self.name, self.info, self.variants)
1071
Markus Armbrusterac882192015-09-16 13:06:05 +02001072
1073class QAPISchemaCommand(QAPISchemaEntity):
1074 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1075 QAPISchemaEntity.__init__(self, name, info)
1076 assert not arg_type or isinstance(arg_type, str)
1077 assert not ret_type or isinstance(ret_type, str)
1078 self._arg_type_name = arg_type
1079 self.arg_type = None
1080 self._ret_type_name = ret_type
1081 self.ret_type = None
1082 self.gen = gen
1083 self.success_response = success_response
1084
1085 def check(self, schema):
1086 if self._arg_type_name:
1087 self.arg_type = schema.lookup_type(self._arg_type_name)
1088 assert isinstance(self.arg_type, QAPISchemaObjectType)
1089 assert not self.arg_type.variants # not implemented
1090 if self._ret_type_name:
1091 self.ret_type = schema.lookup_type(self._ret_type_name)
1092 assert isinstance(self.ret_type, QAPISchemaType)
1093
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001094 def visit(self, visitor):
1095 visitor.visit_command(self.name, self.info,
1096 self.arg_type, self.ret_type,
1097 self.gen, self.success_response)
1098
Markus Armbrusterac882192015-09-16 13:06:05 +02001099
1100class QAPISchemaEvent(QAPISchemaEntity):
1101 def __init__(self, name, info, arg_type):
1102 QAPISchemaEntity.__init__(self, name, info)
1103 assert not arg_type or isinstance(arg_type, str)
1104 self._arg_type_name = arg_type
1105 self.arg_type = None
1106
1107 def check(self, schema):
1108 if self._arg_type_name:
1109 self.arg_type = schema.lookup_type(self._arg_type_name)
1110 assert isinstance(self.arg_type, QAPISchemaObjectType)
1111 assert not self.arg_type.variants # not implemented
1112
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001113 def visit(self, visitor):
1114 visitor.visit_event(self.name, self.info, self.arg_type)
1115
Markus Armbrusterac882192015-09-16 13:06:05 +02001116
1117class QAPISchema(object):
1118 def __init__(self, fname):
1119 try:
1120 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001121 self._entity_dict = {}
1122 self._def_predefineds()
1123 self._def_exprs()
1124 self.check()
Markus Armbrusterac882192015-09-16 13:06:05 +02001125 except (QAPISchemaError, QAPIExprError), err:
1126 print >>sys.stderr, err
1127 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001128
Markus Armbrusterac882192015-09-16 13:06:05 +02001129 def _def_entity(self, ent):
1130 assert ent.name not in self._entity_dict
1131 self._entity_dict[ent.name] = ent
1132
1133 def lookup_entity(self, name, typ=None):
1134 ent = self._entity_dict.get(name)
1135 if typ and not isinstance(ent, typ):
1136 return None
1137 return ent
1138
1139 def lookup_type(self, name):
1140 return self.lookup_entity(name, QAPISchemaType)
1141
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001142 def _def_builtin_type(self, name, json_type, c_type, c_null):
1143 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1144 c_type, c_null))
Markus Armbruster28770e02015-09-16 13:06:24 +02001145 self._make_array_type(name) # TODO really needed?
Markus Armbrusterac882192015-09-16 13:06:05 +02001146
1147 def _def_predefineds(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001148 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1149 ('number', 'number', 'double', '0'),
1150 ('int', 'int', 'int64_t', '0'),
1151 ('int8', 'int', 'int8_t', '0'),
1152 ('int16', 'int', 'int16_t', '0'),
1153 ('int32', 'int', 'int32_t', '0'),
1154 ('int64', 'int', 'int64_t', '0'),
1155 ('uint8', 'int', 'uint8_t', '0'),
1156 ('uint16', 'int', 'uint16_t', '0'),
1157 ('uint32', 'int', 'uint32_t', '0'),
1158 ('uint64', 'int', 'uint64_t', '0'),
1159 ('size', 'int', 'uint64_t', '0'),
1160 ('bool', 'boolean', 'bool', 'false'),
Markus Armbruster28770e02015-09-16 13:06:24 +02001161 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001162 self._def_builtin_type(*t)
Markus Armbruster39a18152015-09-16 13:06:28 +02001163 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1164 [], None)
1165 self._def_entity(self.the_empty_object_type)
Markus Armbrusterac882192015-09-16 13:06:05 +02001166
1167 def _make_implicit_enum_type(self, name, values):
1168 name = name + 'Kind'
1169 self._def_entity(QAPISchemaEnumType(name, None, values, None))
1170 return name
1171
1172 def _make_array_type(self, element_type):
1173 name = element_type + 'List'
1174 if not self.lookup_type(name):
1175 self._def_entity(QAPISchemaArrayType(name, None, element_type))
1176 return name
1177
1178 def _make_implicit_object_type(self, name, role, members):
1179 if not members:
1180 return None
1181 name = ':obj-%s-%s' % (name, role)
1182 if not self.lookup_entity(name, QAPISchemaObjectType):
1183 self._def_entity(QAPISchemaObjectType(name, None, None,
1184 members, None))
1185 return name
1186
1187 def _def_enum_type(self, expr, info):
1188 name = expr['enum']
1189 data = expr['data']
1190 prefix = expr.get('prefix')
1191 self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
1192 self._make_array_type(name) # TODO really needed?
1193
1194 def _make_member(self, name, typ):
1195 optional = False
1196 if name.startswith('*'):
1197 name = name[1:]
1198 optional = True
1199 if isinstance(typ, list):
1200 assert len(typ) == 1
1201 typ = self._make_array_type(typ[0])
1202 return QAPISchemaObjectTypeMember(name, typ, optional)
1203
1204 def _make_members(self, data):
1205 return [self._make_member(key, value)
1206 for (key, value) in data.iteritems()]
1207
1208 def _def_struct_type(self, expr, info):
1209 name = expr['struct']
1210 base = expr.get('base')
1211 data = expr['data']
1212 self._def_entity(QAPISchemaObjectType(name, info, base,
1213 self._make_members(data),
1214 None))
1215 self._make_array_type(name) # TODO really needed?
1216
1217 def _make_variant(self, case, typ):
1218 return QAPISchemaObjectTypeVariant(case, typ)
1219
1220 def _make_simple_variant(self, case, typ):
1221 if isinstance(typ, list):
1222 assert len(typ) == 1
1223 typ = self._make_array_type(typ[0])
1224 typ = self._make_implicit_object_type(typ, 'wrapper',
1225 [self._make_member('data', typ)])
1226 return QAPISchemaObjectTypeVariant(case, typ)
1227
1228 def _make_tag_enum(self, type_name, variants):
1229 return self._make_implicit_enum_type(type_name,
1230 [v.name for v in variants])
1231
1232 def _def_union_type(self, expr, info):
1233 name = expr['union']
1234 data = expr['data']
1235 base = expr.get('base')
1236 tag_name = expr.get('discriminator')
1237 tag_enum = None
1238 if tag_name:
1239 variants = [self._make_variant(key, value)
1240 for (key, value) in data.iteritems()]
1241 else:
1242 variants = [self._make_simple_variant(key, value)
1243 for (key, value) in data.iteritems()]
1244 tag_enum = self._make_tag_enum(name, variants)
1245 self._def_entity(
1246 QAPISchemaObjectType(name, info, base,
1247 self._make_members(OrderedDict()),
1248 QAPISchemaObjectTypeVariants(tag_name,
1249 tag_enum,
1250 variants)))
1251 self._make_array_type(name) # TODO really needed?
1252
1253 def _def_alternate_type(self, expr, info):
1254 name = expr['alternate']
1255 data = expr['data']
1256 variants = [self._make_variant(key, value)
1257 for (key, value) in data.iteritems()]
1258 tag_enum = self._make_tag_enum(name, variants)
1259 self._def_entity(
1260 QAPISchemaAlternateType(name, info,
1261 QAPISchemaObjectTypeVariants(None,
1262 tag_enum,
1263 variants)))
1264 self._make_array_type(name) # TODO really needed?
1265
1266 def _def_command(self, expr, info):
1267 name = expr['command']
1268 data = expr.get('data')
1269 rets = expr.get('returns')
1270 gen = expr.get('gen', True)
1271 success_response = expr.get('success-response', True)
1272 if isinstance(data, OrderedDict):
1273 data = self._make_implicit_object_type(name, 'arg',
1274 self._make_members(data))
1275 if isinstance(rets, list):
1276 assert len(rets) == 1
1277 rets = self._make_array_type(rets[0])
1278 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1279 success_response))
1280
1281 def _def_event(self, expr, info):
1282 name = expr['event']
1283 data = expr.get('data')
1284 if isinstance(data, OrderedDict):
1285 data = self._make_implicit_object_type(name, 'arg',
1286 self._make_members(data))
1287 self._def_entity(QAPISchemaEvent(name, info, data))
1288
1289 def _def_exprs(self):
1290 for expr_elem in self.exprs:
1291 expr = expr_elem['expr']
1292 info = expr_elem['info']
1293 if 'enum' in expr:
1294 self._def_enum_type(expr, info)
1295 elif 'struct' in expr:
1296 self._def_struct_type(expr, info)
1297 elif 'union' in expr:
1298 self._def_union_type(expr, info)
1299 elif 'alternate' in expr:
1300 self._def_alternate_type(expr, info)
1301 elif 'command' in expr:
1302 self._def_command(expr, info)
1303 elif 'event' in expr:
1304 self._def_event(expr, info)
1305 else:
1306 assert False
1307
1308 def check(self):
1309 for ent in self._entity_dict.values():
1310 ent.check(self)
1311
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001312 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001313 visitor.visit_begin(self)
1314 for (name, entity) in sorted(self._entity_dict.items()):
1315 if visitor.visit_needed(entity):
1316 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001317 visitor.visit_end()
1318
Markus Armbruster2caba362013-07-27 17:41:56 +02001319
Markus Armbruster00e4b282015-06-10 10:04:36 +02001320#
1321# Code generation helpers
1322#
1323
Michael Roth0f923be2011-07-19 14:50:39 -05001324def camel_case(name):
1325 new_name = ''
1326 first = True
1327 for ch in name:
1328 if ch in ['_', '-']:
1329 first = True
1330 elif first:
1331 new_name += ch.upper()
1332 first = False
1333 else:
1334 new_name += ch.lower()
1335 return new_name
1336
Eric Blake437db252015-09-29 16:21:02 -06001337
Markus Armbruster849bc532015-05-14 06:50:53 -06001338# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1339# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1340# ENUM24_Name -> ENUM24_NAME
1341def camel_to_upper(value):
1342 c_fun_str = c_name(value, False)
1343 if value.isupper():
1344 return c_fun_str
1345
1346 new_name = ''
1347 l = len(c_fun_str)
1348 for i in range(l):
1349 c = c_fun_str[i]
1350 # When c is upper and no "_" appears before, do more checks
1351 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001352 if i < l - 1 and c_fun_str[i + 1].islower():
1353 new_name += '_'
1354 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001355 new_name += '_'
1356 new_name += c
1357 return new_name.lstrip('_').upper()
1358
Eric Blake437db252015-09-29 16:21:02 -06001359
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001360def c_enum_const(type_name, const_name, prefix=None):
1361 if prefix is not None:
1362 type_name = prefix
Markus Armbruster849bc532015-05-14 06:50:53 -06001363 return camel_to_upper(type_name + '_' + const_name)
1364
Eric Blake18df5152015-05-14 06:50:48 -06001365c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001366
Eric Blake437db252015-09-29 16:21:02 -06001367
Eric Blakec6405b52015-05-14 06:50:55 -06001368# Map @name to a valid C identifier.
1369# If @protect, avoid returning certain ticklish identifiers (like
1370# C keywords) by prepending "q_".
1371#
1372# Used for converting 'name' from a 'name':'type' qapi definition
1373# into a generated struct member, as well as converting type names
1374# into substrings of a generated C function name.
1375# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1376# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001377def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001378 # ANSI X3J11/88-090, 3.1.1
1379 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001380 'default', 'do', 'double', 'else', 'enum', 'extern',
1381 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1382 'return', 'short', 'signed', 'sizeof', 'static',
1383 'struct', 'switch', 'typedef', 'union', 'unsigned',
1384 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001385 # ISO/IEC 9899:1999, 6.4.1
1386 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1387 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001388 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1389 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001390 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1391 # excluding _.*
1392 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001393 # C++ ISO/IEC 14882:2003 2.11
1394 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1395 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1396 'namespace', 'new', 'operator', 'private', 'protected',
1397 'public', 'reinterpret_cast', 'static_cast', 'template',
1398 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1399 'using', 'virtual', 'wchar_t',
1400 # alternative representations
1401 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1402 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001403 # namespace pollution:
Max Reitz8592a542013-12-20 19:28:18 +01001404 polluted_words = set(['unix', 'errno'])
Eric Blake437db252015-09-29 16:21:02 -06001405 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1406 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001407 return "q_" + name
Eric Blake18df5152015-05-14 06:50:48 -06001408 return name.translate(c_name_trans)
Michael Roth0f923be2011-07-19 14:50:39 -05001409
Amos Kong05dfb262014-06-10 19:25:53 +08001410eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001411pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001412
Eric Blake437db252015-09-29 16:21:02 -06001413
Michael Roth0f923be2011-07-19 14:50:39 -05001414def genindent(count):
1415 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001416 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001417 ret += " "
1418 return ret
1419
1420indent_level = 0
1421
Eric Blake437db252015-09-29 16:21:02 -06001422
Michael Roth0f923be2011-07-19 14:50:39 -05001423def push_indent(indent_amount=4):
1424 global indent_level
1425 indent_level += indent_amount
1426
Eric Blake437db252015-09-29 16:21:02 -06001427
Michael Roth0f923be2011-07-19 14:50:39 -05001428def pop_indent(indent_amount=4):
1429 global indent_level
1430 indent_level -= indent_amount
1431
Eric Blake437db252015-09-29 16:21:02 -06001432
Markus Armbruster77e703b2015-06-24 19:27:32 +02001433# Generate @code with @kwds interpolated.
1434# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001435def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001436 raw = code % kwds
1437 if indent_level:
1438 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001439 # re.subn() lacks flags support before Python 2.7, use re.compile()
1440 raw = re.subn(re.compile("^.", re.MULTILINE),
1441 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001442 raw = raw[0]
1443 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001444
Eric Blake437db252015-09-29 16:21:02 -06001445
Michael Roth0f923be2011-07-19 14:50:39 -05001446def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001447 if code[0] == '\n':
1448 code = code[1:]
1449 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001450
Michael Roth0f923be2011-07-19 14:50:39 -05001451
1452def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001453 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001454
Eric Blake437db252015-09-29 16:21:02 -06001455
Michael Rothc0afa9c2013-05-10 17:46:00 -05001456def guardstart(name):
1457 return mcgen('''
1458
1459#ifndef %(name)s
1460#define %(name)s
1461
1462''',
1463 name=guardname(name))
1464
Eric Blake437db252015-09-29 16:21:02 -06001465
Michael Rothc0afa9c2013-05-10 17:46:00 -05001466def guardend(name):
1467 return mcgen('''
1468
1469#endif /* %(name)s */
1470
1471''',
1472 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001473
Eric Blake437db252015-09-29 16:21:02 -06001474
Markus Armbrustere98859a2015-09-16 13:06:16 +02001475def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001476 ret = mcgen('''
1477
Markus Armbrustere98859a2015-09-16 13:06:16 +02001478const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001479''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001480 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001481 for value in values:
1482 index = c_enum_const(name, value, prefix)
1483 ret += mcgen('''
1484 [%(index)s] = "%(value)s",
1485''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001486 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001487
1488 max_index = c_enum_const(name, 'MAX', prefix)
1489 ret += mcgen('''
1490 [%(max_index)s] = NULL,
1491};
1492''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001493 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001494 return ret
1495
Eric Blake437db252015-09-29 16:21:02 -06001496
Markus Armbrustere98859a2015-09-16 13:06:16 +02001497def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001498 # append automatically generated _MAX value
Markus Armbrustere98859a2015-09-16 13:06:16 +02001499 enum_values = values + ['MAX']
1500
1501 ret = mcgen('''
1502
1503typedef enum %(c_name)s {
1504''',
1505 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001506
1507 i = 0
1508 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001509 ret += mcgen('''
1510 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001511''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001512 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001513 i=i)
1514 i += 1
1515
Markus Armbrustere98859a2015-09-16 13:06:16 +02001516 ret += mcgen('''
1517} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001518''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001519 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001520
Markus Armbrustere98859a2015-09-16 13:06:16 +02001521 ret += mcgen('''
1522
1523extern const char *const %(c_name)s_lookup[];
1524''',
1525 c_name=c_name(name))
1526 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001527
Eric Blake437db252015-09-29 16:21:02 -06001528
Markus Armbruster03b43672015-09-16 13:06:20 +02001529def gen_params(arg_type, extra):
1530 if not arg_type:
1531 return extra
1532 assert not arg_type.variants
1533 ret = ''
1534 sep = ''
1535 for memb in arg_type.members:
1536 ret += sep
1537 sep = ', '
1538 if memb.optional:
1539 ret += 'bool has_%s, ' % c_name(memb.name)
1540 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1541 if extra:
1542 ret += sep + extra
1543 return ret
1544
Eric Blake1f353342015-09-29 16:21:13 -06001545
Eric Blake18bdbc32015-09-29 16:21:15 -06001546def gen_err_check(label='out', skiperr=False):
1547 if skiperr:
Eric Blake1f353342015-09-29 16:21:13 -06001548 return ''
1549 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001550 if (err) {
Eric Blake1f353342015-09-29 16:21:13 -06001551 goto %(label)s;
1552 }
1553''',
Eric Blake18bdbc32015-09-29 16:21:15 -06001554 label=label)
Eric Blake1f353342015-09-29 16:21:13 -06001555
1556
Eric Blake18bdbc32015-09-29 16:21:15 -06001557def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
Eric Blake82ca8e42015-09-29 16:21:14 -06001558 ret = ''
Eric Blake18bdbc32015-09-29 16:21:15 -06001559 if skiperr:
Eric Blake82ca8e42015-09-29 16:21:14 -06001560 errparg = 'NULL'
Eric Blake18bdbc32015-09-29 16:21:15 -06001561 else:
1562 errparg = '&err'
Eric Blake82ca8e42015-09-29 16:21:14 -06001563
1564 for memb in members:
1565 if memb.optional:
1566 ret += mcgen('''
1567 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1568''',
1569 prefix=prefix, c_name=c_name(memb.name),
1570 name=memb.name, errp=errparg)
Eric Blake18bdbc32015-09-29 16:21:15 -06001571 ret += gen_err_check(skiperr=skiperr)
Eric Blake82ca8e42015-09-29 16:21:14 -06001572 ret += mcgen('''
1573 if (%(prefix)shas_%(c_name)s) {
1574''',
1575 prefix=prefix, c_name=c_name(memb.name))
1576 push_indent()
1577
1578 # Ugly: sometimes we need to cast away const
1579 if need_cast and memb.type.name == 'str':
1580 cast = '(char **)'
1581 else:
1582 cast = ''
1583
1584 ret += mcgen('''
1585 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1586''',
1587 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1588 c_name=c_name(memb.name), name=memb.name,
1589 errp=errparg)
Eric Blake18bdbc32015-09-29 16:21:15 -06001590 ret += gen_err_check(skiperr=skiperr)
Eric Blake82ca8e42015-09-29 16:21:14 -06001591
1592 if memb.optional:
1593 pop_indent()
1594 ret += mcgen('''
1595 }
1596''')
1597 return ret
1598
1599
Markus Armbruster00e4b282015-06-10 10:04:36 +02001600#
1601# Common command line parsing
1602#
1603
Eric Blake437db252015-09-29 16:21:02 -06001604
1605def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001606
1607 try:
1608 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001609 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001610 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001611 "output-dir="] + extra_long_options)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001612 except getopt.GetoptError, err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001613 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001614 sys.exit(1)
1615
1616 output_dir = ""
1617 prefix = ""
1618 do_c = False
1619 do_h = False
1620 extra_opts = []
1621
1622 for oa in opts:
1623 o, a = oa
1624 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001625 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1626 if match.end() != len(a):
1627 print >>sys.stderr, \
1628 "%s: 'funny character '%s' in argument of --prefix" \
1629 % (sys.argv[0], a[match.end()])
1630 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001631 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001632 elif o in ("-o", "--output-dir"):
1633 output_dir = a + "/"
1634 elif o in ("-c", "--source"):
1635 do_c = True
1636 elif o in ("-h", "--header"):
1637 do_h = True
1638 else:
1639 extra_opts.append(oa)
1640
1641 if not do_c and not do_h:
1642 do_c = True
1643 do_h = True
1644
Markus Armbruster16d80f62015-04-02 13:32:16 +02001645 if len(args) != 1:
1646 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001647 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001648 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001649
Markus Armbruster54414042015-06-09 16:22:45 +02001650 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001651
Markus Armbruster00e4b282015-06-10 10:04:36 +02001652#
1653# Generate output files with boilerplate
1654#
1655
Eric Blake437db252015-09-29 16:21:02 -06001656
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001657def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1658 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001659 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001660 c_file = output_dir + prefix + c_file
1661 h_file = output_dir + prefix + h_file
1662
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001663 if output_dir:
1664 try:
1665 os.makedirs(output_dir)
1666 except os.error, e:
1667 if e.errno != errno.EEXIST:
1668 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001669
1670 def maybe_open(really, name, opt):
1671 if really:
1672 return open(name, opt)
1673 else:
1674 import StringIO
1675 return StringIO.StringIO()
1676
1677 fdef = maybe_open(do_c, c_file, 'w')
1678 fdecl = maybe_open(do_h, h_file, 'w')
1679
1680 fdef.write(mcgen('''
1681/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1682%(comment)s
1683''',
Eric Blake437db252015-09-29 16:21:02 -06001684 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001685
1686 fdecl.write(mcgen('''
1687/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1688%(comment)s
1689#ifndef %(guard)s
1690#define %(guard)s
1691
1692''',
Eric Blake437db252015-09-29 16:21:02 -06001693 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001694
1695 return (fdef, fdecl)
1696
Eric Blake437db252015-09-29 16:21:02 -06001697
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001698def close_output(fdef, fdecl):
1699 fdecl.write('''
1700#endif
1701''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001702 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001703 fdef.close()