blob: d2ce9b3b1900aff9e4faa92b9c78b3787beb7ac6 [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',
Eric Blake10d4d992015-05-04 09:05:23 -060059]
60
Eric Blake4dc2e692015-05-04 09:05:17 -060061enum_types = []
62struct_types = []
63union_types = []
64events = []
65all_names = {}
66
Markus Armbruster00e4b282015-06-10 10:04:36 +020067#
68# Parsing the schema into expressions
69#
70
Eric Blake437db252015-09-29 16:21:02 -060071
Lluís Vilanovaa719a272014-05-07 20:46:15 +020072def error_path(parent):
73 res = ""
74 while parent:
75 res = ("In file included from %s:%d:\n" % (parent['file'],
76 parent['line'])) + res
77 parent = parent['parent']
78 return res
79
Eric Blake437db252015-09-29 16:21:02 -060080
Markus Armbruster2caba362013-07-27 17:41:56 +020081class QAPISchemaError(Exception):
82 def __init__(self, schema, msg):
Eric Blake59b00542015-09-29 16:21:01 -060083 Exception.__init__(self)
Markus Armbruster54414042015-06-09 16:22:45 +020084 self.fname = schema.fname
Markus Armbruster2caba362013-07-27 17:41:56 +020085 self.msg = msg
Wenchao Xia515b9432014-03-04 18:44:33 -080086 self.col = 1
87 self.line = schema.line
88 for ch in schema.src[schema.line_pos:schema.pos]:
89 if ch == '\t':
Markus Armbruster2caba362013-07-27 17:41:56 +020090 self.col = (self.col + 7) % 8 + 1
91 else:
92 self.col += 1
Markus Armbruster54414042015-06-09 16:22:45 +020093 self.info = schema.incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +020094
95 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +020096 return error_path(self.info) + \
Markus Armbruster54414042015-06-09 16:22:45 +020097 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
Markus Armbruster2caba362013-07-27 17:41:56 +020098
Eric Blake437db252015-09-29 16:21:02 -060099
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800100class QAPIExprError(Exception):
101 def __init__(self, expr_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -0600102 Exception.__init__(self)
Eric Blake7618b912015-10-12 22:22:22 -0600103 assert expr_info
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200104 self.info = expr_info
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800105 self.msg = msg
106
107 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200108 return error_path(self.info['parent']) + \
109 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800110
Eric Blake437db252015-09-29 16:21:02 -0600111
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200112class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500113
Eric Blake437db252015-09-29 16:21:02 -0600114 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200115 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200116 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200117 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200118 previously_included.append(abs_fname)
119 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200120 self.src = fp.read()
121 if self.src == '' or self.src[-1] != '\n':
122 self.src += '\n'
123 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800124 self.line = 1
125 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200126 self.exprs = []
127 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500128
Eric Blake437db252015-09-29 16:21:02 -0600129 while self.tok is not None:
Markus Armbruster54414042015-06-09 16:22:45 +0200130 expr_info = {'file': fname, 'line': self.line,
131 'parent': self.incl_info}
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200132 expr = self.get_expr(False)
133 if isinstance(expr, dict) and "include" in expr:
134 if len(expr) != 1:
Eric Blake437db252015-09-29 16:21:02 -0600135 raise QAPIExprError(expr_info,
136 "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200137 include = expr["include"]
138 if not isinstance(include, str):
139 raise QAPIExprError(expr_info,
Eric Blake7408fb62015-09-29 16:21:00 -0600140 "Value of 'include' must be a string")
Markus Armbruster54414042015-06-09 16:22:45 +0200141 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
142 include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200143 # catch inclusion cycle
144 inf = expr_info
145 while inf:
146 if incl_abs_fname == os.path.abspath(inf['file']):
Stefan Hajnoczi7ac9a9d2014-08-27 12:08:51 +0100147 raise QAPIExprError(expr_info, "Inclusion loop for %s"
148 % include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200149 inf = inf['parent']
Benoît Canet24fd8482014-05-16 12:51:56 +0200150 # skip multiple include of the same file
Markus Armbruster54414042015-06-09 16:22:45 +0200151 if incl_abs_fname in previously_included:
Benoît Canet24fd8482014-05-16 12:51:56 +0200152 continue
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200153 try:
Markus Armbruster54414042015-06-09 16:22:45 +0200154 fobj = open(incl_abs_fname, 'r')
Luiz Capitulino34788812014-05-20 13:50:19 -0400155 except IOError, e:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200156 raise QAPIExprError(expr_info,
157 '%s: %s' % (e.strerror, include))
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200158 exprs_include = QAPISchemaParser(fobj, previously_included,
159 expr_info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200160 self.exprs.extend(exprs_include.exprs)
161 else:
162 expr_elem = {'expr': expr,
163 'info': expr_info}
164 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500165
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200166 def accept(self):
167 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200168 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200169 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200170 self.cursor += 1
171 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500172
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200173 if self.tok == '#':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200174 self.cursor = self.src.find('\n', self.cursor)
Eric Blake8712fa52015-10-26 16:34:41 -0600175 elif self.tok in "{}:,[]":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200176 return
177 elif self.tok == "'":
178 string = ''
179 esc = False
180 while True:
181 ch = self.src[self.cursor]
182 self.cursor += 1
183 if ch == '\n':
Markus Armbruster2caba362013-07-27 17:41:56 +0200184 raise QAPISchemaError(self,
185 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200186 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600187 if ch == 'b':
188 string += '\b'
189 elif ch == 'f':
190 string += '\f'
191 elif ch == 'n':
192 string += '\n'
193 elif ch == 'r':
194 string += '\r'
195 elif ch == 't':
196 string += '\t'
197 elif ch == 'u':
198 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600199 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600200 ch = self.src[self.cursor]
201 self.cursor += 1
202 if ch not in "0123456789abcdefABCDEF":
203 raise QAPISchemaError(self,
204 '\\u escape needs 4 '
205 'hex digits')
206 value = (value << 4) + int(ch, 16)
207 # If Python 2 and 3 didn't disagree so much on
208 # how to handle Unicode, then we could allow
209 # Unicode string defaults. But most of QAPI is
210 # ASCII-only, so we aren't losing much for now.
211 if not value or value > 0x7f:
212 raise QAPISchemaError(self,
213 'For now, \\u escape '
214 'only supports non-zero '
215 'values up to \\u007f')
216 string += chr(value)
217 elif ch in "\\/'\"":
218 string += ch
219 else:
220 raise QAPISchemaError(self,
Eric Blake437db252015-09-29 16:21:02 -0600221 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200222 esc = False
223 elif ch == "\\":
224 esc = True
225 elif ch == "'":
226 self.val = string
227 return
228 else:
229 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200230 elif self.src.startswith("true", self.pos):
231 self.val = True
232 self.cursor += 3
233 return
234 elif self.src.startswith("false", self.pos):
235 self.val = False
236 self.cursor += 4
237 return
238 elif self.src.startswith("null", self.pos):
239 self.val = None
240 self.cursor += 3
241 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200242 elif self.tok == '\n':
243 if self.cursor == len(self.src):
244 self.tok = None
245 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800246 self.line += 1
247 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200248 elif not self.tok.isspace():
249 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500250
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200251 def get_members(self):
252 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200253 if self.tok == '}':
254 self.accept()
255 return expr
256 if self.tok != "'":
257 raise QAPISchemaError(self, 'Expected string or "}"')
258 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200259 key = self.val
260 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200261 if self.tok != ':':
262 raise QAPISchemaError(self, 'Expected ":"')
263 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800264 if key in expr:
265 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200266 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200267 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200268 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200269 return expr
270 if self.tok != ',':
271 raise QAPISchemaError(self, 'Expected "," or "}"')
272 self.accept()
273 if self.tok != "'":
274 raise QAPISchemaError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500275
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200276 def get_values(self):
277 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200278 if self.tok == ']':
279 self.accept()
280 return expr
Eric Blake437db252015-09-29 16:21:02 -0600281 if self.tok not in "{['tfn":
Fam Zhenge53188a2015-05-04 09:05:18 -0600282 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
283 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200284 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200285 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200286 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200287 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200288 return expr
289 if self.tok != ',':
290 raise QAPISchemaError(self, 'Expected "," or "]"')
291 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500292
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200293 def get_expr(self, nested):
294 if self.tok != '{' and not nested:
295 raise QAPISchemaError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200296 if self.tok == '{':
297 self.accept()
298 expr = self.get_members()
299 elif self.tok == '[':
300 self.accept()
301 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600302 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200303 expr = self.val
304 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200305 else:
306 raise QAPISchemaError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200307 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200308
Markus Armbruster00e4b282015-06-10 10:04:36 +0200309#
310# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200311# TODO fold into QAPISchema
312# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200313#
314
Eric Blake437db252015-09-29 16:21:02 -0600315
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800316def find_base_fields(base):
317 base_struct_define = find_struct(base)
318 if not base_struct_define:
319 return None
320 return base_struct_define['data']
321
Eric Blake437db252015-09-29 16:21:02 -0600322
Eric Blake811d04f2015-05-04 09:05:10 -0600323# Return the qtype of an alternate branch, or None on error.
324def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600325 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600326 return builtin_types[qapi_type]
327 elif find_struct(qapi_type):
328 return "QTYPE_QDICT"
329 elif find_enum(qapi_type):
330 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600331 elif find_union(qapi_type):
332 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600333 return None
334
Eric Blake437db252015-09-29 16:21:02 -0600335
Wenchao Xiabceae762014-03-06 17:08:56 -0800336# Return the discriminator enum define if discriminator is specified as an
337# enum type, otherwise return None.
338def discriminator_find_enum_define(expr):
339 base = expr.get('base')
340 discriminator = expr.get('discriminator')
341
342 if not (discriminator and base):
343 return None
344
345 base_fields = find_base_fields(base)
346 if not base_fields:
347 return None
348
349 discriminator_type = base_fields.get(discriminator)
350 if not discriminator_type:
351 return None
352
353 return find_enum(discriminator_type)
354
Eric Blake437db252015-09-29 16:21:02 -0600355
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200356# FIXME should enforce "other than downstream extensions [...], all
357# names should begin with a letter".
Eric Blakec9e0a792015-05-04 09:05:22 -0600358valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600359
360
361def check_name(expr_info, source, name, allow_optional=False,
362 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600363 global valid_name
364 membername = name
365
366 if not isinstance(name, str):
367 raise QAPIExprError(expr_info,
368 "%s requires a string name" % source)
369 if name.startswith('*'):
370 membername = name[1:]
371 if not allow_optional:
372 raise QAPIExprError(expr_info,
373 "%s does not allow optional name '%s'"
374 % (source, name))
375 # Enum members can start with a digit, because the generated C
376 # code always prefixes it with the enum name
377 if enum_member:
378 membername = '_' + membername
Eric Blake9fb081e2015-10-26 16:34:44 -0600379 # Reserve the entire 'q_' namespace for c_name()
380 if not valid_name.match(membername) or \
381 c_name(membername, False).startswith('q_'):
Eric Blakec9e0a792015-05-04 09:05:22 -0600382 raise QAPIExprError(expr_info,
383 "%s uses invalid name '%s'" % (source, name))
384
Eric Blake437db252015-09-29 16:21:02 -0600385
386def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200387 global all_names
388 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200389 # FIXME should reject names that differ only in '_' vs. '.'
390 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200391 if name in all_names:
392 raise QAPIExprError(info,
393 "%s '%s' is already defined"
394 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600395 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200396 raise QAPIExprError(info,
Eric Blake255960d2015-10-26 16:34:43 -0600397 "%s '%s' should not end in '%s'"
398 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200399 all_names[name] = meta
400
Eric Blake437db252015-09-29 16:21:02 -0600401
Markus Armbruster00e4b282015-06-10 10:04:36 +0200402def add_struct(definition, info):
403 global struct_types
404 name = definition['struct']
405 add_name(name, info, 'struct')
406 struct_types.append(definition)
407
Eric Blake437db252015-09-29 16:21:02 -0600408
Markus Armbruster00e4b282015-06-10 10:04:36 +0200409def find_struct(name):
410 global struct_types
411 for struct in struct_types:
412 if struct['struct'] == name:
413 return struct
414 return None
415
Eric Blake437db252015-09-29 16:21:02 -0600416
Markus Armbruster00e4b282015-06-10 10:04:36 +0200417def add_union(definition, info):
418 global union_types
419 name = definition['union']
420 add_name(name, info, 'union')
421 union_types.append(definition)
422
Eric Blake437db252015-09-29 16:21:02 -0600423
Markus Armbruster00e4b282015-06-10 10:04:36 +0200424def find_union(name):
425 global union_types
426 for union in union_types:
427 if union['union'] == name:
428 return union
429 return None
430
Eric Blake437db252015-09-29 16:21:02 -0600431
432def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200433 global enum_types
434 add_name(name, info, 'enum', implicit)
435 enum_types.append({"enum_name": name, "enum_values": enum_values})
436
Eric Blake437db252015-09-29 16:21:02 -0600437
Markus Armbruster00e4b282015-06-10 10:04:36 +0200438def find_enum(name):
439 global enum_types
440 for enum in enum_types:
441 if enum['enum_name'] == name:
442 return enum
443 return None
444
Markus Armbruster00e4b282015-06-10 10:04:36 +0200445
Eric Blake437db252015-09-29 16:21:02 -0600446def is_enum(name):
447 return find_enum(name) is not None
448
449
450def check_type(expr_info, source, value, allow_array=False,
451 allow_dict=False, allow_optional=False,
452 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600453 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600454
455 if value is None:
456 return
457
Eric Blakedd883c62015-05-04 09:05:21 -0600458 # Check if array type for value is okay
459 if isinstance(value, list):
460 if not allow_array:
461 raise QAPIExprError(expr_info,
462 "%s cannot be an array" % source)
463 if len(value) != 1 or not isinstance(value[0], str):
464 raise QAPIExprError(expr_info,
465 "%s: array type must contain single type name"
466 % source)
467 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600468
469 # Check if type name for value is okay
470 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600471 if value not in all_names:
Eric Blakedd883c62015-05-04 09:05:21 -0600472 raise QAPIExprError(expr_info,
473 "%s uses unknown type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200474 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600475 if not all_names[value] in allow_metas:
476 raise QAPIExprError(expr_info,
477 "%s cannot use %s type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200478 % (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600479 return
480
Eric Blakedd883c62015-05-04 09:05:21 -0600481 if not allow_dict:
482 raise QAPIExprError(expr_info,
483 "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200484
485 if not isinstance(value, OrderedDict):
486 raise QAPIExprError(expr_info,
487 "%s should be a dictionary or type name" % source)
488
489 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600490 for (key, arg) in value.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600491 check_name(expr_info, "Member of %s" % source, key,
492 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600493 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Eric Blake9fb081e2015-10-26 16:34:44 -0600494 raise QAPIExprError(expr_info,
495 "Member of %s uses reserved name '%s'"
496 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600497 # Todo: allow dictionaries to represent default values of
498 # an optional argument.
Eric Blakedd883c62015-05-04 09:05:21 -0600499 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200500 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600501 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600502 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600503
Eric Blake437db252015-09-29 16:21:02 -0600504
505def check_member_clash(expr_info, base_name, data, source=""):
Eric Blakeff55d722015-05-04 09:05:37 -0600506 base = find_struct(base_name)
507 assert base
508 base_members = base['data']
509 for key in data.keys():
510 if key.startswith('*'):
511 key = key[1:]
512 if key in base_members or "*" + key in base_members:
513 raise QAPIExprError(expr_info,
514 "Member name '%s'%s clashes with base '%s'"
515 % (key, source, base_name))
516 if base.get('base'):
517 check_member_clash(expr_info, base['base'], data, source)
518
Eric Blake437db252015-09-29 16:21:02 -0600519
Eric Blakedd883c62015-05-04 09:05:21 -0600520def check_command(expr, expr_info):
521 name = expr['command']
Eric Blake2cbf0992015-05-04 09:05:24 -0600522
Eric Blakedd883c62015-05-04 09:05:21 -0600523 check_type(expr_info, "'data' for command '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600524 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200525 allow_metas=['struct'])
Eric Blake10d4d992015-05-04 09:05:23 -0600526 returns_meta = ['union', 'struct']
527 if name in returns_whitelist:
528 returns_meta += ['built-in', 'alternate', 'enum']
Eric Blakedd883c62015-05-04 09:05:21 -0600529 check_type(expr_info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200530 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200531 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600532
Eric Blake437db252015-09-29 16:21:02 -0600533
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200534def check_event(expr, expr_info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600535 global events
536 name = expr['event']
Eric Blake4dc2e692015-05-04 09:05:17 -0600537
538 if name.upper() == 'MAX':
539 raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
540 events.append(name)
Eric Blakedd883c62015-05-04 09:05:21 -0600541 check_type(expr_info, "'data' for event '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600542 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster315932b2015-07-01 10:12:24 +0200543 allow_metas=['struct'])
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200544
Eric Blake437db252015-09-29 16:21:02 -0600545
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800546def check_union(expr, expr_info):
547 name = expr['union']
548 base = expr.get('base')
549 discriminator = expr.get('discriminator')
550 members = expr['data']
Eric Blake61a94662015-11-18 01:52:49 -0700551 values = {'MAX': '(automatic)'}
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800552
Eric Blake811d04f2015-05-04 09:05:10 -0600553 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600554
555 # With no discriminator it is a simple union.
556 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600557 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600558 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600559 if base is not None:
560 raise QAPIExprError(expr_info,
Eric Blake811d04f2015-05-04 09:05:10 -0600561 "Simple union '%s' must not have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600562 % name)
563
564 # Else, it's a flat union.
565 else:
566 # The object must have a string member 'base'.
Eric Blake376863e2015-09-29 16:21:07 -0600567 check_type(expr_info, "'base' for union '%s'" % name,
568 base, allow_metas=['struct'])
569 if not base:
Eric Blake44bd1272015-05-04 09:05:08 -0600570 raise QAPIExprError(expr_info,
Eric Blake376863e2015-09-29 16:21:07 -0600571 "Flat union '%s' must have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600572 % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800573 base_fields = find_base_fields(base)
Eric Blake376863e2015-09-29 16:21:07 -0600574 assert base_fields
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800575
Eric Blakec9e0a792015-05-04 09:05:22 -0600576 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600577 # member of the base struct.
Eric Blakec9e0a792015-05-04 09:05:22 -0600578 check_name(expr_info, "Discriminator of flat union '%s'" % name,
579 discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800580 discriminator_type = base_fields.get(discriminator)
581 if not discriminator_type:
582 raise QAPIExprError(expr_info,
583 "Discriminator '%s' is not a member of base "
Eric Blakefd41dd42015-05-04 09:05:25 -0600584 "struct '%s'"
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800585 % (discriminator, base))
586 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600587 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800588 # Do not allow string discriminator
589 if not enum_define:
590 raise QAPIExprError(expr_info,
591 "Discriminator '%s' must be of enumeration "
592 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800593
594 # Check every branch
595 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600596 check_name(expr_info, "Member of union '%s'" % name, key)
597
Eric Blakedd883c62015-05-04 09:05:21 -0600598 # Each value must name a known type; furthermore, in flat unions,
Eric Blakeff55d722015-05-04 09:05:37 -0600599 # branches must be a struct with no overlapping member names
Eric Blakedd883c62015-05-04 09:05:21 -0600600 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200601 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakeff55d722015-05-04 09:05:37 -0600602 if base:
603 branch_struct = find_struct(value)
604 assert branch_struct
605 check_member_clash(expr_info, base, branch_struct['data'],
606 " of branch '%s'" % key)
Eric Blakedd883c62015-05-04 09:05:21 -0600607
Eric Blake44bd1272015-05-04 09:05:08 -0600608 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700609 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600610 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600611 if key not in enum_define['enum_values']:
Eric Blake44bd1272015-05-04 09:05:08 -0600612 raise QAPIExprError(expr_info,
613 "Discriminator value '%s' is not found in "
614 "enum '%s'" %
615 (key, enum_define["enum_name"]))
616
617 # Otherwise, check for conflicts in the generated enum
618 else:
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600619 c_key = camel_to_upper(key)
Eric Blake44bd1272015-05-04 09:05:08 -0600620 if c_key in values:
621 raise QAPIExprError(expr_info,
622 "Union '%s' member '%s' clashes with '%s'"
623 % (name, key, values[c_key]))
624 values[c_key] = key
625
Eric Blake437db252015-09-29 16:21:02 -0600626
Eric Blake811d04f2015-05-04 09:05:10 -0600627def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600628 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600629 members = expr['data']
Eric Blake437db252015-09-29 16:21:02 -0600630 values = {'MAX': '(automatic)'}
Eric Blake811d04f2015-05-04 09:05:10 -0600631 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600632
Eric Blake811d04f2015-05-04 09:05:10 -0600633 # Check every branch
634 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600635 check_name(expr_info, "Member of alternate '%s'" % name, key)
636
Eric Blake811d04f2015-05-04 09:05:10 -0600637 # Check for conflicts in the generated enum
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600638 c_key = camel_to_upper(key)
Eric Blake811d04f2015-05-04 09:05:10 -0600639 if c_key in values:
640 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600641 "Alternate '%s' member '%s' clashes with '%s'"
642 % (name, key, values[c_key]))
Eric Blake811d04f2015-05-04 09:05:10 -0600643 values[c_key] = key
644
645 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600646 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
647 value,
648 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600649 qtype = find_alternate_member_qtype(value)
Eric Blakedd883c62015-05-04 09:05:21 -0600650 assert qtype
Eric Blake811d04f2015-05-04 09:05:10 -0600651 if qtype in types_seen:
652 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600653 "Alternate '%s' member '%s' can't "
Eric Blake811d04f2015-05-04 09:05:10 -0600654 "be distinguished from member '%s'"
655 % (name, key, types_seen[qtype]))
656 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800657
Eric Blake437db252015-09-29 16:21:02 -0600658
Eric Blakecf393592015-05-04 09:05:04 -0600659def check_enum(expr, expr_info):
660 name = expr['enum']
661 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100662 prefix = expr.get('prefix')
Eric Blake437db252015-09-29 16:21:02 -0600663 values = {'MAX': '(automatic)'}
Eric Blakecf393592015-05-04 09:05:04 -0600664
665 if not isinstance(members, list):
666 raise QAPIExprError(expr_info,
667 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100668 if prefix is not None and not isinstance(prefix, str):
669 raise QAPIExprError(expr_info,
670 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600671 for member in members:
Eric Blake437db252015-09-29 16:21:02 -0600672 check_name(expr_info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600673 enum_member=True)
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600674 key = camel_to_upper(member)
Eric Blakecf393592015-05-04 09:05:04 -0600675 if key in values:
676 raise QAPIExprError(expr_info,
677 "Enum '%s' member '%s' clashes with '%s'"
678 % (name, member, values[key]))
679 values[key] = member
680
Eric Blake437db252015-09-29 16:21:02 -0600681
Eric Blakedd883c62015-05-04 09:05:21 -0600682def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600683 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600684 members = expr['data']
685
Eric Blakefd41dd42015-05-04 09:05:25 -0600686 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600687 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600688 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600689 allow_metas=['struct'])
Eric Blakeff55d722015-05-04 09:05:37 -0600690 if expr.get('base'):
691 check_member_clash(expr_info, expr['base'], expr['data'])
Eric Blakedd883c62015-05-04 09:05:21 -0600692
Eric Blake437db252015-09-29 16:21:02 -0600693
Eric Blake0545f6b2015-05-04 09:05:15 -0600694def check_keys(expr_elem, meta, required, optional=[]):
695 expr = expr_elem['expr']
696 info = expr_elem['info']
697 name = expr[meta]
698 if not isinstance(name, str):
699 raise QAPIExprError(info,
700 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600701 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600702 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600703 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600704 raise QAPIExprError(info,
705 "Unknown key '%s' in %s '%s'"
706 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600707 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600708 raise QAPIExprError(info,
709 "'%s' of %s '%s' should only use false value"
710 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600711 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600712 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600713 raise QAPIExprError(info,
714 "Key '%s' is missing from %s '%s'"
715 % (key, meta, name))
716
Eric Blake437db252015-09-29 16:21:02 -0600717
Markus Armbruster4d076d62015-06-10 08:55:21 +0200718def check_exprs(exprs):
719 global all_names
720
721 # Learn the types and check for valid expression keys
722 for builtin in builtin_types.keys():
723 all_names[builtin] = 'built-in'
724 for expr_elem in exprs:
725 expr = expr_elem['expr']
726 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600727 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100728 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200729 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600730 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200731 check_keys(expr_elem, 'union', ['data'],
732 ['base', 'discriminator'])
733 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600734 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200735 check_keys(expr_elem, 'alternate', ['data'])
736 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600737 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200738 check_keys(expr_elem, 'struct', ['data'], ['base'])
739 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600740 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200741 check_keys(expr_elem, 'command', [],
742 ['data', 'returns', 'gen', 'success-response'])
743 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600744 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200745 check_keys(expr_elem, 'event', [], ['data'])
746 add_name(expr['event'], info, 'event')
747 else:
748 raise QAPIExprError(expr_elem['info'],
749 "Expression is missing metatype")
750
751 # Try again for hidden UnionKind enum
752 for expr_elem in exprs:
753 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600754 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200755 if not discriminator_find_enum_define(expr):
756 add_enum('%sKind' % expr['union'], expr_elem['info'],
757 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600758 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200759 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
760 implicit=True)
761
762 # Validate that exprs make sense
763 for expr_elem in exprs:
764 expr = expr_elem['expr']
765 info = expr_elem['info']
766
Eric Blake437db252015-09-29 16:21:02 -0600767 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200768 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600769 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200770 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600771 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200772 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600773 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200774 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600775 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200776 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600777 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200778 check_event(expr, info)
779 else:
780 assert False, 'unexpected meta type'
781
Markus Armbrusterac882192015-09-16 13:06:05 +0200782 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600783
Markus Armbrusterac882192015-09-16 13:06:05 +0200784
785#
786# Schema compiler frontend
787#
788
789class QAPISchemaEntity(object):
790 def __init__(self, name, info):
791 assert isinstance(name, str)
792 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -0600793 # For explicitly defined entities, info points to the (explicit)
794 # definition. For builtins (and their arrays), info is None.
795 # For implicitly defined entities, info points to a place that
796 # triggered the implicit definition (there may be more than one
797 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +0200798 self.info = info
799
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200800 def c_name(self):
801 return c_name(self.name)
802
Markus Armbrusterac882192015-09-16 13:06:05 +0200803 def check(self, schema):
804 pass
805
Eric Blake49823c42015-10-12 22:22:27 -0600806 def is_implicit(self):
807 return not self.info
808
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200809 def visit(self, visitor):
810 pass
811
812
813class QAPISchemaVisitor(object):
814 def visit_begin(self, schema):
815 pass
816
817 def visit_end(self):
818 pass
819
Eric Blake25a0d9c2015-10-12 22:22:21 -0600820 def visit_needed(self, entity):
821 # Default to visiting everything
822 return True
823
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200824 def visit_builtin_type(self, name, info, json_type):
825 pass
826
827 def visit_enum_type(self, name, info, values, prefix):
828 pass
829
830 def visit_array_type(self, name, info, element_type):
831 pass
832
833 def visit_object_type(self, name, info, base, members, variants):
834 pass
835
Markus Armbruster39a18152015-09-16 13:06:28 +0200836 def visit_object_type_flat(self, name, info, members, variants):
837 pass
838
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200839 def visit_alternate_type(self, name, info, variants):
840 pass
841
842 def visit_command(self, name, info, arg_type, ret_type,
843 gen, success_response):
844 pass
845
846 def visit_event(self, name, info, arg_type):
847 pass
848
Markus Armbrusterac882192015-09-16 13:06:05 +0200849
850class QAPISchemaType(QAPISchemaEntity):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200851 def c_type(self, is_param=False):
852 return c_name(self.name) + pointer_suffix
853
854 def c_null(self):
855 return 'NULL'
856
857 def json_type(self):
858 pass
859
860 def alternate_qtype(self):
861 json2qtype = {
862 'string': 'QTYPE_QSTRING',
863 'number': 'QTYPE_QFLOAT',
864 'int': 'QTYPE_QINT',
865 'boolean': 'QTYPE_QBOOL',
866 'object': 'QTYPE_QDICT'
867 }
868 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200869
870
871class QAPISchemaBuiltinType(QAPISchemaType):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200872 def __init__(self, name, json_type, c_type, c_null):
Markus Armbrusterac882192015-09-16 13:06:05 +0200873 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200874 assert not c_type or isinstance(c_type, str)
875 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
876 'value')
877 self._json_type_name = json_type
878 self._c_type_name = c_type
879 self._c_null_val = c_null
880
881 def c_name(self):
882 return self.name
883
884 def c_type(self, is_param=False):
885 if is_param and self.name == 'str':
886 return 'const ' + self._c_type_name
887 return self._c_type_name
888
889 def c_null(self):
890 return self._c_null_val
891
892 def json_type(self):
893 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200894
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200895 def visit(self, visitor):
896 visitor.visit_builtin_type(self.name, self.info, self.json_type())
897
Markus Armbrusterac882192015-09-16 13:06:05 +0200898
899class QAPISchemaEnumType(QAPISchemaType):
900 def __init__(self, name, info, values, prefix):
901 QAPISchemaType.__init__(self, name, info)
902 for v in values:
903 assert isinstance(v, str)
904 assert prefix is None or isinstance(prefix, str)
905 self.values = values
906 self.prefix = prefix
907
908 def check(self, schema):
909 assert len(set(self.values)) == len(self.values)
910
Eric Blake99df5282015-10-12 22:22:32 -0600911 def is_implicit(self):
912 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -0600913 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -0600914
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200915 def c_type(self, is_param=False):
916 return c_name(self.name)
917
918 def c_null(self):
919 return c_enum_const(self.name, (self.values + ['MAX'])[0],
920 self.prefix)
921
922 def json_type(self):
923 return 'string'
924
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200925 def visit(self, visitor):
926 visitor.visit_enum_type(self.name, self.info,
927 self.values, self.prefix)
928
Markus Armbrusterac882192015-09-16 13:06:05 +0200929
930class QAPISchemaArrayType(QAPISchemaType):
931 def __init__(self, name, info, element_type):
932 QAPISchemaType.__init__(self, name, info)
933 assert isinstance(element_type, str)
934 self._element_type_name = element_type
935 self.element_type = None
936
937 def check(self, schema):
938 self.element_type = schema.lookup_type(self._element_type_name)
939 assert self.element_type
940
Eric Blake99df5282015-10-12 22:22:32 -0600941 def is_implicit(self):
942 return True
943
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200944 def json_type(self):
945 return 'array'
946
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200947 def visit(self, visitor):
948 visitor.visit_array_type(self.name, self.info, self.element_type)
949
Markus Armbrusterac882192015-09-16 13:06:05 +0200950
951class QAPISchemaObjectType(QAPISchemaType):
952 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -0700953 # struct has local_members, optional base, and no variants
954 # flat union has base, variants, and no local_members
955 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +0200956 QAPISchemaType.__init__(self, name, info)
957 assert base is None or isinstance(base, str)
958 for m in local_members:
959 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -0700960 m.set_owner(name)
961 if variants is not None:
962 assert isinstance(variants, QAPISchemaObjectTypeVariants)
963 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200964 self._base_name = base
965 self.base = None
966 self.local_members = local_members
967 self.variants = variants
968 self.members = None
969
970 def check(self, schema):
971 assert self.members is not False # not running in cycles
972 if self.members:
973 return
974 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -0700975 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +0200976 if self._base_name:
977 self.base = schema.lookup_type(self._base_name)
978 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +0200979 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700980 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200981 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -0700982 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700983 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700984 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +0200985 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -0700986 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700987 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -0700988 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200989
Eric Blake27b60ab2015-11-18 01:52:51 -0700990 # Check that the members of this type do not cause duplicate JSON fields,
991 # and update seen to track the members seen so far. Report any errors
992 # on behalf of info, which is not necessarily self.info
993 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -0700994 assert not self.variants # not implemented
995 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -0700996 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -0700997
Eric Blake99df5282015-10-12 22:22:32 -0600998 def is_implicit(self):
999 # See QAPISchema._make_implicit_object_type()
1000 return self.name[0] == ':'
1001
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001002 def c_name(self):
Eric Blake49823c42015-10-12 22:22:27 -06001003 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001004 return QAPISchemaType.c_name(self)
1005
1006 def c_type(self, is_param=False):
Eric Blake49823c42015-10-12 22:22:27 -06001007 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001008 return QAPISchemaType.c_type(self)
1009
1010 def json_type(self):
1011 return 'object'
1012
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001013 def visit(self, visitor):
1014 visitor.visit_object_type(self.name, self.info,
1015 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001016 visitor.visit_object_type_flat(self.name, self.info,
1017 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001018
Markus Armbrusterac882192015-09-16 13:06:05 +02001019
1020class QAPISchemaObjectTypeMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001021 role = 'member'
1022
Markus Armbrusterac882192015-09-16 13:06:05 +02001023 def __init__(self, name, typ, optional):
1024 assert isinstance(name, str)
1025 assert isinstance(typ, str)
1026 assert isinstance(optional, bool)
1027 self.name = name
1028 self._type_name = typ
1029 self.type = None
1030 self.optional = optional
Eric Blake88d4ef82015-11-18 01:52:50 -07001031 self.owner = None
1032
1033 def set_owner(self, name):
1034 assert not self.owner
1035 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001036
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001037 def check(self, schema):
Eric Blake88d4ef82015-11-18 01:52:50 -07001038 assert self.owner
Markus Armbrusterac882192015-09-16 13:06:05 +02001039 self.type = schema.lookup_type(self._type_name)
1040 assert self.type
Markus Armbrusterac882192015-09-16 13:06:05 +02001041
Eric Blake27b60ab2015-11-18 01:52:51 -07001042 def check_clash(self, info, seen):
1043 cname = c_name(self.name)
1044 if cname in seen:
1045 raise QAPIExprError(info,
1046 "%s collides with %s"
1047 % (self.describe(), seen[cname].describe()))
1048 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001049
Eric Blake88d4ef82015-11-18 01:52:50 -07001050 def _pretty_owner(self):
1051 owner = self.owner
1052 if owner.startswith(':obj-'):
1053 # See QAPISchema._make_implicit_object_type() - reverse the
1054 # mapping there to create a nice human-readable description
1055 owner = owner[5:]
1056 if owner.endswith('-arg'):
1057 return '(parameter of %s)' % owner[:-4]
1058 else:
1059 assert owner.endswith('-wrapper')
1060 # Unreachable and not implemented
1061 assert False
1062 return '(%s of %s)' % (self.role, owner)
1063
1064 def describe(self):
1065 return "'%s' %s" % (self.name, self._pretty_owner())
1066
Markus Armbrusterac882192015-09-16 13:06:05 +02001067
1068class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001069 def __init__(self, tag_name, tag_member, variants):
1070 # Flat unions pass tag_name but not tag_member.
1071 # Simple unions and alternates pass tag_member but not tag_name.
1072 # After check(), tag_member is always set, and tag_name remains
1073 # a reliable witness of being used by a flat union.
1074 assert bool(tag_member) != bool(tag_name)
1075 assert (isinstance(tag_name, str) or
1076 isinstance(tag_member, QAPISchemaObjectTypeMember))
Markus Armbrusterac882192015-09-16 13:06:05 +02001077 for v in variants:
1078 assert isinstance(v, QAPISchemaObjectTypeVariant)
1079 self.tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001080 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001081 self.variants = variants
1082
Eric Blake88d4ef82015-11-18 01:52:50 -07001083 def set_owner(self, name):
1084 for v in self.variants:
1085 v.set_owner(name)
1086
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001087 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001088 if not self.tag_member: # flat union
Eric Blake27b60ab2015-11-18 01:52:51 -07001089 self.tag_member = seen[c_name(self.tag_name)]
1090 assert self.tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001091 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1092 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001093 v.check(schema)
1094 assert v.name in self.tag_member.type.values
Eric Blakeb807a1e2015-11-18 01:52:46 -07001095 if isinstance(v.type, QAPISchemaObjectType):
1096 v.type.check(schema)
1097
Eric Blake27b60ab2015-11-18 01:52:51 -07001098 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001099 for v in self.variants:
1100 # Reset seen map for each variant, since qapi names from one
1101 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001102 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001103 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001104
Eric Blake437db252015-09-29 16:21:02 -06001105
Markus Armbrusterac882192015-09-16 13:06:05 +02001106class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001107 role = 'branch'
1108
Markus Armbrusterac882192015-09-16 13:06:05 +02001109 def __init__(self, name, typ):
1110 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1111
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001112 # This function exists to support ugly simple union special cases
1113 # TODO get rid of them, and drop the function
1114 def simple_union_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001115 if (self.type.is_implicit() and
1116 isinstance(self.type, QAPISchemaObjectType)):
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001117 assert len(self.type.members) == 1
1118 assert not self.type.variants
1119 return self.type.members[0].type
1120 return None
1121
Markus Armbrusterac882192015-09-16 13:06:05 +02001122
1123class QAPISchemaAlternateType(QAPISchemaType):
1124 def __init__(self, name, info, variants):
1125 QAPISchemaType.__init__(self, name, info)
1126 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1127 assert not variants.tag_name
Eric Blake88d4ef82015-11-18 01:52:50 -07001128 variants.set_owner(name)
1129 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001130 self.variants = variants
1131
1132 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001133 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001134 # Not calling self.variants.check_clash(), because there's nothing
1135 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001136 self.variants.check(schema, {})
Markus Armbrusterac882192015-09-16 13:06:05 +02001137
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001138 def json_type(self):
1139 return 'value'
1140
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001141 def visit(self, visitor):
1142 visitor.visit_alternate_type(self.name, self.info, self.variants)
1143
Markus Armbrusterac882192015-09-16 13:06:05 +02001144
1145class QAPISchemaCommand(QAPISchemaEntity):
1146 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1147 QAPISchemaEntity.__init__(self, name, info)
1148 assert not arg_type or isinstance(arg_type, str)
1149 assert not ret_type or isinstance(ret_type, str)
1150 self._arg_type_name = arg_type
1151 self.arg_type = None
1152 self._ret_type_name = ret_type
1153 self.ret_type = None
1154 self.gen = gen
1155 self.success_response = success_response
1156
1157 def check(self, schema):
1158 if self._arg_type_name:
1159 self.arg_type = schema.lookup_type(self._arg_type_name)
1160 assert isinstance(self.arg_type, QAPISchemaObjectType)
1161 assert not self.arg_type.variants # not implemented
1162 if self._ret_type_name:
1163 self.ret_type = schema.lookup_type(self._ret_type_name)
1164 assert isinstance(self.ret_type, QAPISchemaType)
1165
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001166 def visit(self, visitor):
1167 visitor.visit_command(self.name, self.info,
1168 self.arg_type, self.ret_type,
1169 self.gen, self.success_response)
1170
Markus Armbrusterac882192015-09-16 13:06:05 +02001171
1172class QAPISchemaEvent(QAPISchemaEntity):
1173 def __init__(self, name, info, arg_type):
1174 QAPISchemaEntity.__init__(self, name, info)
1175 assert not arg_type or isinstance(arg_type, str)
1176 self._arg_type_name = arg_type
1177 self.arg_type = None
1178
1179 def check(self, schema):
1180 if self._arg_type_name:
1181 self.arg_type = schema.lookup_type(self._arg_type_name)
1182 assert isinstance(self.arg_type, QAPISchemaObjectType)
1183 assert not self.arg_type.variants # not implemented
1184
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001185 def visit(self, visitor):
1186 visitor.visit_event(self.name, self.info, self.arg_type)
1187
Markus Armbrusterac882192015-09-16 13:06:05 +02001188
1189class QAPISchema(object):
1190 def __init__(self, fname):
1191 try:
1192 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001193 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001194 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001195 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001196 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001197 self._def_exprs()
1198 self.check()
Markus Armbrusterac882192015-09-16 13:06:05 +02001199 except (QAPISchemaError, QAPIExprError), err:
1200 print >>sys.stderr, err
1201 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001202
Markus Armbrusterac882192015-09-16 13:06:05 +02001203 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001204 # Only the predefined types are allowed to not have info
1205 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001206 assert ent.name not in self._entity_dict
1207 self._entity_dict[ent.name] = ent
1208
1209 def lookup_entity(self, name, typ=None):
1210 ent = self._entity_dict.get(name)
1211 if typ and not isinstance(ent, typ):
1212 return None
1213 return ent
1214
1215 def lookup_type(self, name):
1216 return self.lookup_entity(name, QAPISchemaType)
1217
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001218 def _def_builtin_type(self, name, json_type, c_type, c_null):
1219 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1220 c_type, c_null))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001221 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1222 # qapi-types.h from a single .c, all arrays of builtins must be
1223 # declared in the first file whether or not they are used. Nicer
1224 # would be to use lazy instantiation, while figuring out how to
1225 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001226 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001227
1228 def _def_predefineds(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001229 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1230 ('number', 'number', 'double', '0'),
1231 ('int', 'int', 'int64_t', '0'),
1232 ('int8', 'int', 'int8_t', '0'),
1233 ('int16', 'int', 'int16_t', '0'),
1234 ('int32', 'int', 'int32_t', '0'),
1235 ('int64', 'int', 'int64_t', '0'),
1236 ('uint8', 'int', 'uint8_t', '0'),
1237 ('uint16', 'int', 'uint16_t', '0'),
1238 ('uint32', 'int', 'uint32_t', '0'),
1239 ('uint64', 'int', 'uint64_t', '0'),
1240 ('size', 'int', 'uint64_t', '0'),
1241 ('bool', 'boolean', 'bool', 'false'),
Markus Armbruster28770e02015-09-16 13:06:24 +02001242 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001243 self._def_builtin_type(*t)
Markus Armbruster39a18152015-09-16 13:06:28 +02001244 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1245 [], None)
1246 self._def_entity(self.the_empty_object_type)
Markus Armbrusterac882192015-09-16 13:06:05 +02001247
Eric Blake99df5282015-10-12 22:22:32 -06001248 def _make_implicit_enum_type(self, name, info, values):
Eric Blake49823c42015-10-12 22:22:27 -06001249 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake99df5282015-10-12 22:22:32 -06001250 self._def_entity(QAPISchemaEnumType(name, info, values, None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001251 return name
1252
Eric Blake99df5282015-10-12 22:22:32 -06001253 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001254 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001255 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001256 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001257 return name
1258
Eric Blake99df5282015-10-12 22:22:32 -06001259 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001260 if not members:
1261 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001262 # See also QAPISchemaObjectTypeMember._pretty_owner()
Markus Armbrusterac882192015-09-16 13:06:05 +02001263 name = ':obj-%s-%s' % (name, role)
1264 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001265 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001266 members, None))
1267 return name
1268
1269 def _def_enum_type(self, expr, info):
1270 name = expr['enum']
1271 data = expr['data']
1272 prefix = expr.get('prefix')
1273 self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001274
Eric Blake99df5282015-10-12 22:22:32 -06001275 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001276 optional = False
1277 if name.startswith('*'):
1278 name = name[1:]
1279 optional = True
1280 if isinstance(typ, list):
1281 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001282 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001283 return QAPISchemaObjectTypeMember(name, typ, optional)
1284
Eric Blake99df5282015-10-12 22:22:32 -06001285 def _make_members(self, data, info):
1286 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001287 for (key, value) in data.iteritems()]
1288
1289 def _def_struct_type(self, expr, info):
1290 name = expr['struct']
1291 base = expr.get('base')
1292 data = expr['data']
1293 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001294 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001295 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001296
1297 def _make_variant(self, case, typ):
1298 return QAPISchemaObjectTypeVariant(case, typ)
1299
Eric Blake99df5282015-10-12 22:22:32 -06001300 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001301 if isinstance(typ, list):
1302 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001303 typ = self._make_array_type(typ[0], info)
1304 typ = self._make_implicit_object_type(
1305 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001306 return QAPISchemaObjectTypeVariant(case, typ)
1307
Eric Blake99df5282015-10-12 22:22:32 -06001308 def _make_implicit_tag(self, type_name, info, variants):
1309 typ = self._make_implicit_enum_type(type_name, info,
Eric Blake46292ba2015-10-12 22:22:29 -06001310 [v.name for v in variants])
1311 return QAPISchemaObjectTypeMember('type', typ, False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001312
1313 def _def_union_type(self, expr, info):
1314 name = expr['union']
1315 data = expr['data']
1316 base = expr.get('base')
1317 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001318 tag_member = None
Markus Armbrusterac882192015-09-16 13:06:05 +02001319 if tag_name:
1320 variants = [self._make_variant(key, value)
1321 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001322 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001323 else:
Eric Blake99df5282015-10-12 22:22:32 -06001324 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001325 for (key, value) in data.iteritems()]
Eric Blake99df5282015-10-12 22:22:32 -06001326 tag_member = self._make_implicit_tag(name, info, variants)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001327 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001328 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001329 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001330 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001331 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001332 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001333
1334 def _def_alternate_type(self, expr, info):
1335 name = expr['alternate']
1336 data = expr['data']
1337 variants = [self._make_variant(key, value)
1338 for (key, value) in data.iteritems()]
Eric Blake99df5282015-10-12 22:22:32 -06001339 tag_member = self._make_implicit_tag(name, info, variants)
Markus Armbrusterac882192015-09-16 13:06:05 +02001340 self._def_entity(
1341 QAPISchemaAlternateType(name, info,
1342 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001343 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001344 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001345
1346 def _def_command(self, expr, info):
1347 name = expr['command']
1348 data = expr.get('data')
1349 rets = expr.get('returns')
1350 gen = expr.get('gen', True)
1351 success_response = expr.get('success-response', True)
1352 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001353 data = self._make_implicit_object_type(
1354 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001355 if isinstance(rets, list):
1356 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001357 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001358 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1359 success_response))
1360
1361 def _def_event(self, expr, info):
1362 name = expr['event']
1363 data = expr.get('data')
1364 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001365 data = self._make_implicit_object_type(
1366 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001367 self._def_entity(QAPISchemaEvent(name, info, data))
1368
1369 def _def_exprs(self):
1370 for expr_elem in self.exprs:
1371 expr = expr_elem['expr']
1372 info = expr_elem['info']
1373 if 'enum' in expr:
1374 self._def_enum_type(expr, info)
1375 elif 'struct' in expr:
1376 self._def_struct_type(expr, info)
1377 elif 'union' in expr:
1378 self._def_union_type(expr, info)
1379 elif 'alternate' in expr:
1380 self._def_alternate_type(expr, info)
1381 elif 'command' in expr:
1382 self._def_command(expr, info)
1383 elif 'event' in expr:
1384 self._def_event(expr, info)
1385 else:
1386 assert False
1387
1388 def check(self):
1389 for ent in self._entity_dict.values():
1390 ent.check(self)
1391
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001392 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001393 visitor.visit_begin(self)
1394 for (name, entity) in sorted(self._entity_dict.items()):
1395 if visitor.visit_needed(entity):
1396 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001397 visitor.visit_end()
1398
Markus Armbruster2caba362013-07-27 17:41:56 +02001399
Markus Armbruster00e4b282015-06-10 10:04:36 +02001400#
1401# Code generation helpers
1402#
1403
Michael Roth0f923be2011-07-19 14:50:39 -05001404def camel_case(name):
1405 new_name = ''
1406 first = True
1407 for ch in name:
1408 if ch in ['_', '-']:
1409 first = True
1410 elif first:
1411 new_name += ch.upper()
1412 first = False
1413 else:
1414 new_name += ch.lower()
1415 return new_name
1416
Eric Blake437db252015-09-29 16:21:02 -06001417
Markus Armbruster849bc532015-05-14 06:50:53 -06001418# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1419# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1420# ENUM24_Name -> ENUM24_NAME
1421def camel_to_upper(value):
1422 c_fun_str = c_name(value, False)
1423 if value.isupper():
1424 return c_fun_str
1425
1426 new_name = ''
1427 l = len(c_fun_str)
1428 for i in range(l):
1429 c = c_fun_str[i]
1430 # When c is upper and no "_" appears before, do more checks
1431 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001432 if i < l - 1 and c_fun_str[i + 1].islower():
1433 new_name += '_'
1434 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001435 new_name += '_'
1436 new_name += c
1437 return new_name.lstrip('_').upper()
1438
Eric Blake437db252015-09-29 16:21:02 -06001439
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001440def c_enum_const(type_name, const_name, prefix=None):
1441 if prefix is not None:
1442 type_name = prefix
Markus Armbruster849bc532015-05-14 06:50:53 -06001443 return camel_to_upper(type_name + '_' + const_name)
1444
Eric Blake18df5152015-05-14 06:50:48 -06001445c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001446
Eric Blake437db252015-09-29 16:21:02 -06001447
Eric Blakec6405b52015-05-14 06:50:55 -06001448# Map @name to a valid C identifier.
1449# If @protect, avoid returning certain ticklish identifiers (like
1450# C keywords) by prepending "q_".
1451#
1452# Used for converting 'name' from a 'name':'type' qapi definition
1453# into a generated struct member, as well as converting type names
1454# into substrings of a generated C function name.
1455# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1456# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001457def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001458 # ANSI X3J11/88-090, 3.1.1
1459 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001460 'default', 'do', 'double', 'else', 'enum', 'extern',
1461 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1462 'return', 'short', 'signed', 'sizeof', 'static',
1463 'struct', 'switch', 'typedef', 'union', 'unsigned',
1464 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001465 # ISO/IEC 9899:1999, 6.4.1
1466 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1467 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001468 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1469 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001470 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1471 # excluding _.*
1472 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001473 # C++ ISO/IEC 14882:2003 2.11
1474 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1475 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1476 'namespace', 'new', 'operator', 'private', 'protected',
1477 'public', 'reinterpret_cast', 'static_cast', 'template',
1478 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1479 'using', 'virtual', 'wchar_t',
1480 # alternative representations
1481 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1482 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001483 # namespace pollution:
Max Reitz8592a542013-12-20 19:28:18 +01001484 polluted_words = set(['unix', 'errno'])
Eric Blakec43567c2015-11-18 01:52:52 -07001485 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001486 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1487 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001488 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001489 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001490
Amos Kong05dfb262014-06-10 19:25:53 +08001491eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001492pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001493
Eric Blake437db252015-09-29 16:21:02 -06001494
Michael Roth0f923be2011-07-19 14:50:39 -05001495def genindent(count):
1496 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001497 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001498 ret += " "
1499 return ret
1500
1501indent_level = 0
1502
Eric Blake437db252015-09-29 16:21:02 -06001503
Michael Roth0f923be2011-07-19 14:50:39 -05001504def push_indent(indent_amount=4):
1505 global indent_level
1506 indent_level += indent_amount
1507
Eric Blake437db252015-09-29 16:21:02 -06001508
Michael Roth0f923be2011-07-19 14:50:39 -05001509def pop_indent(indent_amount=4):
1510 global indent_level
1511 indent_level -= indent_amount
1512
Eric Blake437db252015-09-29 16:21:02 -06001513
Markus Armbruster77e703b2015-06-24 19:27:32 +02001514# Generate @code with @kwds interpolated.
1515# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001516def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001517 raw = code % kwds
1518 if indent_level:
1519 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001520 # re.subn() lacks flags support before Python 2.7, use re.compile()
1521 raw = re.subn(re.compile("^.", re.MULTILINE),
1522 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001523 raw = raw[0]
1524 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001525
Eric Blake437db252015-09-29 16:21:02 -06001526
Michael Roth0f923be2011-07-19 14:50:39 -05001527def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001528 if code[0] == '\n':
1529 code = code[1:]
1530 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001531
Michael Roth0f923be2011-07-19 14:50:39 -05001532
1533def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001534 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001535
Eric Blake437db252015-09-29 16:21:02 -06001536
Michael Rothc0afa9c2013-05-10 17:46:00 -05001537def guardstart(name):
1538 return mcgen('''
1539
1540#ifndef %(name)s
1541#define %(name)s
1542
1543''',
1544 name=guardname(name))
1545
Eric Blake437db252015-09-29 16:21:02 -06001546
Michael Rothc0afa9c2013-05-10 17:46:00 -05001547def guardend(name):
1548 return mcgen('''
1549
1550#endif /* %(name)s */
1551
1552''',
1553 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001554
Eric Blake437db252015-09-29 16:21:02 -06001555
Markus Armbrustere98859a2015-09-16 13:06:16 +02001556def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001557 ret = mcgen('''
1558
Markus Armbrustere98859a2015-09-16 13:06:16 +02001559const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001560''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001561 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001562 for value in values:
1563 index = c_enum_const(name, value, prefix)
1564 ret += mcgen('''
1565 [%(index)s] = "%(value)s",
1566''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001567 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001568
1569 max_index = c_enum_const(name, 'MAX', prefix)
1570 ret += mcgen('''
1571 [%(max_index)s] = NULL,
1572};
1573''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001574 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001575 return ret
1576
Eric Blake437db252015-09-29 16:21:02 -06001577
Markus Armbrustere98859a2015-09-16 13:06:16 +02001578def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001579 # append automatically generated _MAX value
Markus Armbrustere98859a2015-09-16 13:06:16 +02001580 enum_values = values + ['MAX']
1581
1582 ret = mcgen('''
1583
1584typedef enum %(c_name)s {
1585''',
1586 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001587
1588 i = 0
1589 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001590 ret += mcgen('''
1591 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001592''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001593 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001594 i=i)
1595 i += 1
1596
Markus Armbrustere98859a2015-09-16 13:06:16 +02001597 ret += mcgen('''
1598} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001599''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001600 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001601
Markus Armbrustere98859a2015-09-16 13:06:16 +02001602 ret += mcgen('''
1603
1604extern const char *const %(c_name)s_lookup[];
1605''',
1606 c_name=c_name(name))
1607 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001608
Eric Blake437db252015-09-29 16:21:02 -06001609
Markus Armbruster03b43672015-09-16 13:06:20 +02001610def gen_params(arg_type, extra):
1611 if not arg_type:
1612 return extra
1613 assert not arg_type.variants
1614 ret = ''
1615 sep = ''
1616 for memb in arg_type.members:
1617 ret += sep
1618 sep = ', '
1619 if memb.optional:
1620 ret += 'bool has_%s, ' % c_name(memb.name)
1621 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1622 if extra:
1623 ret += sep + extra
1624 return ret
1625
Eric Blake1f353342015-09-29 16:21:13 -06001626
Eric Blake18bdbc32015-09-29 16:21:15 -06001627def gen_err_check(label='out', skiperr=False):
1628 if skiperr:
Eric Blake1f353342015-09-29 16:21:13 -06001629 return ''
1630 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001631 if (err) {
Eric Blake1f353342015-09-29 16:21:13 -06001632 goto %(label)s;
1633 }
1634''',
Eric Blake18bdbc32015-09-29 16:21:15 -06001635 label=label)
Eric Blake1f353342015-09-29 16:21:13 -06001636
1637
Eric Blake18bdbc32015-09-29 16:21:15 -06001638def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
Eric Blake82ca8e42015-09-29 16:21:14 -06001639 ret = ''
Eric Blake18bdbc32015-09-29 16:21:15 -06001640 if skiperr:
Eric Blake82ca8e42015-09-29 16:21:14 -06001641 errparg = 'NULL'
Eric Blake18bdbc32015-09-29 16:21:15 -06001642 else:
1643 errparg = '&err'
Eric Blake82ca8e42015-09-29 16:21:14 -06001644
1645 for memb in members:
1646 if memb.optional:
1647 ret += mcgen('''
1648 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1649''',
1650 prefix=prefix, c_name=c_name(memb.name),
1651 name=memb.name, errp=errparg)
Eric Blake18bdbc32015-09-29 16:21:15 -06001652 ret += gen_err_check(skiperr=skiperr)
Eric Blake82ca8e42015-09-29 16:21:14 -06001653 ret += mcgen('''
1654 if (%(prefix)shas_%(c_name)s) {
1655''',
1656 prefix=prefix, c_name=c_name(memb.name))
1657 push_indent()
1658
1659 # Ugly: sometimes we need to cast away const
1660 if need_cast and memb.type.name == 'str':
1661 cast = '(char **)'
1662 else:
1663 cast = ''
1664
1665 ret += mcgen('''
1666 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1667''',
1668 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1669 c_name=c_name(memb.name), name=memb.name,
1670 errp=errparg)
Eric Blake18bdbc32015-09-29 16:21:15 -06001671 ret += gen_err_check(skiperr=skiperr)
Eric Blake82ca8e42015-09-29 16:21:14 -06001672
1673 if memb.optional:
1674 pop_indent()
1675 ret += mcgen('''
1676 }
1677''')
1678 return ret
1679
1680
Markus Armbruster00e4b282015-06-10 10:04:36 +02001681#
1682# Common command line parsing
1683#
1684
Eric Blake437db252015-09-29 16:21:02 -06001685
1686def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001687
1688 try:
1689 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001690 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001691 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001692 "output-dir="] + extra_long_options)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001693 except getopt.GetoptError, err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001694 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001695 sys.exit(1)
1696
1697 output_dir = ""
1698 prefix = ""
1699 do_c = False
1700 do_h = False
1701 extra_opts = []
1702
1703 for oa in opts:
1704 o, a = oa
1705 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001706 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1707 if match.end() != len(a):
1708 print >>sys.stderr, \
1709 "%s: 'funny character '%s' in argument of --prefix" \
1710 % (sys.argv[0], a[match.end()])
1711 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001712 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001713 elif o in ("-o", "--output-dir"):
1714 output_dir = a + "/"
1715 elif o in ("-c", "--source"):
1716 do_c = True
1717 elif o in ("-h", "--header"):
1718 do_h = True
1719 else:
1720 extra_opts.append(oa)
1721
1722 if not do_c and not do_h:
1723 do_c = True
1724 do_h = True
1725
Markus Armbruster16d80f62015-04-02 13:32:16 +02001726 if len(args) != 1:
1727 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001728 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001729 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001730
Markus Armbruster54414042015-06-09 16:22:45 +02001731 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001732
Markus Armbruster00e4b282015-06-10 10:04:36 +02001733#
1734# Generate output files with boilerplate
1735#
1736
Eric Blake437db252015-09-29 16:21:02 -06001737
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001738def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1739 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001740 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001741 c_file = output_dir + prefix + c_file
1742 h_file = output_dir + prefix + h_file
1743
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001744 if output_dir:
1745 try:
1746 os.makedirs(output_dir)
1747 except os.error, e:
1748 if e.errno != errno.EEXIST:
1749 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001750
1751 def maybe_open(really, name, opt):
1752 if really:
1753 return open(name, opt)
1754 else:
1755 import StringIO
1756 return StringIO.StringIO()
1757
1758 fdef = maybe_open(do_c, c_file, 'w')
1759 fdecl = maybe_open(do_h, h_file, 'w')
1760
1761 fdef.write(mcgen('''
1762/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1763%(comment)s
1764''',
Eric Blake437db252015-09-29 16:21:02 -06001765 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001766
1767 fdecl.write(mcgen('''
1768/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1769%(comment)s
1770#ifndef %(guard)s
1771#define %(guard)s
1772
1773''',
Eric Blake437db252015-09-29 16:21:02 -06001774 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001775
1776 return (fdef, fdecl)
1777
Eric Blake437db252015-09-29 16:21:02 -06001778
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001779def close_output(fdef, fdecl):
1780 fdecl.write('''
1781#endif
1782''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001783 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001784 fdef.close()