blob: 7e6c396a1d0cde81116c3e28713e8af70be7a6f4 [file] [log] [blame]
Michael Roth0f923be2011-07-19 14:50:39 -05001#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
Eric Blakefe2a9302015-05-04 09:05:02 -06005# Copyright (c) 2013-2015 Red Hat Inc.
Michael Roth0f923be2011-07-19 14:50:39 -05006#
7# Authors:
8# Anthony Liguori <aliguori@us.ibm.com>
Markus Armbrusterc7a3f252013-07-27 17:41:55 +02009# Markus Armbruster <armbru@redhat.com>
Michael Roth0f923be2011-07-19 14:50:39 -050010#
Markus Armbruster678e48a2014-03-01 08:40:34 +010011# This work is licensed under the terms of the GNU GPL, version 2.
12# See the COPYING file in the top-level directory.
Michael Roth0f923be2011-07-19 14:50:39 -050013
Lluís Vilanovaa719a272014-05-07 20:46:15 +020014import re
Michael Roth0f923be2011-07-19 14:50:39 -050015from ordereddict import OrderedDict
Markus Armbruster12f8e1b2015-04-02 14:46:39 +020016import errno
Markus Armbruster2114f5a2015-04-02 13:12:21 +020017import getopt
Lluís Vilanova33aaad52014-05-02 15:52:35 +020018import os
Markus Armbruster2caba362013-07-27 17:41:56 +020019import sys
Markus Armbruster47299262015-05-14 06:50:47 -060020import string
Michael Roth0f923be2011-07-19 14:50:39 -050021
Eric Blakeb52c4b92015-05-04 09:05:00 -060022builtin_types = {
Kevin Wolf69dd62d2013-07-08 16:14:21 +020023 'str': 'QTYPE_QSTRING',
24 'int': 'QTYPE_QINT',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
27 'int8': 'QTYPE_QINT',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
Eric Blakecb17f792015-05-04 09:05:01 -060035 'size': 'QTYPE_QINT',
Eric Blake1310a3d2015-12-01 22:20:46 -070036 'any': None, # any QType possible, actually
Eric Blake7264f5c2015-12-01 22:20:47 -070037 'QType': 'QTYPE_QSTRING',
Kevin Wolf69dd62d2013-07-08 16:14:21 +020038}
39
Eric Blake10d4d992015-05-04 09:05:23 -060040# Whitelist of commands allowed to return a non-dictionary
41returns_whitelist = [
42 # From QMP:
43 'human-monitor-command',
Markus Armbruster6eb39372015-09-16 13:06:25 +020044 'qom-get',
Eric Blake10d4d992015-05-04 09:05:23 -060045 'query-migrate-cache-size',
46 'query-tpm-models',
47 'query-tpm-types',
48 'ringbuf-read',
49
50 # From QGA:
51 'guest-file-open',
52 'guest-fsfreeze-freeze',
53 'guest-fsfreeze-freeze-list',
54 'guest-fsfreeze-status',
55 'guest-fsfreeze-thaw',
56 'guest-get-time',
57 'guest-set-vcpus',
58 'guest-sync',
59 'guest-sync-delimited',
Eric Blake10d4d992015-05-04 09:05:23 -060060]
61
Eric Blake4dc2e692015-05-04 09:05:17 -060062enum_types = []
63struct_types = []
64union_types = []
65events = []
66all_names = {}
67
Markus Armbruster00e4b282015-06-10 10:04:36 +020068#
69# Parsing the schema into expressions
70#
71
Eric Blake437db252015-09-29 16:21:02 -060072
Lluís Vilanovaa719a272014-05-07 20:46:15 +020073def error_path(parent):
74 res = ""
75 while parent:
76 res = ("In file included from %s:%d:\n" % (parent['file'],
77 parent['line'])) + res
78 parent = parent['parent']
79 return res
80
Eric Blake437db252015-09-29 16:21:02 -060081
Markus Armbruster2caba362013-07-27 17:41:56 +020082class QAPISchemaError(Exception):
83 def __init__(self, schema, msg):
Eric Blake59b00542015-09-29 16:21:01 -060084 Exception.__init__(self)
Markus Armbruster54414042015-06-09 16:22:45 +020085 self.fname = schema.fname
Markus Armbruster2caba362013-07-27 17:41:56 +020086 self.msg = msg
Wenchao Xia515b9432014-03-04 18:44:33 -080087 self.col = 1
88 self.line = schema.line
89 for ch in schema.src[schema.line_pos:schema.pos]:
90 if ch == '\t':
Markus Armbruster2caba362013-07-27 17:41:56 +020091 self.col = (self.col + 7) % 8 + 1
92 else:
93 self.col += 1
Markus Armbruster54414042015-06-09 16:22:45 +020094 self.info = schema.incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +020095
96 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +020097 return error_path(self.info) + \
Markus Armbruster54414042015-06-09 16:22:45 +020098 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
Markus Armbruster2caba362013-07-27 17:41:56 +020099
Eric Blake437db252015-09-29 16:21:02 -0600100
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800101class QAPIExprError(Exception):
102 def __init__(self, expr_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -0600103 Exception.__init__(self)
Eric Blake7618b912015-10-12 22:22:22 -0600104 assert expr_info
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200105 self.info = expr_info
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800106 self.msg = msg
107
108 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200109 return error_path(self.info['parent']) + \
110 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800111
Eric Blake437db252015-09-29 16:21:02 -0600112
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200113class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500114
Eric Blake437db252015-09-29 16:21:02 -0600115 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200116 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200117 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200118 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200119 previously_included.append(abs_fname)
120 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200121 self.src = fp.read()
122 if self.src == '' or self.src[-1] != '\n':
123 self.src += '\n'
124 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800125 self.line = 1
126 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200127 self.exprs = []
128 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500129
Eric Blake437db252015-09-29 16:21:02 -0600130 while self.tok is not None:
Markus Armbruster54414042015-06-09 16:22:45 +0200131 expr_info = {'file': fname, 'line': self.line,
132 'parent': self.incl_info}
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200133 expr = self.get_expr(False)
134 if isinstance(expr, dict) and "include" in expr:
135 if len(expr) != 1:
Eric Blake437db252015-09-29 16:21:02 -0600136 raise QAPIExprError(expr_info,
137 "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200138 include = expr["include"]
139 if not isinstance(include, str):
140 raise QAPIExprError(expr_info,
Eric Blake7408fb62015-09-29 16:21:00 -0600141 "Value of 'include' must be a string")
Markus Armbruster54414042015-06-09 16:22:45 +0200142 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
143 include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200144 # catch inclusion cycle
145 inf = expr_info
146 while inf:
147 if incl_abs_fname == os.path.abspath(inf['file']):
Stefan Hajnoczi7ac9a9d2014-08-27 12:08:51 +0100148 raise QAPIExprError(expr_info, "Inclusion loop for %s"
149 % include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200150 inf = inf['parent']
Benoît Canet24fd8482014-05-16 12:51:56 +0200151 # skip multiple include of the same file
Markus Armbruster54414042015-06-09 16:22:45 +0200152 if incl_abs_fname in previously_included:
Benoît Canet24fd8482014-05-16 12:51:56 +0200153 continue
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200154 try:
Markus Armbruster54414042015-06-09 16:22:45 +0200155 fobj = open(incl_abs_fname, 'r')
Luiz Capitulino34788812014-05-20 13:50:19 -0400156 except IOError, e:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200157 raise QAPIExprError(expr_info,
158 '%s: %s' % (e.strerror, include))
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200159 exprs_include = QAPISchemaParser(fobj, previously_included,
160 expr_info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200161 self.exprs.extend(exprs_include.exprs)
162 else:
163 expr_elem = {'expr': expr,
164 'info': expr_info}
165 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500166
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200167 def accept(self):
168 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200169 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200170 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200171 self.cursor += 1
172 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500173
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200174 if self.tok == '#':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200175 self.cursor = self.src.find('\n', self.cursor)
Eric Blake8712fa52015-10-26 16:34:41 -0600176 elif self.tok in "{}:,[]":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200177 return
178 elif self.tok == "'":
179 string = ''
180 esc = False
181 while True:
182 ch = self.src[self.cursor]
183 self.cursor += 1
184 if ch == '\n':
Markus Armbruster2caba362013-07-27 17:41:56 +0200185 raise QAPISchemaError(self,
186 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200187 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600188 if ch == 'b':
189 string += '\b'
190 elif ch == 'f':
191 string += '\f'
192 elif ch == 'n':
193 string += '\n'
194 elif ch == 'r':
195 string += '\r'
196 elif ch == 't':
197 string += '\t'
198 elif ch == 'u':
199 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600200 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600201 ch = self.src[self.cursor]
202 self.cursor += 1
203 if ch not in "0123456789abcdefABCDEF":
204 raise QAPISchemaError(self,
205 '\\u escape needs 4 '
206 'hex digits')
207 value = (value << 4) + int(ch, 16)
208 # If Python 2 and 3 didn't disagree so much on
209 # how to handle Unicode, then we could allow
210 # Unicode string defaults. But most of QAPI is
211 # ASCII-only, so we aren't losing much for now.
212 if not value or value > 0x7f:
213 raise QAPISchemaError(self,
214 'For now, \\u escape '
215 'only supports non-zero '
216 'values up to \\u007f')
217 string += chr(value)
218 elif ch in "\\/'\"":
219 string += ch
220 else:
221 raise QAPISchemaError(self,
Eric Blake437db252015-09-29 16:21:02 -0600222 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200223 esc = False
224 elif ch == "\\":
225 esc = True
226 elif ch == "'":
227 self.val = string
228 return
229 else:
230 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200231 elif self.src.startswith("true", self.pos):
232 self.val = True
233 self.cursor += 3
234 return
235 elif self.src.startswith("false", self.pos):
236 self.val = False
237 self.cursor += 4
238 return
239 elif self.src.startswith("null", self.pos):
240 self.val = None
241 self.cursor += 3
242 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200243 elif self.tok == '\n':
244 if self.cursor == len(self.src):
245 self.tok = None
246 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800247 self.line += 1
248 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200249 elif not self.tok.isspace():
250 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500251
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200252 def get_members(self):
253 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200254 if self.tok == '}':
255 self.accept()
256 return expr
257 if self.tok != "'":
258 raise QAPISchemaError(self, 'Expected string or "}"')
259 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200260 key = self.val
261 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200262 if self.tok != ':':
263 raise QAPISchemaError(self, 'Expected ":"')
264 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800265 if key in expr:
266 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200267 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200268 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200269 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200270 return expr
271 if self.tok != ',':
272 raise QAPISchemaError(self, 'Expected "," or "}"')
273 self.accept()
274 if self.tok != "'":
275 raise QAPISchemaError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500276
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200277 def get_values(self):
278 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200279 if self.tok == ']':
280 self.accept()
281 return expr
Eric Blake437db252015-09-29 16:21:02 -0600282 if self.tok not in "{['tfn":
Fam Zhenge53188a2015-05-04 09:05:18 -0600283 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
284 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200285 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200286 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200287 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200288 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200289 return expr
290 if self.tok != ',':
291 raise QAPISchemaError(self, 'Expected "," or "]"')
292 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500293
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200294 def get_expr(self, nested):
295 if self.tok != '{' and not nested:
296 raise QAPISchemaError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200297 if self.tok == '{':
298 self.accept()
299 expr = self.get_members()
300 elif self.tok == '[':
301 self.accept()
302 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600303 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200304 expr = self.val
305 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200306 else:
307 raise QAPISchemaError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200308 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200309
Markus Armbruster00e4b282015-06-10 10:04:36 +0200310#
311# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200312# TODO fold into QAPISchema
313# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200314#
315
Eric Blake437db252015-09-29 16:21:02 -0600316
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800317def find_base_fields(base):
318 base_struct_define = find_struct(base)
319 if not base_struct_define:
320 return None
321 return base_struct_define['data']
322
Eric Blake437db252015-09-29 16:21:02 -0600323
Eric Blake811d04f2015-05-04 09:05:10 -0600324# Return the qtype of an alternate branch, or None on error.
325def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600326 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600327 return builtin_types[qapi_type]
328 elif find_struct(qapi_type):
329 return "QTYPE_QDICT"
330 elif find_enum(qapi_type):
331 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600332 elif find_union(qapi_type):
333 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600334 return None
335
Eric Blake437db252015-09-29 16:21:02 -0600336
Wenchao Xiabceae762014-03-06 17:08:56 -0800337# Return the discriminator enum define if discriminator is specified as an
338# enum type, otherwise return None.
339def discriminator_find_enum_define(expr):
340 base = expr.get('base')
341 discriminator = expr.get('discriminator')
342
343 if not (discriminator and base):
344 return None
345
346 base_fields = find_base_fields(base)
347 if not base_fields:
348 return None
349
350 discriminator_type = base_fields.get(discriminator)
351 if not discriminator_type:
352 return None
353
354 return find_enum(discriminator_type)
355
Eric Blake437db252015-09-29 16:21:02 -0600356
Eric Blake59a92fe2015-11-18 01:52:56 -0700357# Names must be letters, numbers, -, and _. They must start with letter,
358# except for downstream extensions which must start with __RFQDN_.
359# Dots are only valid in the downstream extension prefix.
360valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
361 '[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
Eric Blake59a92fe2015-11-18 01:52:56 -0700380 if enum_member and membername[0].isdigit():
381 membername = 'D' + membername
Eric Blake9fb081e2015-10-26 16:34:44 -0600382 # Reserve the entire 'q_' namespace for c_name()
383 if not valid_name.match(membername) or \
384 c_name(membername, False).startswith('q_'):
Eric Blakec9e0a792015-05-04 09:05:22 -0600385 raise QAPIExprError(expr_info,
386 "%s uses invalid name '%s'" % (source, name))
387
Eric Blake437db252015-09-29 16:21:02 -0600388
389def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200390 global all_names
391 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200392 # FIXME should reject names that differ only in '_' vs. '.'
393 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200394 if name in all_names:
395 raise QAPIExprError(info,
396 "%s '%s' is already defined"
397 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600398 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200399 raise QAPIExprError(info,
Eric Blake255960d2015-10-26 16:34:43 -0600400 "%s '%s' should not end in '%s'"
401 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200402 all_names[name] = meta
403
Eric Blake437db252015-09-29 16:21:02 -0600404
Markus Armbruster00e4b282015-06-10 10:04:36 +0200405def add_struct(definition, info):
406 global struct_types
407 name = definition['struct']
408 add_name(name, info, 'struct')
409 struct_types.append(definition)
410
Eric Blake437db252015-09-29 16:21:02 -0600411
Markus Armbruster00e4b282015-06-10 10:04:36 +0200412def find_struct(name):
413 global struct_types
414 for struct in struct_types:
415 if struct['struct'] == name:
416 return struct
417 return None
418
Eric Blake437db252015-09-29 16:21:02 -0600419
Markus Armbruster00e4b282015-06-10 10:04:36 +0200420def add_union(definition, info):
421 global union_types
422 name = definition['union']
423 add_name(name, info, 'union')
424 union_types.append(definition)
425
Eric Blake437db252015-09-29 16:21:02 -0600426
Markus Armbruster00e4b282015-06-10 10:04:36 +0200427def find_union(name):
428 global union_types
429 for union in union_types:
430 if union['union'] == name:
431 return union
432 return None
433
Eric Blake437db252015-09-29 16:21:02 -0600434
435def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200436 global enum_types
437 add_name(name, info, 'enum', implicit)
438 enum_types.append({"enum_name": name, "enum_values": enum_values})
439
Eric Blake437db252015-09-29 16:21:02 -0600440
Markus Armbruster00e4b282015-06-10 10:04:36 +0200441def find_enum(name):
442 global enum_types
443 for enum in enum_types:
444 if enum['enum_name'] == name:
445 return enum
446 return None
447
Markus Armbruster00e4b282015-06-10 10:04:36 +0200448
Eric Blake437db252015-09-29 16:21:02 -0600449def is_enum(name):
450 return find_enum(name) is not None
451
452
453def check_type(expr_info, source, value, allow_array=False,
454 allow_dict=False, allow_optional=False,
455 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600456 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600457
458 if value is None:
459 return
460
Eric Blakedd883c62015-05-04 09:05:21 -0600461 # Check if array type for value is okay
462 if isinstance(value, list):
463 if not allow_array:
464 raise QAPIExprError(expr_info,
465 "%s cannot be an array" % source)
466 if len(value) != 1 or not isinstance(value[0], str):
467 raise QAPIExprError(expr_info,
468 "%s: array type must contain single type name"
469 % source)
470 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600471
472 # Check if type name for value is okay
473 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600474 if value not in all_names:
Eric Blakedd883c62015-05-04 09:05:21 -0600475 raise QAPIExprError(expr_info,
476 "%s uses unknown type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200477 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600478 if not all_names[value] in allow_metas:
479 raise QAPIExprError(expr_info,
480 "%s cannot use %s type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200481 % (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600482 return
483
Eric Blakedd883c62015-05-04 09:05:21 -0600484 if not allow_dict:
485 raise QAPIExprError(expr_info,
486 "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200487
488 if not isinstance(value, OrderedDict):
489 raise QAPIExprError(expr_info,
490 "%s should be a dictionary or type name" % source)
491
492 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600493 for (key, arg) in value.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600494 check_name(expr_info, "Member of %s" % source, key,
495 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600496 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Eric Blake9fb081e2015-10-26 16:34:44 -0600497 raise QAPIExprError(expr_info,
498 "Member of %s uses reserved name '%s'"
499 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600500 # Todo: allow dictionaries to represent default values of
501 # an optional argument.
Eric Blakedd883c62015-05-04 09:05:21 -0600502 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200503 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600504 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600505 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600506
Eric Blake437db252015-09-29 16:21:02 -0600507
508def check_member_clash(expr_info, base_name, data, source=""):
Eric Blakeff55d722015-05-04 09:05:37 -0600509 base = find_struct(base_name)
510 assert base
511 base_members = base['data']
512 for key in data.keys():
513 if key.startswith('*'):
514 key = key[1:]
515 if key in base_members or "*" + key in base_members:
516 raise QAPIExprError(expr_info,
517 "Member name '%s'%s clashes with base '%s'"
518 % (key, source, base_name))
519 if base.get('base'):
520 check_member_clash(expr_info, base['base'], data, source)
521
Eric Blake437db252015-09-29 16:21:02 -0600522
Eric Blakedd883c62015-05-04 09:05:21 -0600523def check_command(expr, expr_info):
524 name = expr['command']
Eric Blake2cbf0992015-05-04 09:05:24 -0600525
Eric Blakedd883c62015-05-04 09:05:21 -0600526 check_type(expr_info, "'data' for command '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600527 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200528 allow_metas=['struct'])
Eric Blake10d4d992015-05-04 09:05:23 -0600529 returns_meta = ['union', 'struct']
530 if name in returns_whitelist:
531 returns_meta += ['built-in', 'alternate', 'enum']
Eric Blakedd883c62015-05-04 09:05:21 -0600532 check_type(expr_info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200533 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200534 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600535
Eric Blake437db252015-09-29 16:21:02 -0600536
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200537def check_event(expr, expr_info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600538 global events
539 name = expr['event']
Eric Blake4dc2e692015-05-04 09:05:17 -0600540
Eric Blake4dc2e692015-05-04 09:05:17 -0600541 events.append(name)
Eric Blakedd883c62015-05-04 09:05:21 -0600542 check_type(expr_info, "'data' for event '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600543 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster315932b2015-07-01 10:12:24 +0200544 allow_metas=['struct'])
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200545
Eric Blake437db252015-09-29 16:21:02 -0600546
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800547def check_union(expr, expr_info):
548 name = expr['union']
549 base = expr.get('base')
550 discriminator = expr.get('discriminator')
551 members = expr['data']
Eric Blake04e06392015-11-18 01:52:58 -0700552 values = {}
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800553
Eric Blake811d04f2015-05-04 09:05:10 -0600554 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600555
556 # With no discriminator it is a simple union.
557 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600558 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600559 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600560 if base is not None:
561 raise QAPIExprError(expr_info,
Eric Blake811d04f2015-05-04 09:05:10 -0600562 "Simple union '%s' must not have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600563 % name)
564
565 # Else, it's a flat union.
566 else:
567 # The object must have a string member 'base'.
Eric Blake376863e2015-09-29 16:21:07 -0600568 check_type(expr_info, "'base' for union '%s'" % name,
569 base, allow_metas=['struct'])
570 if not base:
Eric Blake44bd1272015-05-04 09:05:08 -0600571 raise QAPIExprError(expr_info,
Eric Blake376863e2015-09-29 16:21:07 -0600572 "Flat union '%s' must have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600573 % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800574 base_fields = find_base_fields(base)
Eric Blake376863e2015-09-29 16:21:07 -0600575 assert base_fields
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800576
Eric Blakec9e0a792015-05-04 09:05:22 -0600577 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600578 # member of the base struct.
Eric Blakec9e0a792015-05-04 09:05:22 -0600579 check_name(expr_info, "Discriminator of flat union '%s'" % name,
580 discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800581 discriminator_type = base_fields.get(discriminator)
582 if not discriminator_type:
583 raise QAPIExprError(expr_info,
584 "Discriminator '%s' is not a member of base "
Eric Blakefd41dd42015-05-04 09:05:25 -0600585 "struct '%s'"
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800586 % (discriminator, base))
587 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600588 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800589 # Do not allow string discriminator
590 if not enum_define:
591 raise QAPIExprError(expr_info,
592 "Discriminator '%s' must be of enumeration "
593 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800594
595 # Check every branch
596 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600597 check_name(expr_info, "Member of union '%s'" % name, key)
598
Eric Blakedd883c62015-05-04 09:05:21 -0600599 # Each value must name a known type; furthermore, in flat unions,
Eric Blakeff55d722015-05-04 09:05:37 -0600600 # branches must be a struct with no overlapping member names
Eric Blakedd883c62015-05-04 09:05:21 -0600601 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200602 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakeff55d722015-05-04 09:05:37 -0600603 if base:
604 branch_struct = find_struct(value)
605 assert branch_struct
606 check_member_clash(expr_info, base, branch_struct['data'],
607 " of branch '%s'" % key)
Eric Blakedd883c62015-05-04 09:05:21 -0600608
Eric Blake44bd1272015-05-04 09:05:08 -0600609 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700610 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600611 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600612 if key not in enum_define['enum_values']:
Eric Blake44bd1272015-05-04 09:05:08 -0600613 raise QAPIExprError(expr_info,
614 "Discriminator value '%s' is not found in "
615 "enum '%s'" %
616 (key, enum_define["enum_name"]))
617
618 # Otherwise, check for conflicts in the generated enum
619 else:
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600620 c_key = camel_to_upper(key)
Eric Blake44bd1272015-05-04 09:05:08 -0600621 if c_key in values:
622 raise QAPIExprError(expr_info,
623 "Union '%s' member '%s' clashes with '%s'"
624 % (name, key, values[c_key]))
625 values[c_key] = key
626
Eric Blake437db252015-09-29 16:21:02 -0600627
Eric Blake811d04f2015-05-04 09:05:10 -0600628def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600629 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600630 members = expr['data']
Eric Blake04e06392015-11-18 01:52:58 -0700631 values = {}
Eric Blake811d04f2015-05-04 09:05:10 -0600632 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600633
Eric Blake811d04f2015-05-04 09:05:10 -0600634 # Check every branch
635 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600636 check_name(expr_info, "Member of alternate '%s'" % name, key)
637
Eric Blake0426d532015-12-01 22:20:48 -0700638 # Check for conflicts in the branch names
639 c_key = c_name(key)
Eric Blake811d04f2015-05-04 09:05:10 -0600640 if c_key in values:
641 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600642 "Alternate '%s' member '%s' clashes with '%s'"
643 % (name, key, values[c_key]))
Eric Blake811d04f2015-05-04 09:05:10 -0600644 values[c_key] = key
645
646 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600647 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
648 value,
649 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600650 qtype = find_alternate_member_qtype(value)
Eric Blakedd883c62015-05-04 09:05:21 -0600651 assert qtype
Eric Blake811d04f2015-05-04 09:05:10 -0600652 if qtype in types_seen:
653 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600654 "Alternate '%s' member '%s' can't "
Eric Blake811d04f2015-05-04 09:05:10 -0600655 "be distinguished from member '%s'"
656 % (name, key, types_seen[qtype]))
657 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800658
Eric Blake437db252015-09-29 16:21:02 -0600659
Eric Blakecf393592015-05-04 09:05:04 -0600660def check_enum(expr, expr_info):
661 name = expr['enum']
662 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100663 prefix = expr.get('prefix')
Eric Blake04e06392015-11-18 01:52:58 -0700664 values = {}
Eric Blakecf393592015-05-04 09:05:04 -0600665
666 if not isinstance(members, list):
667 raise QAPIExprError(expr_info,
668 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100669 if prefix is not None and not isinstance(prefix, str):
670 raise QAPIExprError(expr_info,
671 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600672 for member in members:
Eric Blake437db252015-09-29 16:21:02 -0600673 check_name(expr_info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600674 enum_member=True)
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600675 key = camel_to_upper(member)
Eric Blakecf393592015-05-04 09:05:04 -0600676 if key in values:
677 raise QAPIExprError(expr_info,
678 "Enum '%s' member '%s' clashes with '%s'"
679 % (name, member, values[key]))
680 values[key] = member
681
Eric Blake437db252015-09-29 16:21:02 -0600682
Eric Blakedd883c62015-05-04 09:05:21 -0600683def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600684 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600685 members = expr['data']
686
Eric Blakefd41dd42015-05-04 09:05:25 -0600687 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600688 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600689 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600690 allow_metas=['struct'])
Eric Blakeff55d722015-05-04 09:05:37 -0600691 if expr.get('base'):
692 check_member_clash(expr_info, expr['base'], expr['data'])
Eric Blakedd883c62015-05-04 09:05:21 -0600693
Eric Blake437db252015-09-29 16:21:02 -0600694
Eric Blake0545f6b2015-05-04 09:05:15 -0600695def check_keys(expr_elem, meta, required, optional=[]):
696 expr = expr_elem['expr']
697 info = expr_elem['info']
698 name = expr[meta]
699 if not isinstance(name, str):
700 raise QAPIExprError(info,
701 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600702 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600703 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600704 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600705 raise QAPIExprError(info,
706 "Unknown key '%s' in %s '%s'"
707 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600708 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600709 raise QAPIExprError(info,
710 "'%s' of %s '%s' should only use false value"
711 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600712 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600713 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600714 raise QAPIExprError(info,
715 "Key '%s' is missing from %s '%s'"
716 % (key, meta, name))
717
Eric Blake437db252015-09-29 16:21:02 -0600718
Markus Armbruster4d076d62015-06-10 08:55:21 +0200719def check_exprs(exprs):
720 global all_names
721
722 # Learn the types and check for valid expression keys
723 for builtin in builtin_types.keys():
724 all_names[builtin] = 'built-in'
725 for expr_elem in exprs:
726 expr = expr_elem['expr']
727 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600728 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100729 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200730 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600731 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200732 check_keys(expr_elem, 'union', ['data'],
733 ['base', 'discriminator'])
734 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600735 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200736 check_keys(expr_elem, 'alternate', ['data'])
737 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600738 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200739 check_keys(expr_elem, 'struct', ['data'], ['base'])
740 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600741 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200742 check_keys(expr_elem, 'command', [],
743 ['data', 'returns', 'gen', 'success-response'])
744 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600745 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200746 check_keys(expr_elem, 'event', [], ['data'])
747 add_name(expr['event'], info, 'event')
748 else:
749 raise QAPIExprError(expr_elem['info'],
750 "Expression is missing metatype")
751
752 # Try again for hidden UnionKind enum
753 for expr_elem in exprs:
754 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600755 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200756 if not discriminator_find_enum_define(expr):
757 add_enum('%sKind' % expr['union'], expr_elem['info'],
758 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600759 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200760 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
761 implicit=True)
762
763 # Validate that exprs make sense
764 for expr_elem in exprs:
765 expr = expr_elem['expr']
766 info = expr_elem['info']
767
Eric Blake437db252015-09-29 16:21:02 -0600768 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200769 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600770 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200771 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600772 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200773 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600774 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200775 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600776 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200777 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600778 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200779 check_event(expr, info)
780 else:
781 assert False, 'unexpected meta type'
782
Markus Armbrusterac882192015-09-16 13:06:05 +0200783 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600784
Markus Armbrusterac882192015-09-16 13:06:05 +0200785
786#
787# Schema compiler frontend
788#
789
790class QAPISchemaEntity(object):
791 def __init__(self, name, info):
792 assert isinstance(name, str)
793 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -0600794 # For explicitly defined entities, info points to the (explicit)
795 # definition. For builtins (and their arrays), info is None.
796 # For implicitly defined entities, info points to a place that
797 # triggered the implicit definition (there may be more than one
798 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +0200799 self.info = info
800
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200801 def c_name(self):
802 return c_name(self.name)
803
Markus Armbrusterac882192015-09-16 13:06:05 +0200804 def check(self, schema):
805 pass
806
Eric Blake49823c42015-10-12 22:22:27 -0600807 def is_implicit(self):
808 return not self.info
809
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200810 def visit(self, visitor):
811 pass
812
813
814class QAPISchemaVisitor(object):
815 def visit_begin(self, schema):
816 pass
817
818 def visit_end(self):
819 pass
820
Eric Blake25a0d9c2015-10-12 22:22:21 -0600821 def visit_needed(self, entity):
822 # Default to visiting everything
823 return True
824
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200825 def visit_builtin_type(self, name, info, json_type):
826 pass
827
828 def visit_enum_type(self, name, info, values, prefix):
829 pass
830
831 def visit_array_type(self, name, info, element_type):
832 pass
833
834 def visit_object_type(self, name, info, base, members, variants):
835 pass
836
Markus Armbruster39a18152015-09-16 13:06:28 +0200837 def visit_object_type_flat(self, name, info, members, variants):
838 pass
839
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200840 def visit_alternate_type(self, name, info, variants):
841 pass
842
843 def visit_command(self, name, info, arg_type, ret_type,
844 gen, success_response):
845 pass
846
847 def visit_event(self, name, info, arg_type):
848 pass
849
Markus Armbrusterac882192015-09-16 13:06:05 +0200850
851class QAPISchemaType(QAPISchemaEntity):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200852 def c_type(self, is_param=False):
853 return c_name(self.name) + pointer_suffix
854
855 def c_null(self):
856 return 'NULL'
857
858 def json_type(self):
859 pass
860
861 def alternate_qtype(self):
862 json2qtype = {
863 'string': 'QTYPE_QSTRING',
864 'number': 'QTYPE_QFLOAT',
865 'int': 'QTYPE_QINT',
866 'boolean': 'QTYPE_QBOOL',
867 'object': 'QTYPE_QDICT'
868 }
869 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200870
871
872class QAPISchemaBuiltinType(QAPISchemaType):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200873 def __init__(self, name, json_type, c_type, c_null):
Markus Armbrusterac882192015-09-16 13:06:05 +0200874 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200875 assert not c_type or isinstance(c_type, str)
876 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
877 'value')
878 self._json_type_name = json_type
879 self._c_type_name = c_type
880 self._c_null_val = c_null
881
882 def c_name(self):
883 return self.name
884
885 def c_type(self, is_param=False):
886 if is_param and self.name == 'str':
887 return 'const ' + self._c_type_name
888 return self._c_type_name
889
890 def c_null(self):
891 return self._c_null_val
892
893 def json_type(self):
894 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200895
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200896 def visit(self, visitor):
897 visitor.visit_builtin_type(self.name, self.info, self.json_type())
898
Markus Armbrusterac882192015-09-16 13:06:05 +0200899
900class QAPISchemaEnumType(QAPISchemaType):
901 def __init__(self, name, info, values, prefix):
902 QAPISchemaType.__init__(self, name, info)
903 for v in values:
904 assert isinstance(v, str)
905 assert prefix is None or isinstance(prefix, str)
906 self.values = values
907 self.prefix = prefix
908
909 def check(self, schema):
910 assert len(set(self.values)) == len(self.values)
911
Eric Blake99df5282015-10-12 22:22:32 -0600912 def is_implicit(self):
913 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -0600914 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -0600915
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200916 def c_type(self, is_param=False):
917 return c_name(self.name)
918
919 def c_null(self):
Eric Blake7fb1cf12015-11-18 01:52:57 -0700920 return c_enum_const(self.name, (self.values + ['_MAX'])[0],
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200921 self.prefix)
922
923 def json_type(self):
924 return 'string'
925
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200926 def visit(self, visitor):
927 visitor.visit_enum_type(self.name, self.info,
928 self.values, self.prefix)
929
Markus Armbrusterac882192015-09-16 13:06:05 +0200930
931class QAPISchemaArrayType(QAPISchemaType):
932 def __init__(self, name, info, element_type):
933 QAPISchemaType.__init__(self, name, info)
934 assert isinstance(element_type, str)
935 self._element_type_name = element_type
936 self.element_type = None
937
938 def check(self, schema):
939 self.element_type = schema.lookup_type(self._element_type_name)
940 assert self.element_type
941
Eric Blake99df5282015-10-12 22:22:32 -0600942 def is_implicit(self):
943 return True
944
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200945 def json_type(self):
946 return 'array'
947
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200948 def visit(self, visitor):
949 visitor.visit_array_type(self.name, self.info, self.element_type)
950
Markus Armbrusterac882192015-09-16 13:06:05 +0200951
952class QAPISchemaObjectType(QAPISchemaType):
953 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -0700954 # struct has local_members, optional base, and no variants
955 # flat union has base, variants, and no local_members
956 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +0200957 QAPISchemaType.__init__(self, name, info)
958 assert base is None or isinstance(base, str)
959 for m in local_members:
960 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -0700961 m.set_owner(name)
962 if variants is not None:
963 assert isinstance(variants, QAPISchemaObjectTypeVariants)
964 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200965 self._base_name = base
966 self.base = None
967 self.local_members = local_members
968 self.variants = variants
969 self.members = None
970
971 def check(self, schema):
972 assert self.members is not False # not running in cycles
973 if self.members:
974 return
975 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -0700976 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +0200977 if self._base_name:
978 self.base = schema.lookup_type(self._base_name)
979 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +0200980 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700981 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200982 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -0700983 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700984 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700985 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +0200986 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -0700987 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700988 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -0700989 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200990
Eric Blake27b60ab2015-11-18 01:52:51 -0700991 # Check that the members of this type do not cause duplicate JSON fields,
992 # and update seen to track the members seen so far. Report any errors
993 # on behalf of info, which is not necessarily self.info
994 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -0700995 assert not self.variants # not implemented
996 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -0700997 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -0700998
Eric Blake99df5282015-10-12 22:22:32 -0600999 def is_implicit(self):
1000 # See QAPISchema._make_implicit_object_type()
1001 return self.name[0] == ':'
1002
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001003 def c_name(self):
Eric Blake49823c42015-10-12 22:22:27 -06001004 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001005 return QAPISchemaType.c_name(self)
1006
1007 def c_type(self, is_param=False):
Eric Blake49823c42015-10-12 22:22:27 -06001008 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001009 return QAPISchemaType.c_type(self)
1010
1011 def json_type(self):
1012 return 'object'
1013
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001014 def visit(self, visitor):
1015 visitor.visit_object_type(self.name, self.info,
1016 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001017 visitor.visit_object_type_flat(self.name, self.info,
1018 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001019
Markus Armbrusterac882192015-09-16 13:06:05 +02001020
1021class QAPISchemaObjectTypeMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001022 role = 'member'
1023
Markus Armbrusterac882192015-09-16 13:06:05 +02001024 def __init__(self, name, typ, optional):
1025 assert isinstance(name, str)
1026 assert isinstance(typ, str)
1027 assert isinstance(optional, bool)
1028 self.name = name
1029 self._type_name = typ
1030 self.type = None
1031 self.optional = optional
Eric Blake88d4ef82015-11-18 01:52:50 -07001032 self.owner = None
1033
1034 def set_owner(self, name):
1035 assert not self.owner
1036 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001037
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001038 def check(self, schema):
Eric Blake88d4ef82015-11-18 01:52:50 -07001039 assert self.owner
Markus Armbrusterac882192015-09-16 13:06:05 +02001040 self.type = schema.lookup_type(self._type_name)
1041 assert self.type
Markus Armbrusterac882192015-09-16 13:06:05 +02001042
Eric Blake27b60ab2015-11-18 01:52:51 -07001043 def check_clash(self, info, seen):
1044 cname = c_name(self.name)
1045 if cname in seen:
1046 raise QAPIExprError(info,
1047 "%s collides with %s"
1048 % (self.describe(), seen[cname].describe()))
1049 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001050
Eric Blake88d4ef82015-11-18 01:52:50 -07001051 def _pretty_owner(self):
1052 owner = self.owner
1053 if owner.startswith(':obj-'):
1054 # See QAPISchema._make_implicit_object_type() - reverse the
1055 # mapping there to create a nice human-readable description
1056 owner = owner[5:]
1057 if owner.endswith('-arg'):
1058 return '(parameter of %s)' % owner[:-4]
1059 else:
1060 assert owner.endswith('-wrapper')
1061 # Unreachable and not implemented
1062 assert False
1063 return '(%s of %s)' % (self.role, owner)
1064
1065 def describe(self):
1066 return "'%s' %s" % (self.name, self._pretty_owner())
1067
Markus Armbrusterac882192015-09-16 13:06:05 +02001068
1069class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001070 def __init__(self, tag_name, tag_member, variants):
1071 # Flat unions pass tag_name but not tag_member.
1072 # Simple unions and alternates pass tag_member but not tag_name.
1073 # After check(), tag_member is always set, and tag_name remains
1074 # a reliable witness of being used by a flat union.
1075 assert bool(tag_member) != bool(tag_name)
1076 assert (isinstance(tag_name, str) or
1077 isinstance(tag_member, QAPISchemaObjectTypeMember))
Markus Armbrusterac882192015-09-16 13:06:05 +02001078 for v in variants:
1079 assert isinstance(v, QAPISchemaObjectTypeVariant)
1080 self.tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001081 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001082 self.variants = variants
1083
Eric Blake88d4ef82015-11-18 01:52:50 -07001084 def set_owner(self, name):
1085 for v in self.variants:
1086 v.set_owner(name)
1087
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001088 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001089 if not self.tag_member: # flat union
Eric Blake27b60ab2015-11-18 01:52:51 -07001090 self.tag_member = seen[c_name(self.tag_name)]
1091 assert self.tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001092 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1093 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001094 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001095 # Union names must match enum values; alternate names are
1096 # checked separately. Use 'seen' to tell the two apart.
1097 if seen:
1098 assert v.name in self.tag_member.type.values
1099 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001100 v.type.check(schema)
1101
Eric Blake27b60ab2015-11-18 01:52:51 -07001102 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001103 for v in self.variants:
1104 # Reset seen map for each variant, since qapi names from one
1105 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001106 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001107 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001108
Eric Blake437db252015-09-29 16:21:02 -06001109
Markus Armbrusterac882192015-09-16 13:06:05 +02001110class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001111 role = 'branch'
1112
Markus Armbrusterac882192015-09-16 13:06:05 +02001113 def __init__(self, name, typ):
1114 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1115
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001116 # This function exists to support ugly simple union special cases
1117 # TODO get rid of them, and drop the function
1118 def simple_union_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001119 if (self.type.is_implicit() and
1120 isinstance(self.type, QAPISchemaObjectType)):
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001121 assert len(self.type.members) == 1
1122 assert not self.type.variants
1123 return self.type.members[0].type
1124 return None
1125
Markus Armbrusterac882192015-09-16 13:06:05 +02001126
1127class QAPISchemaAlternateType(QAPISchemaType):
1128 def __init__(self, name, info, variants):
1129 QAPISchemaType.__init__(self, name, info)
1130 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1131 assert not variants.tag_name
Eric Blake88d4ef82015-11-18 01:52:50 -07001132 variants.set_owner(name)
1133 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001134 self.variants = variants
1135
1136 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001137 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001138 # Not calling self.variants.check_clash(), because there's nothing
1139 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001140 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001141 # Alternate branch names have no relation to the tag enum values;
1142 # so we have to check for potential name collisions ourselves.
1143 seen = {}
1144 for v in self.variants.variants:
1145 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001146
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001147 def json_type(self):
1148 return 'value'
1149
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001150 def visit(self, visitor):
1151 visitor.visit_alternate_type(self.name, self.info, self.variants)
1152
Markus Armbrusterac882192015-09-16 13:06:05 +02001153
1154class QAPISchemaCommand(QAPISchemaEntity):
1155 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1156 QAPISchemaEntity.__init__(self, name, info)
1157 assert not arg_type or isinstance(arg_type, str)
1158 assert not ret_type or isinstance(ret_type, str)
1159 self._arg_type_name = arg_type
1160 self.arg_type = None
1161 self._ret_type_name = ret_type
1162 self.ret_type = None
1163 self.gen = gen
1164 self.success_response = success_response
1165
1166 def check(self, schema):
1167 if self._arg_type_name:
1168 self.arg_type = schema.lookup_type(self._arg_type_name)
1169 assert isinstance(self.arg_type, QAPISchemaObjectType)
1170 assert not self.arg_type.variants # not implemented
1171 if self._ret_type_name:
1172 self.ret_type = schema.lookup_type(self._ret_type_name)
1173 assert isinstance(self.ret_type, QAPISchemaType)
1174
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001175 def visit(self, visitor):
1176 visitor.visit_command(self.name, self.info,
1177 self.arg_type, self.ret_type,
1178 self.gen, self.success_response)
1179
Markus Armbrusterac882192015-09-16 13:06:05 +02001180
1181class QAPISchemaEvent(QAPISchemaEntity):
1182 def __init__(self, name, info, arg_type):
1183 QAPISchemaEntity.__init__(self, name, info)
1184 assert not arg_type or isinstance(arg_type, str)
1185 self._arg_type_name = arg_type
1186 self.arg_type = None
1187
1188 def check(self, schema):
1189 if self._arg_type_name:
1190 self.arg_type = schema.lookup_type(self._arg_type_name)
1191 assert isinstance(self.arg_type, QAPISchemaObjectType)
1192 assert not self.arg_type.variants # not implemented
1193
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001194 def visit(self, visitor):
1195 visitor.visit_event(self.name, self.info, self.arg_type)
1196
Markus Armbrusterac882192015-09-16 13:06:05 +02001197
1198class QAPISchema(object):
1199 def __init__(self, fname):
1200 try:
1201 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001202 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001203 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001204 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001205 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001206 self._def_exprs()
1207 self.check()
Markus Armbrusterac882192015-09-16 13:06:05 +02001208 except (QAPISchemaError, QAPIExprError), err:
1209 print >>sys.stderr, err
1210 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001211
Markus Armbrusterac882192015-09-16 13:06:05 +02001212 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001213 # Only the predefined types are allowed to not have info
1214 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001215 assert ent.name not in self._entity_dict
1216 self._entity_dict[ent.name] = ent
1217
1218 def lookup_entity(self, name, typ=None):
1219 ent = self._entity_dict.get(name)
1220 if typ and not isinstance(ent, typ):
1221 return None
1222 return ent
1223
1224 def lookup_type(self, name):
1225 return self.lookup_entity(name, QAPISchemaType)
1226
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001227 def _def_builtin_type(self, name, json_type, c_type, c_null):
1228 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1229 c_type, c_null))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001230 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1231 # qapi-types.h from a single .c, all arrays of builtins must be
1232 # declared in the first file whether or not they are used. Nicer
1233 # would be to use lazy instantiation, while figuring out how to
1234 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001235 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001236
1237 def _def_predefineds(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001238 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1239 ('number', 'number', 'double', '0'),
1240 ('int', 'int', 'int64_t', '0'),
1241 ('int8', 'int', 'int8_t', '0'),
1242 ('int16', 'int', 'int16_t', '0'),
1243 ('int32', 'int', 'int32_t', '0'),
1244 ('int64', 'int', 'int64_t', '0'),
1245 ('uint8', 'int', 'uint8_t', '0'),
1246 ('uint16', 'int', 'uint16_t', '0'),
1247 ('uint32', 'int', 'uint32_t', '0'),
1248 ('uint64', 'int', 'uint64_t', '0'),
1249 ('size', 'int', 'uint64_t', '0'),
1250 ('bool', 'boolean', 'bool', 'false'),
Markus Armbruster28770e02015-09-16 13:06:24 +02001251 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001252 self._def_builtin_type(*t)
Markus Armbruster39a18152015-09-16 13:06:28 +02001253 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1254 [], None)
1255 self._def_entity(self.the_empty_object_type)
Eric Blake7264f5c2015-12-01 22:20:47 -07001256 self._def_entity(QAPISchemaEnumType('QType', None,
1257 ['none', 'qnull', 'qint',
1258 'qstring', 'qdict', 'qlist',
1259 'qfloat', 'qbool'],
1260 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001261
Eric Blake99df5282015-10-12 22:22:32 -06001262 def _make_implicit_enum_type(self, name, info, values):
Eric Blake49823c42015-10-12 22:22:27 -06001263 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake99df5282015-10-12 22:22:32 -06001264 self._def_entity(QAPISchemaEnumType(name, info, values, None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001265 return name
1266
Eric Blake99df5282015-10-12 22:22:32 -06001267 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001268 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001269 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001270 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001271 return name
1272
Eric Blake99df5282015-10-12 22:22:32 -06001273 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001274 if not members:
1275 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001276 # See also QAPISchemaObjectTypeMember._pretty_owner()
Markus Armbrusterac882192015-09-16 13:06:05 +02001277 name = ':obj-%s-%s' % (name, role)
1278 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001279 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001280 members, None))
1281 return name
1282
1283 def _def_enum_type(self, expr, info):
1284 name = expr['enum']
1285 data = expr['data']
1286 prefix = expr.get('prefix')
1287 self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001288
Eric Blake99df5282015-10-12 22:22:32 -06001289 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001290 optional = False
1291 if name.startswith('*'):
1292 name = name[1:]
1293 optional = True
1294 if isinstance(typ, list):
1295 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001296 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001297 return QAPISchemaObjectTypeMember(name, typ, optional)
1298
Eric Blake99df5282015-10-12 22:22:32 -06001299 def _make_members(self, data, info):
1300 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001301 for (key, value) in data.iteritems()]
1302
1303 def _def_struct_type(self, expr, info):
1304 name = expr['struct']
1305 base = expr.get('base')
1306 data = expr['data']
1307 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001308 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001309 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001310
1311 def _make_variant(self, case, typ):
1312 return QAPISchemaObjectTypeVariant(case, typ)
1313
Eric Blake99df5282015-10-12 22:22:32 -06001314 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001315 if isinstance(typ, list):
1316 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001317 typ = self._make_array_type(typ[0], info)
1318 typ = self._make_implicit_object_type(
1319 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001320 return QAPISchemaObjectTypeVariant(case, typ)
1321
Markus Armbrusterac882192015-09-16 13:06:05 +02001322 def _def_union_type(self, expr, info):
1323 name = expr['union']
1324 data = expr['data']
1325 base = expr.get('base')
1326 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001327 tag_member = None
Markus Armbrusterac882192015-09-16 13:06:05 +02001328 if tag_name:
1329 variants = [self._make_variant(key, value)
1330 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001331 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001332 else:
Eric Blake99df5282015-10-12 22:22:32 -06001333 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001334 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001335 typ = self._make_implicit_enum_type(name, info,
1336 [v.name for v in variants])
1337 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001338 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001339 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001340 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001341 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001342 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001343 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001344
1345 def _def_alternate_type(self, expr, info):
1346 name = expr['alternate']
1347 data = expr['data']
1348 variants = [self._make_variant(key, value)
1349 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001350 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001351 self._def_entity(
1352 QAPISchemaAlternateType(name, info,
1353 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001354 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001355 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001356
1357 def _def_command(self, expr, info):
1358 name = expr['command']
1359 data = expr.get('data')
1360 rets = expr.get('returns')
1361 gen = expr.get('gen', True)
1362 success_response = expr.get('success-response', True)
1363 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001364 data = self._make_implicit_object_type(
1365 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001366 if isinstance(rets, list):
1367 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001368 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001369 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1370 success_response))
1371
1372 def _def_event(self, expr, info):
1373 name = expr['event']
1374 data = expr.get('data')
1375 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001376 data = self._make_implicit_object_type(
1377 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001378 self._def_entity(QAPISchemaEvent(name, info, data))
1379
1380 def _def_exprs(self):
1381 for expr_elem in self.exprs:
1382 expr = expr_elem['expr']
1383 info = expr_elem['info']
1384 if 'enum' in expr:
1385 self._def_enum_type(expr, info)
1386 elif 'struct' in expr:
1387 self._def_struct_type(expr, info)
1388 elif 'union' in expr:
1389 self._def_union_type(expr, info)
1390 elif 'alternate' in expr:
1391 self._def_alternate_type(expr, info)
1392 elif 'command' in expr:
1393 self._def_command(expr, info)
1394 elif 'event' in expr:
1395 self._def_event(expr, info)
1396 else:
1397 assert False
1398
1399 def check(self):
1400 for ent in self._entity_dict.values():
1401 ent.check(self)
1402
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001403 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001404 visitor.visit_begin(self)
1405 for (name, entity) in sorted(self._entity_dict.items()):
1406 if visitor.visit_needed(entity):
1407 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001408 visitor.visit_end()
1409
Markus Armbruster2caba362013-07-27 17:41:56 +02001410
Markus Armbruster00e4b282015-06-10 10:04:36 +02001411#
1412# Code generation helpers
1413#
1414
Michael Roth0f923be2011-07-19 14:50:39 -05001415def camel_case(name):
1416 new_name = ''
1417 first = True
1418 for ch in name:
1419 if ch in ['_', '-']:
1420 first = True
1421 elif first:
1422 new_name += ch.upper()
1423 first = False
1424 else:
1425 new_name += ch.lower()
1426 return new_name
1427
Eric Blake437db252015-09-29 16:21:02 -06001428
Markus Armbruster849bc532015-05-14 06:50:53 -06001429# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1430# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1431# ENUM24_Name -> ENUM24_NAME
1432def camel_to_upper(value):
1433 c_fun_str = c_name(value, False)
1434 if value.isupper():
1435 return c_fun_str
1436
1437 new_name = ''
1438 l = len(c_fun_str)
1439 for i in range(l):
1440 c = c_fun_str[i]
1441 # When c is upper and no "_" appears before, do more checks
1442 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001443 if i < l - 1 and c_fun_str[i + 1].islower():
1444 new_name += '_'
1445 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001446 new_name += '_'
1447 new_name += c
1448 return new_name.lstrip('_').upper()
1449
Eric Blake437db252015-09-29 16:21:02 -06001450
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001451def c_enum_const(type_name, const_name, prefix=None):
1452 if prefix is not None:
1453 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001454 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001455
Eric Blake18df5152015-05-14 06:50:48 -06001456c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001457
Eric Blake437db252015-09-29 16:21:02 -06001458
Eric Blakec6405b52015-05-14 06:50:55 -06001459# Map @name to a valid C identifier.
1460# If @protect, avoid returning certain ticklish identifiers (like
1461# C keywords) by prepending "q_".
1462#
1463# Used for converting 'name' from a 'name':'type' qapi definition
1464# into a generated struct member, as well as converting type names
1465# into substrings of a generated C function name.
1466# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1467# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001468def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001469 # ANSI X3J11/88-090, 3.1.1
1470 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001471 'default', 'do', 'double', 'else', 'enum', 'extern',
1472 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1473 'return', 'short', 'signed', 'sizeof', 'static',
1474 'struct', 'switch', 'typedef', 'union', 'unsigned',
1475 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001476 # ISO/IEC 9899:1999, 6.4.1
1477 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1478 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001479 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1480 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001481 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1482 # excluding _.*
1483 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001484 # C++ ISO/IEC 14882:2003 2.11
1485 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1486 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1487 'namespace', 'new', 'operator', 'private', 'protected',
1488 'public', 'reinterpret_cast', 'static_cast', 'template',
1489 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1490 'using', 'virtual', 'wchar_t',
1491 # alternative representations
1492 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1493 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001494 # namespace pollution:
Max Reitz8592a542013-12-20 19:28:18 +01001495 polluted_words = set(['unix', 'errno'])
Eric Blakec43567c2015-11-18 01:52:52 -07001496 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001497 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1498 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001499 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001500 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001501
Amos Kong05dfb262014-06-10 19:25:53 +08001502eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001503pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001504
Eric Blake437db252015-09-29 16:21:02 -06001505
Michael Roth0f923be2011-07-19 14:50:39 -05001506def genindent(count):
1507 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001508 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001509 ret += " "
1510 return ret
1511
1512indent_level = 0
1513
Eric Blake437db252015-09-29 16:21:02 -06001514
Michael Roth0f923be2011-07-19 14:50:39 -05001515def push_indent(indent_amount=4):
1516 global indent_level
1517 indent_level += indent_amount
1518
Eric Blake437db252015-09-29 16:21:02 -06001519
Michael Roth0f923be2011-07-19 14:50:39 -05001520def pop_indent(indent_amount=4):
1521 global indent_level
1522 indent_level -= indent_amount
1523
Eric Blake437db252015-09-29 16:21:02 -06001524
Markus Armbruster77e703b2015-06-24 19:27:32 +02001525# Generate @code with @kwds interpolated.
1526# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001527def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001528 raw = code % kwds
1529 if indent_level:
1530 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001531 # re.subn() lacks flags support before Python 2.7, use re.compile()
1532 raw = re.subn(re.compile("^.", re.MULTILINE),
1533 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001534 raw = raw[0]
1535 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001536
Eric Blake437db252015-09-29 16:21:02 -06001537
Michael Roth0f923be2011-07-19 14:50:39 -05001538def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001539 if code[0] == '\n':
1540 code = code[1:]
1541 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001542
Michael Roth0f923be2011-07-19 14:50:39 -05001543
1544def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001545 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001546
Eric Blake437db252015-09-29 16:21:02 -06001547
Michael Rothc0afa9c2013-05-10 17:46:00 -05001548def guardstart(name):
1549 return mcgen('''
1550
1551#ifndef %(name)s
1552#define %(name)s
1553
1554''',
1555 name=guardname(name))
1556
Eric Blake437db252015-09-29 16:21:02 -06001557
Michael Rothc0afa9c2013-05-10 17:46:00 -05001558def guardend(name):
1559 return mcgen('''
1560
1561#endif /* %(name)s */
1562
1563''',
1564 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001565
Eric Blake437db252015-09-29 16:21:02 -06001566
Markus Armbrustere98859a2015-09-16 13:06:16 +02001567def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001568 ret = mcgen('''
1569
Markus Armbrustere98859a2015-09-16 13:06:16 +02001570const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001571''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001572 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001573 for value in values:
1574 index = c_enum_const(name, value, prefix)
1575 ret += mcgen('''
1576 [%(index)s] = "%(value)s",
1577''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001578 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001579
Eric Blake7fb1cf12015-11-18 01:52:57 -07001580 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001581 ret += mcgen('''
1582 [%(max_index)s] = NULL,
1583};
1584''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001585 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001586 return ret
1587
Eric Blake437db252015-09-29 16:21:02 -06001588
Markus Armbrustere98859a2015-09-16 13:06:16 +02001589def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001590 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001591 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001592
1593 ret = mcgen('''
1594
1595typedef enum %(c_name)s {
1596''',
1597 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001598
1599 i = 0
1600 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001601 ret += mcgen('''
1602 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001603''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001604 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001605 i=i)
1606 i += 1
1607
Markus Armbrustere98859a2015-09-16 13:06:16 +02001608 ret += mcgen('''
1609} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001610''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001611 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001612
Markus Armbrustere98859a2015-09-16 13:06:16 +02001613 ret += mcgen('''
1614
1615extern const char *const %(c_name)s_lookup[];
1616''',
1617 c_name=c_name(name))
1618 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001619
Eric Blake437db252015-09-29 16:21:02 -06001620
Markus Armbruster03b43672015-09-16 13:06:20 +02001621def gen_params(arg_type, extra):
1622 if not arg_type:
1623 return extra
1624 assert not arg_type.variants
1625 ret = ''
1626 sep = ''
1627 for memb in arg_type.members:
1628 ret += sep
1629 sep = ', '
1630 if memb.optional:
1631 ret += 'bool has_%s, ' % c_name(memb.name)
1632 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1633 if extra:
1634 ret += sep + extra
1635 return ret
1636
Eric Blake1f353342015-09-29 16:21:13 -06001637
Eric Blake18bdbc32015-09-29 16:21:15 -06001638def gen_err_check(label='out', skiperr=False):
1639 if skiperr:
Eric Blake1f353342015-09-29 16:21:13 -06001640 return ''
1641 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001642 if (err) {
Eric Blake1f353342015-09-29 16:21:13 -06001643 goto %(label)s;
1644 }
1645''',
Eric Blake18bdbc32015-09-29 16:21:15 -06001646 label=label)
Eric Blake1f353342015-09-29 16:21:13 -06001647
1648
Eric Blake18bdbc32015-09-29 16:21:15 -06001649def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
Eric Blake82ca8e42015-09-29 16:21:14 -06001650 ret = ''
Eric Blake18bdbc32015-09-29 16:21:15 -06001651 if skiperr:
Eric Blake82ca8e42015-09-29 16:21:14 -06001652 errparg = 'NULL'
Eric Blake18bdbc32015-09-29 16:21:15 -06001653 else:
1654 errparg = '&err'
Eric Blake82ca8e42015-09-29 16:21:14 -06001655
1656 for memb in members:
1657 if memb.optional:
1658 ret += mcgen('''
1659 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1660''',
1661 prefix=prefix, c_name=c_name(memb.name),
1662 name=memb.name, errp=errparg)
Eric Blake18bdbc32015-09-29 16:21:15 -06001663 ret += gen_err_check(skiperr=skiperr)
Eric Blake82ca8e42015-09-29 16:21:14 -06001664 ret += mcgen('''
1665 if (%(prefix)shas_%(c_name)s) {
1666''',
1667 prefix=prefix, c_name=c_name(memb.name))
1668 push_indent()
1669
1670 # Ugly: sometimes we need to cast away const
1671 if need_cast and memb.type.name == 'str':
1672 cast = '(char **)'
1673 else:
1674 cast = ''
1675
1676 ret += mcgen('''
1677 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1678''',
1679 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1680 c_name=c_name(memb.name), name=memb.name,
1681 errp=errparg)
Eric Blake18bdbc32015-09-29 16:21:15 -06001682 ret += gen_err_check(skiperr=skiperr)
Eric Blake82ca8e42015-09-29 16:21:14 -06001683
1684 if memb.optional:
1685 pop_indent()
1686 ret += mcgen('''
1687 }
1688''')
1689 return ret
1690
1691
Markus Armbruster00e4b282015-06-10 10:04:36 +02001692#
1693# Common command line parsing
1694#
1695
Eric Blake437db252015-09-29 16:21:02 -06001696
1697def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001698
1699 try:
1700 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001701 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001702 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001703 "output-dir="] + extra_long_options)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001704 except getopt.GetoptError, err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001705 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001706 sys.exit(1)
1707
1708 output_dir = ""
1709 prefix = ""
1710 do_c = False
1711 do_h = False
1712 extra_opts = []
1713
1714 for oa in opts:
1715 o, a = oa
1716 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001717 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1718 if match.end() != len(a):
1719 print >>sys.stderr, \
1720 "%s: 'funny character '%s' in argument of --prefix" \
1721 % (sys.argv[0], a[match.end()])
1722 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001723 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001724 elif o in ("-o", "--output-dir"):
1725 output_dir = a + "/"
1726 elif o in ("-c", "--source"):
1727 do_c = True
1728 elif o in ("-h", "--header"):
1729 do_h = True
1730 else:
1731 extra_opts.append(oa)
1732
1733 if not do_c and not do_h:
1734 do_c = True
1735 do_h = True
1736
Markus Armbruster16d80f62015-04-02 13:32:16 +02001737 if len(args) != 1:
1738 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001739 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001740 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001741
Markus Armbruster54414042015-06-09 16:22:45 +02001742 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001743
Markus Armbruster00e4b282015-06-10 10:04:36 +02001744#
1745# Generate output files with boilerplate
1746#
1747
Eric Blake437db252015-09-29 16:21:02 -06001748
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001749def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1750 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001751 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001752 c_file = output_dir + prefix + c_file
1753 h_file = output_dir + prefix + h_file
1754
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001755 if output_dir:
1756 try:
1757 os.makedirs(output_dir)
1758 except os.error, e:
1759 if e.errno != errno.EEXIST:
1760 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001761
1762 def maybe_open(really, name, opt):
1763 if really:
1764 return open(name, opt)
1765 else:
1766 import StringIO
1767 return StringIO.StringIO()
1768
1769 fdef = maybe_open(do_c, c_file, 'w')
1770 fdecl = maybe_open(do_h, h_file, 'w')
1771
1772 fdef.write(mcgen('''
1773/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1774%(comment)s
1775''',
Eric Blake437db252015-09-29 16:21:02 -06001776 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001777
1778 fdecl.write(mcgen('''
1779/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1780%(comment)s
1781#ifndef %(guard)s
1782#define %(guard)s
1783
1784''',
Eric Blake437db252015-09-29 16:21:02 -06001785 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001786
1787 return (fdef, fdecl)
1788
Eric Blake437db252015-09-29 16:21:02 -06001789
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001790def close_output(fdef, fdecl):
1791 fdecl.write('''
1792#endif
1793''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001794 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001795 fdef.close()