blob: 3e5caa81938b22278072434cab96a581fad1deeb [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
Eric Blake59a92fe2015-11-18 01:52:56 -0700356# Names must be letters, numbers, -, and _. They must start with letter,
357# except for downstream extensions which must start with __RFQDN_.
358# Dots are only valid in the downstream extension prefix.
359valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
360 '[a-zA-Z][a-zA-Z0-9_-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600361
362
363def check_name(expr_info, source, name, allow_optional=False,
364 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600365 global valid_name
366 membername = name
367
368 if not isinstance(name, str):
369 raise QAPIExprError(expr_info,
370 "%s requires a string name" % source)
371 if name.startswith('*'):
372 membername = name[1:]
373 if not allow_optional:
374 raise QAPIExprError(expr_info,
375 "%s does not allow optional name '%s'"
376 % (source, name))
377 # Enum members can start with a digit, because the generated C
378 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700379 if enum_member and membername[0].isdigit():
380 membername = 'D' + membername
Eric Blake9fb081e2015-10-26 16:34:44 -0600381 # Reserve the entire 'q_' namespace for c_name()
382 if not valid_name.match(membername) or \
383 c_name(membername, False).startswith('q_'):
Eric Blakec9e0a792015-05-04 09:05:22 -0600384 raise QAPIExprError(expr_info,
385 "%s uses invalid name '%s'" % (source, name))
386
Eric Blake437db252015-09-29 16:21:02 -0600387
388def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200389 global all_names
390 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200391 # FIXME should reject names that differ only in '_' vs. '.'
392 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200393 if name in all_names:
394 raise QAPIExprError(info,
395 "%s '%s' is already defined"
396 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600397 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200398 raise QAPIExprError(info,
Eric Blake255960d2015-10-26 16:34:43 -0600399 "%s '%s' should not end in '%s'"
400 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200401 all_names[name] = meta
402
Eric Blake437db252015-09-29 16:21:02 -0600403
Markus Armbruster00e4b282015-06-10 10:04:36 +0200404def add_struct(definition, info):
405 global struct_types
406 name = definition['struct']
407 add_name(name, info, 'struct')
408 struct_types.append(definition)
409
Eric Blake437db252015-09-29 16:21:02 -0600410
Markus Armbruster00e4b282015-06-10 10:04:36 +0200411def find_struct(name):
412 global struct_types
413 for struct in struct_types:
414 if struct['struct'] == name:
415 return struct
416 return None
417
Eric Blake437db252015-09-29 16:21:02 -0600418
Markus Armbruster00e4b282015-06-10 10:04:36 +0200419def add_union(definition, info):
420 global union_types
421 name = definition['union']
422 add_name(name, info, 'union')
423 union_types.append(definition)
424
Eric Blake437db252015-09-29 16:21:02 -0600425
Markus Armbruster00e4b282015-06-10 10:04:36 +0200426def find_union(name):
427 global union_types
428 for union in union_types:
429 if union['union'] == name:
430 return union
431 return None
432
Eric Blake437db252015-09-29 16:21:02 -0600433
434def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200435 global enum_types
436 add_name(name, info, 'enum', implicit)
437 enum_types.append({"enum_name": name, "enum_values": enum_values})
438
Eric Blake437db252015-09-29 16:21:02 -0600439
Markus Armbruster00e4b282015-06-10 10:04:36 +0200440def find_enum(name):
441 global enum_types
442 for enum in enum_types:
443 if enum['enum_name'] == name:
444 return enum
445 return None
446
Markus Armbruster00e4b282015-06-10 10:04:36 +0200447
Eric Blake437db252015-09-29 16:21:02 -0600448def is_enum(name):
449 return find_enum(name) is not None
450
451
452def check_type(expr_info, source, value, allow_array=False,
453 allow_dict=False, allow_optional=False,
454 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600455 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600456
457 if value is None:
458 return
459
Eric Blakedd883c62015-05-04 09:05:21 -0600460 # Check if array type for value is okay
461 if isinstance(value, list):
462 if not allow_array:
463 raise QAPIExprError(expr_info,
464 "%s cannot be an array" % source)
465 if len(value) != 1 or not isinstance(value[0], str):
466 raise QAPIExprError(expr_info,
467 "%s: array type must contain single type name"
468 % source)
469 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600470
471 # Check if type name for value is okay
472 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600473 if value not in all_names:
Eric Blakedd883c62015-05-04 09:05:21 -0600474 raise QAPIExprError(expr_info,
475 "%s uses unknown type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200476 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600477 if not all_names[value] in allow_metas:
478 raise QAPIExprError(expr_info,
479 "%s cannot use %s type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200480 % (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600481 return
482
Eric Blakedd883c62015-05-04 09:05:21 -0600483 if not allow_dict:
484 raise QAPIExprError(expr_info,
485 "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200486
487 if not isinstance(value, OrderedDict):
488 raise QAPIExprError(expr_info,
489 "%s should be a dictionary or type name" % source)
490
491 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600492 for (key, arg) in value.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600493 check_name(expr_info, "Member of %s" % source, key,
494 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600495 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Eric Blake9fb081e2015-10-26 16:34:44 -0600496 raise QAPIExprError(expr_info,
497 "Member of %s uses reserved name '%s'"
498 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600499 # Todo: allow dictionaries to represent default values of
500 # an optional argument.
Eric Blakedd883c62015-05-04 09:05:21 -0600501 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200502 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600503 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600504 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600505
Eric Blake437db252015-09-29 16:21:02 -0600506
507def check_member_clash(expr_info, base_name, data, source=""):
Eric Blakeff55d722015-05-04 09:05:37 -0600508 base = find_struct(base_name)
509 assert base
510 base_members = base['data']
511 for key in data.keys():
512 if key.startswith('*'):
513 key = key[1:]
514 if key in base_members or "*" + key in base_members:
515 raise QAPIExprError(expr_info,
516 "Member name '%s'%s clashes with base '%s'"
517 % (key, source, base_name))
518 if base.get('base'):
519 check_member_clash(expr_info, base['base'], data, source)
520
Eric Blake437db252015-09-29 16:21:02 -0600521
Eric Blakedd883c62015-05-04 09:05:21 -0600522def check_command(expr, expr_info):
523 name = expr['command']
Eric Blake2cbf0992015-05-04 09:05:24 -0600524
Eric Blakedd883c62015-05-04 09:05:21 -0600525 check_type(expr_info, "'data' for command '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600526 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200527 allow_metas=['struct'])
Eric Blake10d4d992015-05-04 09:05:23 -0600528 returns_meta = ['union', 'struct']
529 if name in returns_whitelist:
530 returns_meta += ['built-in', 'alternate', 'enum']
Eric Blakedd883c62015-05-04 09:05:21 -0600531 check_type(expr_info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200532 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200533 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600534
Eric Blake437db252015-09-29 16:21:02 -0600535
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200536def check_event(expr, expr_info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600537 global events
538 name = expr['event']
Eric Blake4dc2e692015-05-04 09:05:17 -0600539
540 if name.upper() == 'MAX':
541 raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
542 events.append(name)
Eric Blakedd883c62015-05-04 09:05:21 -0600543 check_type(expr_info, "'data' for event '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600544 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster315932b2015-07-01 10:12:24 +0200545 allow_metas=['struct'])
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200546
Eric Blake437db252015-09-29 16:21:02 -0600547
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800548def check_union(expr, expr_info):
549 name = expr['union']
550 base = expr.get('base')
551 discriminator = expr.get('discriminator')
552 members = expr['data']
Eric Blake61a94662015-11-18 01:52:49 -0700553 values = {'MAX': '(automatic)'}
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800554
Eric Blake811d04f2015-05-04 09:05:10 -0600555 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600556
557 # With no discriminator it is a simple union.
558 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600559 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600560 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600561 if base is not None:
562 raise QAPIExprError(expr_info,
Eric Blake811d04f2015-05-04 09:05:10 -0600563 "Simple union '%s' must not have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600564 % name)
565
566 # Else, it's a flat union.
567 else:
568 # The object must have a string member 'base'.
Eric Blake376863e2015-09-29 16:21:07 -0600569 check_type(expr_info, "'base' for union '%s'" % name,
570 base, allow_metas=['struct'])
571 if not base:
Eric Blake44bd1272015-05-04 09:05:08 -0600572 raise QAPIExprError(expr_info,
Eric Blake376863e2015-09-29 16:21:07 -0600573 "Flat union '%s' must have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600574 % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800575 base_fields = find_base_fields(base)
Eric Blake376863e2015-09-29 16:21:07 -0600576 assert base_fields
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800577
Eric Blakec9e0a792015-05-04 09:05:22 -0600578 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600579 # member of the base struct.
Eric Blakec9e0a792015-05-04 09:05:22 -0600580 check_name(expr_info, "Discriminator of flat union '%s'" % name,
581 discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800582 discriminator_type = base_fields.get(discriminator)
583 if not discriminator_type:
584 raise QAPIExprError(expr_info,
585 "Discriminator '%s' is not a member of base "
Eric Blakefd41dd42015-05-04 09:05:25 -0600586 "struct '%s'"
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800587 % (discriminator, base))
588 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600589 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800590 # Do not allow string discriminator
591 if not enum_define:
592 raise QAPIExprError(expr_info,
593 "Discriminator '%s' must be of enumeration "
594 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800595
596 # Check every branch
597 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600598 check_name(expr_info, "Member of union '%s'" % name, key)
599
Eric Blakedd883c62015-05-04 09:05:21 -0600600 # Each value must name a known type; furthermore, in flat unions,
Eric Blakeff55d722015-05-04 09:05:37 -0600601 # branches must be a struct with no overlapping member names
Eric Blakedd883c62015-05-04 09:05:21 -0600602 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200603 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakeff55d722015-05-04 09:05:37 -0600604 if base:
605 branch_struct = find_struct(value)
606 assert branch_struct
607 check_member_clash(expr_info, base, branch_struct['data'],
608 " of branch '%s'" % key)
Eric Blakedd883c62015-05-04 09:05:21 -0600609
Eric Blake44bd1272015-05-04 09:05:08 -0600610 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700611 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600612 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600613 if key not in enum_define['enum_values']:
Eric Blake44bd1272015-05-04 09:05:08 -0600614 raise QAPIExprError(expr_info,
615 "Discriminator value '%s' is not found in "
616 "enum '%s'" %
617 (key, enum_define["enum_name"]))
618
619 # Otherwise, check for conflicts in the generated enum
620 else:
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600621 c_key = camel_to_upper(key)
Eric Blake44bd1272015-05-04 09:05:08 -0600622 if c_key in values:
623 raise QAPIExprError(expr_info,
624 "Union '%s' member '%s' clashes with '%s'"
625 % (name, key, values[c_key]))
626 values[c_key] = key
627
Eric Blake437db252015-09-29 16:21:02 -0600628
Eric Blake811d04f2015-05-04 09:05:10 -0600629def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600630 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600631 members = expr['data']
Eric Blake437db252015-09-29 16:21:02 -0600632 values = {'MAX': '(automatic)'}
Eric Blake811d04f2015-05-04 09:05:10 -0600633 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600634
Eric Blake811d04f2015-05-04 09:05:10 -0600635 # Check every branch
636 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600637 check_name(expr_info, "Member of alternate '%s'" % name, key)
638
Eric Blake811d04f2015-05-04 09:05:10 -0600639 # Check for conflicts in the generated enum
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600640 c_key = camel_to_upper(key)
Eric Blake811d04f2015-05-04 09:05:10 -0600641 if c_key in values:
642 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600643 "Alternate '%s' member '%s' clashes with '%s'"
644 % (name, key, values[c_key]))
Eric Blake811d04f2015-05-04 09:05:10 -0600645 values[c_key] = key
646
647 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600648 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
649 value,
650 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600651 qtype = find_alternate_member_qtype(value)
Eric Blakedd883c62015-05-04 09:05:21 -0600652 assert qtype
Eric Blake811d04f2015-05-04 09:05:10 -0600653 if qtype in types_seen:
654 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600655 "Alternate '%s' member '%s' can't "
Eric Blake811d04f2015-05-04 09:05:10 -0600656 "be distinguished from member '%s'"
657 % (name, key, types_seen[qtype]))
658 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800659
Eric Blake437db252015-09-29 16:21:02 -0600660
Eric Blakecf393592015-05-04 09:05:04 -0600661def check_enum(expr, expr_info):
662 name = expr['enum']
663 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100664 prefix = expr.get('prefix')
Eric Blake437db252015-09-29 16:21:02 -0600665 values = {'MAX': '(automatic)'}
Eric Blakecf393592015-05-04 09:05:04 -0600666
667 if not isinstance(members, list):
668 raise QAPIExprError(expr_info,
669 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100670 if prefix is not None and not isinstance(prefix, str):
671 raise QAPIExprError(expr_info,
672 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600673 for member in members:
Eric Blake437db252015-09-29 16:21:02 -0600674 check_name(expr_info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600675 enum_member=True)
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600676 key = camel_to_upper(member)
Eric Blakecf393592015-05-04 09:05:04 -0600677 if key in values:
678 raise QAPIExprError(expr_info,
679 "Enum '%s' member '%s' clashes with '%s'"
680 % (name, member, values[key]))
681 values[key] = member
682
Eric Blake437db252015-09-29 16:21:02 -0600683
Eric Blakedd883c62015-05-04 09:05:21 -0600684def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600685 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600686 members = expr['data']
687
Eric Blakefd41dd42015-05-04 09:05:25 -0600688 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600689 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600690 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600691 allow_metas=['struct'])
Eric Blakeff55d722015-05-04 09:05:37 -0600692 if expr.get('base'):
693 check_member_clash(expr_info, expr['base'], expr['data'])
Eric Blakedd883c62015-05-04 09:05:21 -0600694
Eric Blake437db252015-09-29 16:21:02 -0600695
Eric Blake0545f6b2015-05-04 09:05:15 -0600696def check_keys(expr_elem, meta, required, optional=[]):
697 expr = expr_elem['expr']
698 info = expr_elem['info']
699 name = expr[meta]
700 if not isinstance(name, str):
701 raise QAPIExprError(info,
702 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600703 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600704 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600705 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600706 raise QAPIExprError(info,
707 "Unknown key '%s' in %s '%s'"
708 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600709 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600710 raise QAPIExprError(info,
711 "'%s' of %s '%s' should only use false value"
712 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600713 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600714 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600715 raise QAPIExprError(info,
716 "Key '%s' is missing from %s '%s'"
717 % (key, meta, name))
718
Eric Blake437db252015-09-29 16:21:02 -0600719
Markus Armbruster4d076d62015-06-10 08:55:21 +0200720def check_exprs(exprs):
721 global all_names
722
723 # Learn the types and check for valid expression keys
724 for builtin in builtin_types.keys():
725 all_names[builtin] = 'built-in'
726 for expr_elem in exprs:
727 expr = expr_elem['expr']
728 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600729 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100730 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200731 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600732 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200733 check_keys(expr_elem, 'union', ['data'],
734 ['base', 'discriminator'])
735 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600736 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200737 check_keys(expr_elem, 'alternate', ['data'])
738 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600739 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200740 check_keys(expr_elem, 'struct', ['data'], ['base'])
741 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600742 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200743 check_keys(expr_elem, 'command', [],
744 ['data', 'returns', 'gen', 'success-response'])
745 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600746 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200747 check_keys(expr_elem, 'event', [], ['data'])
748 add_name(expr['event'], info, 'event')
749 else:
750 raise QAPIExprError(expr_elem['info'],
751 "Expression is missing metatype")
752
753 # Try again for hidden UnionKind enum
754 for expr_elem in exprs:
755 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600756 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200757 if not discriminator_find_enum_define(expr):
758 add_enum('%sKind' % expr['union'], expr_elem['info'],
759 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600760 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200761 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
762 implicit=True)
763
764 # Validate that exprs make sense
765 for expr_elem in exprs:
766 expr = expr_elem['expr']
767 info = expr_elem['info']
768
Eric Blake437db252015-09-29 16:21:02 -0600769 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200770 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600771 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200772 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600773 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200774 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600775 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200776 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600777 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200778 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600779 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200780 check_event(expr, info)
781 else:
782 assert False, 'unexpected meta type'
783
Markus Armbrusterac882192015-09-16 13:06:05 +0200784 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600785
Markus Armbrusterac882192015-09-16 13:06:05 +0200786
787#
788# Schema compiler frontend
789#
790
791class QAPISchemaEntity(object):
792 def __init__(self, name, info):
793 assert isinstance(name, str)
794 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -0600795 # For explicitly defined entities, info points to the (explicit)
796 # definition. For builtins (and their arrays), info is None.
797 # For implicitly defined entities, info points to a place that
798 # triggered the implicit definition (there may be more than one
799 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +0200800 self.info = info
801
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200802 def c_name(self):
803 return c_name(self.name)
804
Markus Armbrusterac882192015-09-16 13:06:05 +0200805 def check(self, schema):
806 pass
807
Eric Blake49823c42015-10-12 22:22:27 -0600808 def is_implicit(self):
809 return not self.info
810
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200811 def visit(self, visitor):
812 pass
813
814
815class QAPISchemaVisitor(object):
816 def visit_begin(self, schema):
817 pass
818
819 def visit_end(self):
820 pass
821
Eric Blake25a0d9c2015-10-12 22:22:21 -0600822 def visit_needed(self, entity):
823 # Default to visiting everything
824 return True
825
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200826 def visit_builtin_type(self, name, info, json_type):
827 pass
828
829 def visit_enum_type(self, name, info, values, prefix):
830 pass
831
832 def visit_array_type(self, name, info, element_type):
833 pass
834
835 def visit_object_type(self, name, info, base, members, variants):
836 pass
837
Markus Armbruster39a18152015-09-16 13:06:28 +0200838 def visit_object_type_flat(self, name, info, members, variants):
839 pass
840
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200841 def visit_alternate_type(self, name, info, variants):
842 pass
843
844 def visit_command(self, name, info, arg_type, ret_type,
845 gen, success_response):
846 pass
847
848 def visit_event(self, name, info, arg_type):
849 pass
850
Markus Armbrusterac882192015-09-16 13:06:05 +0200851
852class QAPISchemaType(QAPISchemaEntity):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200853 def c_type(self, is_param=False):
854 return c_name(self.name) + pointer_suffix
855
856 def c_null(self):
857 return 'NULL'
858
859 def json_type(self):
860 pass
861
862 def alternate_qtype(self):
863 json2qtype = {
864 'string': 'QTYPE_QSTRING',
865 'number': 'QTYPE_QFLOAT',
866 'int': 'QTYPE_QINT',
867 'boolean': 'QTYPE_QBOOL',
868 'object': 'QTYPE_QDICT'
869 }
870 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200871
872
873class QAPISchemaBuiltinType(QAPISchemaType):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200874 def __init__(self, name, json_type, c_type, c_null):
Markus Armbrusterac882192015-09-16 13:06:05 +0200875 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200876 assert not c_type or isinstance(c_type, str)
877 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
878 'value')
879 self._json_type_name = json_type
880 self._c_type_name = c_type
881 self._c_null_val = c_null
882
883 def c_name(self):
884 return self.name
885
886 def c_type(self, is_param=False):
887 if is_param and self.name == 'str':
888 return 'const ' + self._c_type_name
889 return self._c_type_name
890
891 def c_null(self):
892 return self._c_null_val
893
894 def json_type(self):
895 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200896
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200897 def visit(self, visitor):
898 visitor.visit_builtin_type(self.name, self.info, self.json_type())
899
Markus Armbrusterac882192015-09-16 13:06:05 +0200900
901class QAPISchemaEnumType(QAPISchemaType):
902 def __init__(self, name, info, values, prefix):
903 QAPISchemaType.__init__(self, name, info)
904 for v in values:
905 assert isinstance(v, str)
906 assert prefix is None or isinstance(prefix, str)
907 self.values = values
908 self.prefix = prefix
909
910 def check(self, schema):
911 assert len(set(self.values)) == len(self.values)
912
Eric Blake99df5282015-10-12 22:22:32 -0600913 def is_implicit(self):
914 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -0600915 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -0600916
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200917 def c_type(self, is_param=False):
918 return c_name(self.name)
919
920 def c_null(self):
921 return c_enum_const(self.name, (self.values + ['MAX'])[0],
922 self.prefix)
923
924 def json_type(self):
925 return 'string'
926
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200927 def visit(self, visitor):
928 visitor.visit_enum_type(self.name, self.info,
929 self.values, self.prefix)
930
Markus Armbrusterac882192015-09-16 13:06:05 +0200931
932class QAPISchemaArrayType(QAPISchemaType):
933 def __init__(self, name, info, element_type):
934 QAPISchemaType.__init__(self, name, info)
935 assert isinstance(element_type, str)
936 self._element_type_name = element_type
937 self.element_type = None
938
939 def check(self, schema):
940 self.element_type = schema.lookup_type(self._element_type_name)
941 assert self.element_type
942
Eric Blake99df5282015-10-12 22:22:32 -0600943 def is_implicit(self):
944 return True
945
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200946 def json_type(self):
947 return 'array'
948
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200949 def visit(self, visitor):
950 visitor.visit_array_type(self.name, self.info, self.element_type)
951
Markus Armbrusterac882192015-09-16 13:06:05 +0200952
953class QAPISchemaObjectType(QAPISchemaType):
954 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -0700955 # struct has local_members, optional base, and no variants
956 # flat union has base, variants, and no local_members
957 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +0200958 QAPISchemaType.__init__(self, name, info)
959 assert base is None or isinstance(base, str)
960 for m in local_members:
961 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -0700962 m.set_owner(name)
963 if variants is not None:
964 assert isinstance(variants, QAPISchemaObjectTypeVariants)
965 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200966 self._base_name = base
967 self.base = None
968 self.local_members = local_members
969 self.variants = variants
970 self.members = None
971
972 def check(self, schema):
973 assert self.members is not False # not running in cycles
974 if self.members:
975 return
976 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -0700977 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +0200978 if self._base_name:
979 self.base = schema.lookup_type(self._base_name)
980 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +0200981 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700982 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200983 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -0700984 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700985 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700986 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +0200987 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -0700988 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700989 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -0700990 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200991
Eric Blake27b60ab2015-11-18 01:52:51 -0700992 # Check that the members of this type do not cause duplicate JSON fields,
993 # and update seen to track the members seen so far. Report any errors
994 # on behalf of info, which is not necessarily self.info
995 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -0700996 assert not self.variants # not implemented
997 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -0700998 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -0700999
Eric Blake99df5282015-10-12 22:22:32 -06001000 def is_implicit(self):
1001 # See QAPISchema._make_implicit_object_type()
1002 return self.name[0] == ':'
1003
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001004 def c_name(self):
Eric Blake49823c42015-10-12 22:22:27 -06001005 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001006 return QAPISchemaType.c_name(self)
1007
1008 def c_type(self, is_param=False):
Eric Blake49823c42015-10-12 22:22:27 -06001009 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001010 return QAPISchemaType.c_type(self)
1011
1012 def json_type(self):
1013 return 'object'
1014
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001015 def visit(self, visitor):
1016 visitor.visit_object_type(self.name, self.info,
1017 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001018 visitor.visit_object_type_flat(self.name, self.info,
1019 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001020
Markus Armbrusterac882192015-09-16 13:06:05 +02001021
1022class QAPISchemaObjectTypeMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001023 role = 'member'
1024
Markus Armbrusterac882192015-09-16 13:06:05 +02001025 def __init__(self, name, typ, optional):
1026 assert isinstance(name, str)
1027 assert isinstance(typ, str)
1028 assert isinstance(optional, bool)
1029 self.name = name
1030 self._type_name = typ
1031 self.type = None
1032 self.optional = optional
Eric Blake88d4ef82015-11-18 01:52:50 -07001033 self.owner = None
1034
1035 def set_owner(self, name):
1036 assert not self.owner
1037 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001038
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001039 def check(self, schema):
Eric Blake88d4ef82015-11-18 01:52:50 -07001040 assert self.owner
Markus Armbrusterac882192015-09-16 13:06:05 +02001041 self.type = schema.lookup_type(self._type_name)
1042 assert self.type
Markus Armbrusterac882192015-09-16 13:06:05 +02001043
Eric Blake27b60ab2015-11-18 01:52:51 -07001044 def check_clash(self, info, seen):
1045 cname = c_name(self.name)
1046 if cname in seen:
1047 raise QAPIExprError(info,
1048 "%s collides with %s"
1049 % (self.describe(), seen[cname].describe()))
1050 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001051
Eric Blake88d4ef82015-11-18 01:52:50 -07001052 def _pretty_owner(self):
1053 owner = self.owner
1054 if owner.startswith(':obj-'):
1055 # See QAPISchema._make_implicit_object_type() - reverse the
1056 # mapping there to create a nice human-readable description
1057 owner = owner[5:]
1058 if owner.endswith('-arg'):
1059 return '(parameter of %s)' % owner[:-4]
1060 else:
1061 assert owner.endswith('-wrapper')
1062 # Unreachable and not implemented
1063 assert False
1064 return '(%s of %s)' % (self.role, owner)
1065
1066 def describe(self):
1067 return "'%s' %s" % (self.name, self._pretty_owner())
1068
Markus Armbrusterac882192015-09-16 13:06:05 +02001069
1070class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001071 def __init__(self, tag_name, tag_member, variants):
1072 # Flat unions pass tag_name but not tag_member.
1073 # Simple unions and alternates pass tag_member but not tag_name.
1074 # After check(), tag_member is always set, and tag_name remains
1075 # a reliable witness of being used by a flat union.
1076 assert bool(tag_member) != bool(tag_name)
1077 assert (isinstance(tag_name, str) or
1078 isinstance(tag_member, QAPISchemaObjectTypeMember))
Markus Armbrusterac882192015-09-16 13:06:05 +02001079 for v in variants:
1080 assert isinstance(v, QAPISchemaObjectTypeVariant)
1081 self.tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001082 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001083 self.variants = variants
1084
Eric Blake88d4ef82015-11-18 01:52:50 -07001085 def set_owner(self, name):
1086 for v in self.variants:
1087 v.set_owner(name)
1088
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001089 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001090 if not self.tag_member: # flat union
Eric Blake27b60ab2015-11-18 01:52:51 -07001091 self.tag_member = seen[c_name(self.tag_name)]
1092 assert self.tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001093 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1094 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001095 v.check(schema)
1096 assert v.name in self.tag_member.type.values
Eric Blakeb807a1e2015-11-18 01:52:46 -07001097 if isinstance(v.type, QAPISchemaObjectType):
1098 v.type.check(schema)
1099
Eric Blake27b60ab2015-11-18 01:52:51 -07001100 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001101 for v in self.variants:
1102 # Reset seen map for each variant, since qapi names from one
1103 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001104 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001105 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001106
Eric Blake437db252015-09-29 16:21:02 -06001107
Markus Armbrusterac882192015-09-16 13:06:05 +02001108class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001109 role = 'branch'
1110
Markus Armbrusterac882192015-09-16 13:06:05 +02001111 def __init__(self, name, typ):
1112 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1113
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001114 # This function exists to support ugly simple union special cases
1115 # TODO get rid of them, and drop the function
1116 def simple_union_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001117 if (self.type.is_implicit() and
1118 isinstance(self.type, QAPISchemaObjectType)):
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001119 assert len(self.type.members) == 1
1120 assert not self.type.variants
1121 return self.type.members[0].type
1122 return None
1123
Markus Armbrusterac882192015-09-16 13:06:05 +02001124
1125class QAPISchemaAlternateType(QAPISchemaType):
1126 def __init__(self, name, info, variants):
1127 QAPISchemaType.__init__(self, name, info)
1128 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1129 assert not variants.tag_name
Eric Blake88d4ef82015-11-18 01:52:50 -07001130 variants.set_owner(name)
1131 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001132 self.variants = variants
1133
1134 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001135 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001136 # Not calling self.variants.check_clash(), because there's nothing
1137 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001138 self.variants.check(schema, {})
Markus Armbrusterac882192015-09-16 13:06:05 +02001139
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001140 def json_type(self):
1141 return 'value'
1142
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001143 def visit(self, visitor):
1144 visitor.visit_alternate_type(self.name, self.info, self.variants)
1145
Markus Armbrusterac882192015-09-16 13:06:05 +02001146
1147class QAPISchemaCommand(QAPISchemaEntity):
1148 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1149 QAPISchemaEntity.__init__(self, name, info)
1150 assert not arg_type or isinstance(arg_type, str)
1151 assert not ret_type or isinstance(ret_type, str)
1152 self._arg_type_name = arg_type
1153 self.arg_type = None
1154 self._ret_type_name = ret_type
1155 self.ret_type = None
1156 self.gen = gen
1157 self.success_response = success_response
1158
1159 def check(self, schema):
1160 if self._arg_type_name:
1161 self.arg_type = schema.lookup_type(self._arg_type_name)
1162 assert isinstance(self.arg_type, QAPISchemaObjectType)
1163 assert not self.arg_type.variants # not implemented
1164 if self._ret_type_name:
1165 self.ret_type = schema.lookup_type(self._ret_type_name)
1166 assert isinstance(self.ret_type, QAPISchemaType)
1167
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001168 def visit(self, visitor):
1169 visitor.visit_command(self.name, self.info,
1170 self.arg_type, self.ret_type,
1171 self.gen, self.success_response)
1172
Markus Armbrusterac882192015-09-16 13:06:05 +02001173
1174class QAPISchemaEvent(QAPISchemaEntity):
1175 def __init__(self, name, info, arg_type):
1176 QAPISchemaEntity.__init__(self, name, info)
1177 assert not arg_type or isinstance(arg_type, str)
1178 self._arg_type_name = arg_type
1179 self.arg_type = None
1180
1181 def check(self, schema):
1182 if self._arg_type_name:
1183 self.arg_type = schema.lookup_type(self._arg_type_name)
1184 assert isinstance(self.arg_type, QAPISchemaObjectType)
1185 assert not self.arg_type.variants # not implemented
1186
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001187 def visit(self, visitor):
1188 visitor.visit_event(self.name, self.info, self.arg_type)
1189
Markus Armbrusterac882192015-09-16 13:06:05 +02001190
1191class QAPISchema(object):
1192 def __init__(self, fname):
1193 try:
1194 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001195 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001196 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001197 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001198 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001199 self._def_exprs()
1200 self.check()
Markus Armbrusterac882192015-09-16 13:06:05 +02001201 except (QAPISchemaError, QAPIExprError), err:
1202 print >>sys.stderr, err
1203 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001204
Markus Armbrusterac882192015-09-16 13:06:05 +02001205 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001206 # Only the predefined types are allowed to not have info
1207 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001208 assert ent.name not in self._entity_dict
1209 self._entity_dict[ent.name] = ent
1210
1211 def lookup_entity(self, name, typ=None):
1212 ent = self._entity_dict.get(name)
1213 if typ and not isinstance(ent, typ):
1214 return None
1215 return ent
1216
1217 def lookup_type(self, name):
1218 return self.lookup_entity(name, QAPISchemaType)
1219
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001220 def _def_builtin_type(self, name, json_type, c_type, c_null):
1221 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1222 c_type, c_null))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001223 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1224 # qapi-types.h from a single .c, all arrays of builtins must be
1225 # declared in the first file whether or not they are used. Nicer
1226 # would be to use lazy instantiation, while figuring out how to
1227 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001228 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001229
1230 def _def_predefineds(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001231 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1232 ('number', 'number', 'double', '0'),
1233 ('int', 'int', 'int64_t', '0'),
1234 ('int8', 'int', 'int8_t', '0'),
1235 ('int16', 'int', 'int16_t', '0'),
1236 ('int32', 'int', 'int32_t', '0'),
1237 ('int64', 'int', 'int64_t', '0'),
1238 ('uint8', 'int', 'uint8_t', '0'),
1239 ('uint16', 'int', 'uint16_t', '0'),
1240 ('uint32', 'int', 'uint32_t', '0'),
1241 ('uint64', 'int', 'uint64_t', '0'),
1242 ('size', 'int', 'uint64_t', '0'),
1243 ('bool', 'boolean', 'bool', 'false'),
Markus Armbruster28770e02015-09-16 13:06:24 +02001244 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001245 self._def_builtin_type(*t)
Markus Armbruster39a18152015-09-16 13:06:28 +02001246 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1247 [], None)
1248 self._def_entity(self.the_empty_object_type)
Markus Armbrusterac882192015-09-16 13:06:05 +02001249
Eric Blake99df5282015-10-12 22:22:32 -06001250 def _make_implicit_enum_type(self, name, info, values):
Eric Blake49823c42015-10-12 22:22:27 -06001251 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake99df5282015-10-12 22:22:32 -06001252 self._def_entity(QAPISchemaEnumType(name, info, values, None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001253 return name
1254
Eric Blake99df5282015-10-12 22:22:32 -06001255 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001256 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001257 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001258 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001259 return name
1260
Eric Blake99df5282015-10-12 22:22:32 -06001261 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001262 if not members:
1263 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001264 # See also QAPISchemaObjectTypeMember._pretty_owner()
Markus Armbrusterac882192015-09-16 13:06:05 +02001265 name = ':obj-%s-%s' % (name, role)
1266 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001267 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001268 members, None))
1269 return name
1270
1271 def _def_enum_type(self, expr, info):
1272 name = expr['enum']
1273 data = expr['data']
1274 prefix = expr.get('prefix')
1275 self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001276
Eric Blake99df5282015-10-12 22:22:32 -06001277 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001278 optional = False
1279 if name.startswith('*'):
1280 name = name[1:]
1281 optional = True
1282 if isinstance(typ, list):
1283 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001284 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001285 return QAPISchemaObjectTypeMember(name, typ, optional)
1286
Eric Blake99df5282015-10-12 22:22:32 -06001287 def _make_members(self, data, info):
1288 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001289 for (key, value) in data.iteritems()]
1290
1291 def _def_struct_type(self, expr, info):
1292 name = expr['struct']
1293 base = expr.get('base')
1294 data = expr['data']
1295 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001296 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001297 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001298
1299 def _make_variant(self, case, typ):
1300 return QAPISchemaObjectTypeVariant(case, typ)
1301
Eric Blake99df5282015-10-12 22:22:32 -06001302 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001303 if isinstance(typ, list):
1304 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001305 typ = self._make_array_type(typ[0], info)
1306 typ = self._make_implicit_object_type(
1307 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001308 return QAPISchemaObjectTypeVariant(case, typ)
1309
Eric Blake99df5282015-10-12 22:22:32 -06001310 def _make_implicit_tag(self, type_name, info, variants):
1311 typ = self._make_implicit_enum_type(type_name, info,
Eric Blake46292ba2015-10-12 22:22:29 -06001312 [v.name for v in variants])
1313 return QAPISchemaObjectTypeMember('type', typ, False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001314
1315 def _def_union_type(self, expr, info):
1316 name = expr['union']
1317 data = expr['data']
1318 base = expr.get('base')
1319 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001320 tag_member = None
Markus Armbrusterac882192015-09-16 13:06:05 +02001321 if tag_name:
1322 variants = [self._make_variant(key, value)
1323 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001324 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001325 else:
Eric Blake99df5282015-10-12 22:22:32 -06001326 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001327 for (key, value) in data.iteritems()]
Eric Blake99df5282015-10-12 22:22:32 -06001328 tag_member = self._make_implicit_tag(name, info, variants)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001329 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001330 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001331 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001332 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001333 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001334 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001335
1336 def _def_alternate_type(self, expr, info):
1337 name = expr['alternate']
1338 data = expr['data']
1339 variants = [self._make_variant(key, value)
1340 for (key, value) in data.iteritems()]
Eric Blake99df5282015-10-12 22:22:32 -06001341 tag_member = self._make_implicit_tag(name, info, variants)
Markus Armbrusterac882192015-09-16 13:06:05 +02001342 self._def_entity(
1343 QAPISchemaAlternateType(name, info,
1344 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001345 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001346 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001347
1348 def _def_command(self, expr, info):
1349 name = expr['command']
1350 data = expr.get('data')
1351 rets = expr.get('returns')
1352 gen = expr.get('gen', True)
1353 success_response = expr.get('success-response', True)
1354 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001355 data = self._make_implicit_object_type(
1356 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001357 if isinstance(rets, list):
1358 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001359 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001360 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1361 success_response))
1362
1363 def _def_event(self, expr, info):
1364 name = expr['event']
1365 data = expr.get('data')
1366 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001367 data = self._make_implicit_object_type(
1368 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001369 self._def_entity(QAPISchemaEvent(name, info, data))
1370
1371 def _def_exprs(self):
1372 for expr_elem in self.exprs:
1373 expr = expr_elem['expr']
1374 info = expr_elem['info']
1375 if 'enum' in expr:
1376 self._def_enum_type(expr, info)
1377 elif 'struct' in expr:
1378 self._def_struct_type(expr, info)
1379 elif 'union' in expr:
1380 self._def_union_type(expr, info)
1381 elif 'alternate' in expr:
1382 self._def_alternate_type(expr, info)
1383 elif 'command' in expr:
1384 self._def_command(expr, info)
1385 elif 'event' in expr:
1386 self._def_event(expr, info)
1387 else:
1388 assert False
1389
1390 def check(self):
1391 for ent in self._entity_dict.values():
1392 ent.check(self)
1393
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001394 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001395 visitor.visit_begin(self)
1396 for (name, entity) in sorted(self._entity_dict.items()):
1397 if visitor.visit_needed(entity):
1398 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001399 visitor.visit_end()
1400
Markus Armbruster2caba362013-07-27 17:41:56 +02001401
Markus Armbruster00e4b282015-06-10 10:04:36 +02001402#
1403# Code generation helpers
1404#
1405
Michael Roth0f923be2011-07-19 14:50:39 -05001406def camel_case(name):
1407 new_name = ''
1408 first = True
1409 for ch in name:
1410 if ch in ['_', '-']:
1411 first = True
1412 elif first:
1413 new_name += ch.upper()
1414 first = False
1415 else:
1416 new_name += ch.lower()
1417 return new_name
1418
Eric Blake437db252015-09-29 16:21:02 -06001419
Markus Armbruster849bc532015-05-14 06:50:53 -06001420# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1421# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1422# ENUM24_Name -> ENUM24_NAME
1423def camel_to_upper(value):
1424 c_fun_str = c_name(value, False)
1425 if value.isupper():
1426 return c_fun_str
1427
1428 new_name = ''
1429 l = len(c_fun_str)
1430 for i in range(l):
1431 c = c_fun_str[i]
1432 # When c is upper and no "_" appears before, do more checks
1433 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001434 if i < l - 1 and c_fun_str[i + 1].islower():
1435 new_name += '_'
1436 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001437 new_name += '_'
1438 new_name += c
1439 return new_name.lstrip('_').upper()
1440
Eric Blake437db252015-09-29 16:21:02 -06001441
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001442def c_enum_const(type_name, const_name, prefix=None):
1443 if prefix is not None:
1444 type_name = prefix
Markus Armbruster849bc532015-05-14 06:50:53 -06001445 return camel_to_upper(type_name + '_' + const_name)
1446
Eric Blake18df5152015-05-14 06:50:48 -06001447c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001448
Eric Blake437db252015-09-29 16:21:02 -06001449
Eric Blakec6405b52015-05-14 06:50:55 -06001450# Map @name to a valid C identifier.
1451# If @protect, avoid returning certain ticklish identifiers (like
1452# C keywords) by prepending "q_".
1453#
1454# Used for converting 'name' from a 'name':'type' qapi definition
1455# into a generated struct member, as well as converting type names
1456# into substrings of a generated C function name.
1457# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1458# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001459def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001460 # ANSI X3J11/88-090, 3.1.1
1461 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001462 'default', 'do', 'double', 'else', 'enum', 'extern',
1463 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1464 'return', 'short', 'signed', 'sizeof', 'static',
1465 'struct', 'switch', 'typedef', 'union', 'unsigned',
1466 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001467 # ISO/IEC 9899:1999, 6.4.1
1468 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1469 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001470 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1471 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001472 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1473 # excluding _.*
1474 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001475 # C++ ISO/IEC 14882:2003 2.11
1476 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1477 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1478 'namespace', 'new', 'operator', 'private', 'protected',
1479 'public', 'reinterpret_cast', 'static_cast', 'template',
1480 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1481 'using', 'virtual', 'wchar_t',
1482 # alternative representations
1483 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1484 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001485 # namespace pollution:
Max Reitz8592a542013-12-20 19:28:18 +01001486 polluted_words = set(['unix', 'errno'])
Eric Blakec43567c2015-11-18 01:52:52 -07001487 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001488 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1489 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001490 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001491 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001492
Amos Kong05dfb262014-06-10 19:25:53 +08001493eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001494pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001495
Eric Blake437db252015-09-29 16:21:02 -06001496
Michael Roth0f923be2011-07-19 14:50:39 -05001497def genindent(count):
1498 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001499 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001500 ret += " "
1501 return ret
1502
1503indent_level = 0
1504
Eric Blake437db252015-09-29 16:21:02 -06001505
Michael Roth0f923be2011-07-19 14:50:39 -05001506def push_indent(indent_amount=4):
1507 global indent_level
1508 indent_level += indent_amount
1509
Eric Blake437db252015-09-29 16:21:02 -06001510
Michael Roth0f923be2011-07-19 14:50:39 -05001511def pop_indent(indent_amount=4):
1512 global indent_level
1513 indent_level -= indent_amount
1514
Eric Blake437db252015-09-29 16:21:02 -06001515
Markus Armbruster77e703b2015-06-24 19:27:32 +02001516# Generate @code with @kwds interpolated.
1517# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001518def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001519 raw = code % kwds
1520 if indent_level:
1521 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001522 # re.subn() lacks flags support before Python 2.7, use re.compile()
1523 raw = re.subn(re.compile("^.", re.MULTILINE),
1524 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001525 raw = raw[0]
1526 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001527
Eric Blake437db252015-09-29 16:21:02 -06001528
Michael Roth0f923be2011-07-19 14:50:39 -05001529def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001530 if code[0] == '\n':
1531 code = code[1:]
1532 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001533
Michael Roth0f923be2011-07-19 14:50:39 -05001534
1535def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001536 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001537
Eric Blake437db252015-09-29 16:21:02 -06001538
Michael Rothc0afa9c2013-05-10 17:46:00 -05001539def guardstart(name):
1540 return mcgen('''
1541
1542#ifndef %(name)s
1543#define %(name)s
1544
1545''',
1546 name=guardname(name))
1547
Eric Blake437db252015-09-29 16:21:02 -06001548
Michael Rothc0afa9c2013-05-10 17:46:00 -05001549def guardend(name):
1550 return mcgen('''
1551
1552#endif /* %(name)s */
1553
1554''',
1555 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001556
Eric Blake437db252015-09-29 16:21:02 -06001557
Markus Armbrustere98859a2015-09-16 13:06:16 +02001558def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001559 ret = mcgen('''
1560
Markus Armbrustere98859a2015-09-16 13:06:16 +02001561const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001562''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001563 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001564 for value in values:
1565 index = c_enum_const(name, value, prefix)
1566 ret += mcgen('''
1567 [%(index)s] = "%(value)s",
1568''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001569 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001570
1571 max_index = c_enum_const(name, 'MAX', prefix)
1572 ret += mcgen('''
1573 [%(max_index)s] = NULL,
1574};
1575''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001576 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001577 return ret
1578
Eric Blake437db252015-09-29 16:21:02 -06001579
Markus Armbrustere98859a2015-09-16 13:06:16 +02001580def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001581 # append automatically generated _MAX value
Markus Armbrustere98859a2015-09-16 13:06:16 +02001582 enum_values = values + ['MAX']
1583
1584 ret = mcgen('''
1585
1586typedef enum %(c_name)s {
1587''',
1588 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001589
1590 i = 0
1591 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001592 ret += mcgen('''
1593 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001594''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001595 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001596 i=i)
1597 i += 1
1598
Markus Armbrustere98859a2015-09-16 13:06:16 +02001599 ret += mcgen('''
1600} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001601''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001602 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001603
Markus Armbrustere98859a2015-09-16 13:06:16 +02001604 ret += mcgen('''
1605
1606extern const char *const %(c_name)s_lookup[];
1607''',
1608 c_name=c_name(name))
1609 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001610
Eric Blake437db252015-09-29 16:21:02 -06001611
Markus Armbruster03b43672015-09-16 13:06:20 +02001612def gen_params(arg_type, extra):
1613 if not arg_type:
1614 return extra
1615 assert not arg_type.variants
1616 ret = ''
1617 sep = ''
1618 for memb in arg_type.members:
1619 ret += sep
1620 sep = ', '
1621 if memb.optional:
1622 ret += 'bool has_%s, ' % c_name(memb.name)
1623 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1624 if extra:
1625 ret += sep + extra
1626 return ret
1627
Eric Blake1f353342015-09-29 16:21:13 -06001628
Eric Blake18bdbc32015-09-29 16:21:15 -06001629def gen_err_check(label='out', skiperr=False):
1630 if skiperr:
Eric Blake1f353342015-09-29 16:21:13 -06001631 return ''
1632 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001633 if (err) {
Eric Blake1f353342015-09-29 16:21:13 -06001634 goto %(label)s;
1635 }
1636''',
Eric Blake18bdbc32015-09-29 16:21:15 -06001637 label=label)
Eric Blake1f353342015-09-29 16:21:13 -06001638
1639
Eric Blake18bdbc32015-09-29 16:21:15 -06001640def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
Eric Blake82ca8e42015-09-29 16:21:14 -06001641 ret = ''
Eric Blake18bdbc32015-09-29 16:21:15 -06001642 if skiperr:
Eric Blake82ca8e42015-09-29 16:21:14 -06001643 errparg = 'NULL'
Eric Blake18bdbc32015-09-29 16:21:15 -06001644 else:
1645 errparg = '&err'
Eric Blake82ca8e42015-09-29 16:21:14 -06001646
1647 for memb in members:
1648 if memb.optional:
1649 ret += mcgen('''
1650 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1651''',
1652 prefix=prefix, c_name=c_name(memb.name),
1653 name=memb.name, errp=errparg)
Eric Blake18bdbc32015-09-29 16:21:15 -06001654 ret += gen_err_check(skiperr=skiperr)
Eric Blake82ca8e42015-09-29 16:21:14 -06001655 ret += mcgen('''
1656 if (%(prefix)shas_%(c_name)s) {
1657''',
1658 prefix=prefix, c_name=c_name(memb.name))
1659 push_indent()
1660
1661 # Ugly: sometimes we need to cast away const
1662 if need_cast and memb.type.name == 'str':
1663 cast = '(char **)'
1664 else:
1665 cast = ''
1666
1667 ret += mcgen('''
1668 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1669''',
1670 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1671 c_name=c_name(memb.name), name=memb.name,
1672 errp=errparg)
Eric Blake18bdbc32015-09-29 16:21:15 -06001673 ret += gen_err_check(skiperr=skiperr)
Eric Blake82ca8e42015-09-29 16:21:14 -06001674
1675 if memb.optional:
1676 pop_indent()
1677 ret += mcgen('''
1678 }
1679''')
1680 return ret
1681
1682
Markus Armbruster00e4b282015-06-10 10:04:36 +02001683#
1684# Common command line parsing
1685#
1686
Eric Blake437db252015-09-29 16:21:02 -06001687
1688def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001689
1690 try:
1691 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001692 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001693 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001694 "output-dir="] + extra_long_options)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001695 except getopt.GetoptError, err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001696 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001697 sys.exit(1)
1698
1699 output_dir = ""
1700 prefix = ""
1701 do_c = False
1702 do_h = False
1703 extra_opts = []
1704
1705 for oa in opts:
1706 o, a = oa
1707 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001708 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1709 if match.end() != len(a):
1710 print >>sys.stderr, \
1711 "%s: 'funny character '%s' in argument of --prefix" \
1712 % (sys.argv[0], a[match.end()])
1713 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001714 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001715 elif o in ("-o", "--output-dir"):
1716 output_dir = a + "/"
1717 elif o in ("-c", "--source"):
1718 do_c = True
1719 elif o in ("-h", "--header"):
1720 do_h = True
1721 else:
1722 extra_opts.append(oa)
1723
1724 if not do_c and not do_h:
1725 do_c = True
1726 do_h = True
1727
Markus Armbruster16d80f62015-04-02 13:32:16 +02001728 if len(args) != 1:
1729 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001730 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001731 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001732
Markus Armbruster54414042015-06-09 16:22:45 +02001733 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001734
Markus Armbruster00e4b282015-06-10 10:04:36 +02001735#
1736# Generate output files with boilerplate
1737#
1738
Eric Blake437db252015-09-29 16:21:02 -06001739
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001740def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1741 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001742 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001743 c_file = output_dir + prefix + c_file
1744 h_file = output_dir + prefix + h_file
1745
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001746 if output_dir:
1747 try:
1748 os.makedirs(output_dir)
1749 except os.error, e:
1750 if e.errno != errno.EEXIST:
1751 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001752
1753 def maybe_open(really, name, opt):
1754 if really:
1755 return open(name, opt)
1756 else:
1757 import StringIO
1758 return StringIO.StringIO()
1759
1760 fdef = maybe_open(do_c, c_file, 'w')
1761 fdecl = maybe_open(do_h, h_file, 'w')
1762
1763 fdef.write(mcgen('''
1764/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1765%(comment)s
1766''',
Eric Blake437db252015-09-29 16:21:02 -06001767 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001768
1769 fdecl.write(mcgen('''
1770/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1771%(comment)s
1772#ifndef %(guard)s
1773#define %(guard)s
1774
1775''',
Eric Blake437db252015-09-29 16:21:02 -06001776 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001777
1778 return (fdef, fdecl)
1779
Eric Blake437db252015-09-29 16:21:02 -06001780
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001781def close_output(fdef, fdecl):
1782 fdecl.write('''
1783#endif
1784''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001785 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001786 fdef.close()