blob: 8edfd79c5220865fc76604e387ac2ef8ff595eda [file] [log] [blame]
Michael Roth0f923be2011-07-19 14:50:39 -05001#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
Eric Blakefe2a9302015-05-04 09:05:02 -06005# Copyright (c) 2013-2015 Red Hat Inc.
Michael Roth0f923be2011-07-19 14:50:39 -05006#
7# Authors:
8# Anthony Liguori <aliguori@us.ibm.com>
Markus Armbrusterc7a3f252013-07-27 17:41:55 +02009# Markus Armbruster <armbru@redhat.com>
Michael Roth0f923be2011-07-19 14:50:39 -050010#
Markus Armbruster678e48a2014-03-01 08:40:34 +010011# This work is licensed under the terms of the GNU GPL, version 2.
12# See the COPYING file in the top-level directory.
Michael Roth0f923be2011-07-19 14:50:39 -050013
Lluís Vilanovaa719a272014-05-07 20:46:15 +020014import re
Michael Roth0f923be2011-07-19 14:50:39 -050015from ordereddict import OrderedDict
Markus Armbruster12f8e1b2015-04-02 14:46:39 +020016import errno
Markus Armbruster2114f5a2015-04-02 13:12:21 +020017import getopt
Lluís Vilanova33aaad52014-05-02 15:52:35 +020018import os
Markus Armbruster2caba362013-07-27 17:41:56 +020019import sys
Markus Armbruster47299262015-05-14 06:50:47 -060020import string
Michael Roth0f923be2011-07-19 14:50:39 -050021
Eric Blakeb52c4b92015-05-04 09:05:00 -060022builtin_types = {
Kevin Wolf69dd62d2013-07-08 16:14:21 +020023 'str': 'QTYPE_QSTRING',
24 'int': 'QTYPE_QINT',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
27 'int8': 'QTYPE_QINT',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
Eric Blakecb17f792015-05-04 09:05:01 -060035 'size': 'QTYPE_QINT',
Eric Blake1310a3d2015-12-01 22:20:46 -070036 'any': None, # any QType possible, actually
Eric Blake7264f5c2015-12-01 22:20:47 -070037 'QType': 'QTYPE_QSTRING',
Kevin Wolf69dd62d2013-07-08 16:14:21 +020038}
39
Eric Blake10d4d992015-05-04 09:05:23 -060040# Whitelist of commands allowed to return a non-dictionary
41returns_whitelist = [
42 # From QMP:
43 'human-monitor-command',
Markus Armbruster6eb39372015-09-16 13:06:25 +020044 'qom-get',
Eric Blake10d4d992015-05-04 09:05:23 -060045 'query-migrate-cache-size',
46 'query-tpm-models',
47 'query-tpm-types',
48 'ringbuf-read',
49
50 # From QGA:
51 'guest-file-open',
52 'guest-fsfreeze-freeze',
53 'guest-fsfreeze-freeze-list',
54 'guest-fsfreeze-status',
55 'guest-fsfreeze-thaw',
56 'guest-get-time',
57 'guest-set-vcpus',
58 'guest-sync',
59 'guest-sync-delimited',
Eric Blake10d4d992015-05-04 09:05:23 -060060]
61
Eric Blake893e1f22015-12-01 22:20:57 -070062# Whitelist of entities allowed to violate case conventions
63case_whitelist = [
64 # From QMP:
65 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
66 'CpuInfoBase', # CPU, visible through query-cpu
67 'CpuInfoMIPS', # PC, visible through query-cpu
68 'CpuInfoTricore', # PC, visible through query-cpu
69 'InputAxis', # TODO: drop when x-input-send-event is fixed
70 'InputButton', # TODO: drop when x-input-send-event is fixed
71 'QapiErrorClass', # all members, visible through errors
72 'UuidInfo', # UUID, visible through query-uuid
73 'X86CPURegister32', # all members, visible indirectly through qom-get
74]
75
Eric Blake4dc2e692015-05-04 09:05:17 -060076enum_types = []
77struct_types = []
78union_types = []
79events = []
80all_names = {}
81
Markus Armbruster00e4b282015-06-10 10:04:36 +020082#
83# Parsing the schema into expressions
84#
85
Eric Blake437db252015-09-29 16:21:02 -060086
Lluís Vilanovaa719a272014-05-07 20:46:15 +020087def error_path(parent):
88 res = ""
89 while parent:
90 res = ("In file included from %s:%d:\n" % (parent['file'],
91 parent['line'])) + res
92 parent = parent['parent']
93 return res
94
Eric Blake437db252015-09-29 16:21:02 -060095
Markus Armbruster2caba362013-07-27 17:41:56 +020096class QAPISchemaError(Exception):
97 def __init__(self, schema, msg):
Eric Blake59b00542015-09-29 16:21:01 -060098 Exception.__init__(self)
Markus Armbruster54414042015-06-09 16:22:45 +020099 self.fname = schema.fname
Markus Armbruster2caba362013-07-27 17:41:56 +0200100 self.msg = msg
Wenchao Xia515b9432014-03-04 18:44:33 -0800101 self.col = 1
102 self.line = schema.line
103 for ch in schema.src[schema.line_pos:schema.pos]:
104 if ch == '\t':
Markus Armbruster2caba362013-07-27 17:41:56 +0200105 self.col = (self.col + 7) % 8 + 1
106 else:
107 self.col += 1
Markus Armbruster54414042015-06-09 16:22:45 +0200108 self.info = schema.incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +0200109
110 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200111 return error_path(self.info) + \
Markus Armbruster54414042015-06-09 16:22:45 +0200112 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
Markus Armbruster2caba362013-07-27 17:41:56 +0200113
Eric Blake437db252015-09-29 16:21:02 -0600114
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800115class QAPIExprError(Exception):
116 def __init__(self, expr_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -0600117 Exception.__init__(self)
Eric Blake7618b912015-10-12 22:22:22 -0600118 assert expr_info
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200119 self.info = expr_info
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800120 self.msg = msg
121
122 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200123 return error_path(self.info['parent']) + \
124 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800125
Eric Blake437db252015-09-29 16:21:02 -0600126
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200127class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500128
Eric Blake437db252015-09-29 16:21:02 -0600129 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200130 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200131 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200132 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200133 previously_included.append(abs_fname)
134 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200135 self.src = fp.read()
136 if self.src == '' or self.src[-1] != '\n':
137 self.src += '\n'
138 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800139 self.line = 1
140 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200141 self.exprs = []
142 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500143
Eric Blake437db252015-09-29 16:21:02 -0600144 while self.tok is not None:
Markus Armbruster54414042015-06-09 16:22:45 +0200145 expr_info = {'file': fname, 'line': self.line,
146 'parent': self.incl_info}
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200147 expr = self.get_expr(False)
148 if isinstance(expr, dict) and "include" in expr:
149 if len(expr) != 1:
Eric Blake437db252015-09-29 16:21:02 -0600150 raise QAPIExprError(expr_info,
151 "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200152 include = expr["include"]
153 if not isinstance(include, str):
154 raise QAPIExprError(expr_info,
Eric Blake7408fb62015-09-29 16:21:00 -0600155 "Value of 'include' must be a string")
Markus Armbruster54414042015-06-09 16:22:45 +0200156 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
157 include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200158 # catch inclusion cycle
159 inf = expr_info
160 while inf:
161 if incl_abs_fname == os.path.abspath(inf['file']):
Stefan Hajnoczi7ac9a9d2014-08-27 12:08:51 +0100162 raise QAPIExprError(expr_info, "Inclusion loop for %s"
163 % include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200164 inf = inf['parent']
Benoît Canet24fd8482014-05-16 12:51:56 +0200165 # skip multiple include of the same file
Markus Armbruster54414042015-06-09 16:22:45 +0200166 if incl_abs_fname in previously_included:
Benoît Canet24fd8482014-05-16 12:51:56 +0200167 continue
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200168 try:
Markus Armbruster54414042015-06-09 16:22:45 +0200169 fobj = open(incl_abs_fname, 'r')
Luiz Capitulino34788812014-05-20 13:50:19 -0400170 except IOError, e:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200171 raise QAPIExprError(expr_info,
172 '%s: %s' % (e.strerror, include))
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200173 exprs_include = QAPISchemaParser(fobj, previously_included,
174 expr_info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200175 self.exprs.extend(exprs_include.exprs)
176 else:
177 expr_elem = {'expr': expr,
178 'info': expr_info}
179 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500180
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200181 def accept(self):
182 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200183 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200184 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200185 self.cursor += 1
186 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500187
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200188 if self.tok == '#':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200189 self.cursor = self.src.find('\n', self.cursor)
Eric Blake8712fa52015-10-26 16:34:41 -0600190 elif self.tok in "{}:,[]":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200191 return
192 elif self.tok == "'":
193 string = ''
194 esc = False
195 while True:
196 ch = self.src[self.cursor]
197 self.cursor += 1
198 if ch == '\n':
Markus Armbruster2caba362013-07-27 17:41:56 +0200199 raise QAPISchemaError(self,
200 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200201 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600202 if ch == 'b':
203 string += '\b'
204 elif ch == 'f':
205 string += '\f'
206 elif ch == 'n':
207 string += '\n'
208 elif ch == 'r':
209 string += '\r'
210 elif ch == 't':
211 string += '\t'
212 elif ch == 'u':
213 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600214 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600215 ch = self.src[self.cursor]
216 self.cursor += 1
217 if ch not in "0123456789abcdefABCDEF":
218 raise QAPISchemaError(self,
219 '\\u escape needs 4 '
220 'hex digits')
221 value = (value << 4) + int(ch, 16)
222 # If Python 2 and 3 didn't disagree so much on
223 # how to handle Unicode, then we could allow
224 # Unicode string defaults. But most of QAPI is
225 # ASCII-only, so we aren't losing much for now.
226 if not value or value > 0x7f:
227 raise QAPISchemaError(self,
228 'For now, \\u escape '
229 'only supports non-zero '
230 'values up to \\u007f')
231 string += chr(value)
232 elif ch in "\\/'\"":
233 string += ch
234 else:
235 raise QAPISchemaError(self,
Eric Blake437db252015-09-29 16:21:02 -0600236 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200237 esc = False
238 elif ch == "\\":
239 esc = True
240 elif ch == "'":
241 self.val = string
242 return
243 else:
244 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200245 elif self.src.startswith("true", self.pos):
246 self.val = True
247 self.cursor += 3
248 return
249 elif self.src.startswith("false", self.pos):
250 self.val = False
251 self.cursor += 4
252 return
253 elif self.src.startswith("null", self.pos):
254 self.val = None
255 self.cursor += 3
256 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200257 elif self.tok == '\n':
258 if self.cursor == len(self.src):
259 self.tok = None
260 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800261 self.line += 1
262 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200263 elif not self.tok.isspace():
264 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500265
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200266 def get_members(self):
267 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200268 if self.tok == '}':
269 self.accept()
270 return expr
271 if self.tok != "'":
272 raise QAPISchemaError(self, 'Expected string or "}"')
273 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200274 key = self.val
275 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200276 if self.tok != ':':
277 raise QAPISchemaError(self, 'Expected ":"')
278 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800279 if key in expr:
280 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200281 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200282 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200283 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200284 return expr
285 if self.tok != ',':
286 raise QAPISchemaError(self, 'Expected "," or "}"')
287 self.accept()
288 if self.tok != "'":
289 raise QAPISchemaError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500290
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200291 def get_values(self):
292 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200293 if self.tok == ']':
294 self.accept()
295 return expr
Eric Blake437db252015-09-29 16:21:02 -0600296 if self.tok not in "{['tfn":
Fam Zhenge53188a2015-05-04 09:05:18 -0600297 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
298 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200299 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200300 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200301 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200302 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200303 return expr
304 if self.tok != ',':
305 raise QAPISchemaError(self, 'Expected "," or "]"')
306 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500307
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200308 def get_expr(self, nested):
309 if self.tok != '{' and not nested:
310 raise QAPISchemaError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200311 if self.tok == '{':
312 self.accept()
313 expr = self.get_members()
314 elif self.tok == '[':
315 self.accept()
316 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600317 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200318 expr = self.val
319 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200320 else:
321 raise QAPISchemaError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200322 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200323
Markus Armbruster00e4b282015-06-10 10:04:36 +0200324#
325# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200326# TODO fold into QAPISchema
327# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200328#
329
Eric Blake437db252015-09-29 16:21:02 -0600330
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800331def find_base_fields(base):
332 base_struct_define = find_struct(base)
333 if not base_struct_define:
334 return None
335 return base_struct_define['data']
336
Eric Blake437db252015-09-29 16:21:02 -0600337
Eric Blake811d04f2015-05-04 09:05:10 -0600338# Return the qtype of an alternate branch, or None on error.
339def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600340 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600341 return builtin_types[qapi_type]
342 elif find_struct(qapi_type):
343 return "QTYPE_QDICT"
344 elif find_enum(qapi_type):
345 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600346 elif find_union(qapi_type):
347 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600348 return None
349
Eric Blake437db252015-09-29 16:21:02 -0600350
Wenchao Xiabceae762014-03-06 17:08:56 -0800351# Return the discriminator enum define if discriminator is specified as an
352# enum type, otherwise return None.
353def discriminator_find_enum_define(expr):
354 base = expr.get('base')
355 discriminator = expr.get('discriminator')
356
357 if not (discriminator and base):
358 return None
359
360 base_fields = find_base_fields(base)
361 if not base_fields:
362 return None
363
364 discriminator_type = base_fields.get(discriminator)
365 if not discriminator_type:
366 return None
367
368 return find_enum(discriminator_type)
369
Eric Blake437db252015-09-29 16:21:02 -0600370
Eric Blake59a92fe2015-11-18 01:52:56 -0700371# Names must be letters, numbers, -, and _. They must start with letter,
372# except for downstream extensions which must start with __RFQDN_.
373# Dots are only valid in the downstream extension prefix.
374valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
375 '[a-zA-Z][a-zA-Z0-9_-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600376
377
378def check_name(expr_info, source, name, allow_optional=False,
379 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600380 global valid_name
381 membername = name
382
383 if not isinstance(name, str):
384 raise QAPIExprError(expr_info,
385 "%s requires a string name" % source)
386 if name.startswith('*'):
387 membername = name[1:]
388 if not allow_optional:
389 raise QAPIExprError(expr_info,
390 "%s does not allow optional name '%s'"
391 % (source, name))
392 # Enum members can start with a digit, because the generated C
393 # code always prefixes it with the enum name
Eric Blake59a92fe2015-11-18 01:52:56 -0700394 if enum_member and membername[0].isdigit():
395 membername = 'D' + membername
Eric Blake9fb081e2015-10-26 16:34:44 -0600396 # Reserve the entire 'q_' namespace for c_name()
397 if not valid_name.match(membername) or \
398 c_name(membername, False).startswith('q_'):
Eric Blakec9e0a792015-05-04 09:05:22 -0600399 raise QAPIExprError(expr_info,
400 "%s uses invalid name '%s'" % (source, name))
401
Eric Blake437db252015-09-29 16:21:02 -0600402
403def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200404 global all_names
405 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200406 # FIXME should reject names that differ only in '_' vs. '.'
407 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200408 if name in all_names:
409 raise QAPIExprError(info,
410 "%s '%s' is already defined"
411 % (all_names[name], name))
Eric Blake255960d2015-10-26 16:34:43 -0600412 if not implicit and (name.endswith('Kind') or name.endswith('List')):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200413 raise QAPIExprError(info,
Eric Blake255960d2015-10-26 16:34:43 -0600414 "%s '%s' should not end in '%s'"
415 % (meta, name, name[-4:]))
Markus Armbruster00e4b282015-06-10 10:04:36 +0200416 all_names[name] = meta
417
Eric Blake437db252015-09-29 16:21:02 -0600418
Markus Armbruster00e4b282015-06-10 10:04:36 +0200419def add_struct(definition, info):
420 global struct_types
421 name = definition['struct']
422 add_name(name, info, 'struct')
423 struct_types.append(definition)
424
Eric Blake437db252015-09-29 16:21:02 -0600425
Markus Armbruster00e4b282015-06-10 10:04:36 +0200426def find_struct(name):
427 global struct_types
428 for struct in struct_types:
429 if struct['struct'] == name:
430 return struct
431 return None
432
Eric Blake437db252015-09-29 16:21:02 -0600433
Markus Armbruster00e4b282015-06-10 10:04:36 +0200434def add_union(definition, info):
435 global union_types
436 name = definition['union']
437 add_name(name, info, 'union')
438 union_types.append(definition)
439
Eric Blake437db252015-09-29 16:21:02 -0600440
Markus Armbruster00e4b282015-06-10 10:04:36 +0200441def find_union(name):
442 global union_types
443 for union in union_types:
444 if union['union'] == name:
445 return union
446 return None
447
Eric Blake437db252015-09-29 16:21:02 -0600448
449def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200450 global enum_types
451 add_name(name, info, 'enum', implicit)
452 enum_types.append({"enum_name": name, "enum_values": enum_values})
453
Eric Blake437db252015-09-29 16:21:02 -0600454
Markus Armbruster00e4b282015-06-10 10:04:36 +0200455def find_enum(name):
456 global enum_types
457 for enum in enum_types:
458 if enum['enum_name'] == name:
459 return enum
460 return None
461
Markus Armbruster00e4b282015-06-10 10:04:36 +0200462
Eric Blake437db252015-09-29 16:21:02 -0600463def is_enum(name):
464 return find_enum(name) is not None
465
466
467def check_type(expr_info, source, value, allow_array=False,
468 allow_dict=False, allow_optional=False,
469 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600470 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600471
472 if value is None:
473 return
474
Eric Blakedd883c62015-05-04 09:05:21 -0600475 # Check if array type for value is okay
476 if isinstance(value, list):
477 if not allow_array:
478 raise QAPIExprError(expr_info,
479 "%s cannot be an array" % source)
480 if len(value) != 1 or not isinstance(value[0], str):
481 raise QAPIExprError(expr_info,
482 "%s: array type must contain single type name"
483 % source)
484 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600485
486 # Check if type name for value is okay
487 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600488 if value not in all_names:
Eric Blakedd883c62015-05-04 09:05:21 -0600489 raise QAPIExprError(expr_info,
490 "%s uses unknown type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200491 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600492 if not all_names[value] in allow_metas:
493 raise QAPIExprError(expr_info,
494 "%s cannot use %s type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200495 % (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600496 return
497
Eric Blakedd883c62015-05-04 09:05:21 -0600498 if not allow_dict:
499 raise QAPIExprError(expr_info,
500 "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200501
502 if not isinstance(value, OrderedDict):
503 raise QAPIExprError(expr_info,
504 "%s should be a dictionary or type name" % source)
505
506 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600507 for (key, arg) in value.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600508 check_name(expr_info, "Member of %s" % source, key,
509 allow_optional=allow_optional)
Eric Blake5e59baf2015-10-26 16:35:02 -0600510 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
Eric Blake9fb081e2015-10-26 16:34:44 -0600511 raise QAPIExprError(expr_info,
512 "Member of %s uses reserved name '%s'"
513 % (source, key))
Eric Blake6b5abc72015-05-04 09:05:33 -0600514 # Todo: allow dictionaries to represent default values of
515 # an optional argument.
Eric Blakedd883c62015-05-04 09:05:21 -0600516 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200517 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600518 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600519 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600520
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
Eric Blake4dc2e692015-05-04 09:05:17 -0600540 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']
551
Eric Blake811d04f2015-05-04 09:05:10 -0600552 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600553
554 # With no discriminator it is a simple union.
555 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600556 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600557 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600558 if base is not None:
559 raise QAPIExprError(expr_info,
Eric Blake811d04f2015-05-04 09:05:10 -0600560 "Simple union '%s' must not have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600561 % name)
562
563 # Else, it's a flat union.
564 else:
565 # The object must have a string member 'base'.
Eric Blake376863e2015-09-29 16:21:07 -0600566 check_type(expr_info, "'base' for union '%s'" % name,
567 base, allow_metas=['struct'])
568 if not base:
Eric Blake44bd1272015-05-04 09:05:08 -0600569 raise QAPIExprError(expr_info,
Eric Blake376863e2015-09-29 16:21:07 -0600570 "Flat union '%s' must have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600571 % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800572 base_fields = find_base_fields(base)
Eric Blake376863e2015-09-29 16:21:07 -0600573 assert base_fields
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800574
Eric Blakec9e0a792015-05-04 09:05:22 -0600575 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600576 # member of the base struct.
Eric Blakec9e0a792015-05-04 09:05:22 -0600577 check_name(expr_info, "Discriminator of flat union '%s'" % name,
578 discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800579 discriminator_type = base_fields.get(discriminator)
580 if not discriminator_type:
581 raise QAPIExprError(expr_info,
582 "Discriminator '%s' is not a member of base "
Eric Blakefd41dd42015-05-04 09:05:25 -0600583 "struct '%s'"
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800584 % (discriminator, base))
585 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600586 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800587 # Do not allow string discriminator
588 if not enum_define:
589 raise QAPIExprError(expr_info,
590 "Discriminator '%s' must be of enumeration "
591 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800592
593 # Check every branch
594 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600595 check_name(expr_info, "Member of union '%s'" % name, key)
596
Eric Blake01cfbaa2015-12-01 22:20:58 -0700597 # Each value must name a known type
Eric Blakedd883c62015-05-04 09:05:21 -0600598 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200599 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600600
Eric Blake44bd1272015-05-04 09:05:08 -0600601 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700602 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600603 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600604 if key not in enum_define['enum_values']:
Eric Blake44bd1272015-05-04 09:05:08 -0600605 raise QAPIExprError(expr_info,
606 "Discriminator value '%s' is not found in "
607 "enum '%s'" %
608 (key, enum_define["enum_name"]))
609
Eric Blake437db252015-09-29 16:21:02 -0600610
Eric Blake811d04f2015-05-04 09:05:10 -0600611def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600612 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600613 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600614 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600615
Eric Blake811d04f2015-05-04 09:05:10 -0600616 # Check every branch
617 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600618 check_name(expr_info, "Member of alternate '%s'" % name, key)
619
Eric Blake811d04f2015-05-04 09:05:10 -0600620 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600621 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
622 value,
623 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600624 qtype = find_alternate_member_qtype(value)
Eric Blakedd883c62015-05-04 09:05:21 -0600625 assert qtype
Eric Blake811d04f2015-05-04 09:05:10 -0600626 if qtype in types_seen:
627 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600628 "Alternate '%s' member '%s' can't "
Eric Blake811d04f2015-05-04 09:05:10 -0600629 "be distinguished from member '%s'"
630 % (name, key, types_seen[qtype]))
631 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800632
Eric Blake437db252015-09-29 16:21:02 -0600633
Eric Blakecf393592015-05-04 09:05:04 -0600634def check_enum(expr, expr_info):
635 name = expr['enum']
636 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100637 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600638
639 if not isinstance(members, list):
640 raise QAPIExprError(expr_info,
641 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100642 if prefix is not None and not isinstance(prefix, str):
643 raise QAPIExprError(expr_info,
644 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600645 for member in members:
Eric Blake437db252015-09-29 16:21:02 -0600646 check_name(expr_info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600647 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600648
Eric Blake437db252015-09-29 16:21:02 -0600649
Eric Blakedd883c62015-05-04 09:05:21 -0600650def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600651 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600652 members = expr['data']
653
Eric Blakefd41dd42015-05-04 09:05:25 -0600654 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600655 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600656 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600657 allow_metas=['struct'])
658
Eric Blake437db252015-09-29 16:21:02 -0600659
Eric Blake0545f6b2015-05-04 09:05:15 -0600660def check_keys(expr_elem, meta, required, optional=[]):
661 expr = expr_elem['expr']
662 info = expr_elem['info']
663 name = expr[meta]
664 if not isinstance(name, str):
665 raise QAPIExprError(info,
666 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600667 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600668 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600669 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600670 raise QAPIExprError(info,
671 "Unknown key '%s' in %s '%s'"
672 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600673 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600674 raise QAPIExprError(info,
675 "'%s' of %s '%s' should only use false value"
676 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600677 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600678 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600679 raise QAPIExprError(info,
680 "Key '%s' is missing from %s '%s'"
681 % (key, meta, name))
682
Eric Blake437db252015-09-29 16:21:02 -0600683
Markus Armbruster4d076d62015-06-10 08:55:21 +0200684def check_exprs(exprs):
685 global all_names
686
687 # Learn the types and check for valid expression keys
688 for builtin in builtin_types.keys():
689 all_names[builtin] = 'built-in'
690 for expr_elem in exprs:
691 expr = expr_elem['expr']
692 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600693 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100694 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200695 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600696 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200697 check_keys(expr_elem, 'union', ['data'],
698 ['base', 'discriminator'])
699 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600700 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200701 check_keys(expr_elem, 'alternate', ['data'])
702 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600703 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200704 check_keys(expr_elem, 'struct', ['data'], ['base'])
705 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600706 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200707 check_keys(expr_elem, 'command', [],
708 ['data', 'returns', 'gen', 'success-response'])
709 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600710 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200711 check_keys(expr_elem, 'event', [], ['data'])
712 add_name(expr['event'], info, 'event')
713 else:
714 raise QAPIExprError(expr_elem['info'],
715 "Expression is missing metatype")
716
717 # Try again for hidden UnionKind enum
718 for expr_elem in exprs:
719 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600720 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200721 if not discriminator_find_enum_define(expr):
722 add_enum('%sKind' % expr['union'], expr_elem['info'],
723 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600724 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200725 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
726 implicit=True)
727
728 # Validate that exprs make sense
729 for expr_elem in exprs:
730 expr = expr_elem['expr']
731 info = expr_elem['info']
732
Eric Blake437db252015-09-29 16:21:02 -0600733 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200734 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600735 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200736 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600737 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200738 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600739 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200740 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600741 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200742 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600743 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200744 check_event(expr, info)
745 else:
746 assert False, 'unexpected meta type'
747
Markus Armbrusterac882192015-09-16 13:06:05 +0200748 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600749
Markus Armbrusterac882192015-09-16 13:06:05 +0200750
751#
752# Schema compiler frontend
753#
754
755class QAPISchemaEntity(object):
756 def __init__(self, name, info):
757 assert isinstance(name, str)
758 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -0600759 # For explicitly defined entities, info points to the (explicit)
760 # definition. For builtins (and their arrays), info is None.
761 # For implicitly defined entities, info points to a place that
762 # triggered the implicit definition (there may be more than one
763 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +0200764 self.info = info
765
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200766 def c_name(self):
767 return c_name(self.name)
768
Markus Armbrusterac882192015-09-16 13:06:05 +0200769 def check(self, schema):
770 pass
771
Eric Blake49823c42015-10-12 22:22:27 -0600772 def is_implicit(self):
773 return not self.info
774
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200775 def visit(self, visitor):
776 pass
777
778
779class QAPISchemaVisitor(object):
780 def visit_begin(self, schema):
781 pass
782
783 def visit_end(self):
784 pass
785
Eric Blake25a0d9c2015-10-12 22:22:21 -0600786 def visit_needed(self, entity):
787 # Default to visiting everything
788 return True
789
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200790 def visit_builtin_type(self, name, info, json_type):
791 pass
792
793 def visit_enum_type(self, name, info, values, prefix):
794 pass
795
796 def visit_array_type(self, name, info, element_type):
797 pass
798
799 def visit_object_type(self, name, info, base, members, variants):
800 pass
801
Markus Armbruster39a18152015-09-16 13:06:28 +0200802 def visit_object_type_flat(self, name, info, members, variants):
803 pass
804
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200805 def visit_alternate_type(self, name, info, variants):
806 pass
807
808 def visit_command(self, name, info, arg_type, ret_type,
809 gen, success_response):
810 pass
811
812 def visit_event(self, name, info, arg_type):
813 pass
814
Markus Armbrusterac882192015-09-16 13:06:05 +0200815
816class QAPISchemaType(QAPISchemaEntity):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200817 def c_type(self, is_param=False):
818 return c_name(self.name) + pointer_suffix
819
820 def c_null(self):
821 return 'NULL'
822
823 def json_type(self):
824 pass
825
826 def alternate_qtype(self):
827 json2qtype = {
828 'string': 'QTYPE_QSTRING',
829 'number': 'QTYPE_QFLOAT',
830 'int': 'QTYPE_QINT',
831 'boolean': 'QTYPE_QBOOL',
832 'object': 'QTYPE_QDICT'
833 }
834 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200835
836
837class QAPISchemaBuiltinType(QAPISchemaType):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200838 def __init__(self, name, json_type, c_type, c_null):
Markus Armbrusterac882192015-09-16 13:06:05 +0200839 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200840 assert not c_type or isinstance(c_type, str)
841 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
842 'value')
843 self._json_type_name = json_type
844 self._c_type_name = c_type
845 self._c_null_val = c_null
846
847 def c_name(self):
848 return self.name
849
850 def c_type(self, is_param=False):
851 if is_param and self.name == 'str':
852 return 'const ' + self._c_type_name
853 return self._c_type_name
854
855 def c_null(self):
856 return self._c_null_val
857
858 def json_type(self):
859 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200860
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200861 def visit(self, visitor):
862 visitor.visit_builtin_type(self.name, self.info, self.json_type())
863
Markus Armbrusterac882192015-09-16 13:06:05 +0200864
865class QAPISchemaEnumType(QAPISchemaType):
866 def __init__(self, name, info, values, prefix):
867 QAPISchemaType.__init__(self, name, info)
868 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -0700869 assert isinstance(v, QAPISchemaMember)
870 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200871 assert prefix is None or isinstance(prefix, str)
872 self.values = values
873 self.prefix = prefix
874
875 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -0700876 seen = {}
877 for v in self.values:
878 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200879
Eric Blake99df5282015-10-12 22:22:32 -0600880 def is_implicit(self):
881 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -0600882 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -0600883
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200884 def c_type(self, is_param=False):
885 return c_name(self.name)
886
Eric Blake93bda4d2015-12-01 22:20:55 -0700887 def member_names(self):
888 return [v.name for v in self.values]
889
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200890 def c_null(self):
Eric Blake93bda4d2015-12-01 22:20:55 -0700891 return c_enum_const(self.name, (self.member_names() + ['_MAX'])[0],
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200892 self.prefix)
893
894 def json_type(self):
895 return 'string'
896
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200897 def visit(self, visitor):
898 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -0700899 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200900
Markus Armbrusterac882192015-09-16 13:06:05 +0200901
902class QAPISchemaArrayType(QAPISchemaType):
903 def __init__(self, name, info, element_type):
904 QAPISchemaType.__init__(self, name, info)
905 assert isinstance(element_type, str)
906 self._element_type_name = element_type
907 self.element_type = None
908
909 def check(self, schema):
910 self.element_type = schema.lookup_type(self._element_type_name)
911 assert self.element_type
912
Eric Blake99df5282015-10-12 22:22:32 -0600913 def is_implicit(self):
914 return True
915
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200916 def json_type(self):
917 return 'array'
918
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200919 def visit(self, visitor):
920 visitor.visit_array_type(self.name, self.info, self.element_type)
921
Markus Armbrusterac882192015-09-16 13:06:05 +0200922
923class QAPISchemaObjectType(QAPISchemaType):
924 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -0700925 # struct has local_members, optional base, and no variants
926 # flat union has base, variants, and no local_members
927 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +0200928 QAPISchemaType.__init__(self, name, info)
929 assert base is None or isinstance(base, str)
930 for m in local_members:
931 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -0700932 m.set_owner(name)
933 if variants is not None:
934 assert isinstance(variants, QAPISchemaObjectTypeVariants)
935 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200936 self._base_name = base
937 self.base = None
938 self.local_members = local_members
939 self.variants = variants
940 self.members = None
941
942 def check(self, schema):
943 assert self.members is not False # not running in cycles
944 if self.members:
945 return
946 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -0700947 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +0200948 if self._base_name:
949 self.base = schema.lookup_type(self._base_name)
950 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +0200951 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700952 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200953 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -0700954 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700955 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700956 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +0200957 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -0700958 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700959 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -0700960 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200961
Eric Blake27b60ab2015-11-18 01:52:51 -0700962 # Check that the members of this type do not cause duplicate JSON fields,
963 # and update seen to track the members seen so far. Report any errors
964 # on behalf of info, which is not necessarily self.info
965 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -0700966 assert not self.variants # not implemented
967 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -0700968 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -0700969
Eric Blake99df5282015-10-12 22:22:32 -0600970 def is_implicit(self):
971 # See QAPISchema._make_implicit_object_type()
972 return self.name[0] == ':'
973
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200974 def c_name(self):
Eric Blake49823c42015-10-12 22:22:27 -0600975 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200976 return QAPISchemaType.c_name(self)
977
978 def c_type(self, is_param=False):
Eric Blake49823c42015-10-12 22:22:27 -0600979 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200980 return QAPISchemaType.c_type(self)
981
982 def json_type(self):
983 return 'object'
984
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200985 def visit(self, visitor):
986 visitor.visit_object_type(self.name, self.info,
987 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +0200988 visitor.visit_object_type_flat(self.name, self.info,
989 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200990
Markus Armbrusterac882192015-09-16 13:06:05 +0200991
Eric Blaked44f9ac2015-12-01 22:20:54 -0700992class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -0700993 role = 'member'
994
Eric Blaked44f9ac2015-12-01 22:20:54 -0700995 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +0200996 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +0200997 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -0700998 self.owner = None
999
1000 def set_owner(self, name):
1001 assert not self.owner
1002 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001003
Eric Blake27b60ab2015-11-18 01:52:51 -07001004 def check_clash(self, info, seen):
1005 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001006 if cname.lower() != cname and self.owner not in case_whitelist:
1007 raise QAPIExprError(info,
1008 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001009 if cname in seen:
1010 raise QAPIExprError(info,
1011 "%s collides with %s"
1012 % (self.describe(), seen[cname].describe()))
1013 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001014
Eric Blake88d4ef82015-11-18 01:52:50 -07001015 def _pretty_owner(self):
1016 owner = self.owner
1017 if owner.startswith(':obj-'):
1018 # See QAPISchema._make_implicit_object_type() - reverse the
1019 # mapping there to create a nice human-readable description
1020 owner = owner[5:]
1021 if owner.endswith('-arg'):
1022 return '(parameter of %s)' % owner[:-4]
1023 else:
1024 assert owner.endswith('-wrapper')
1025 # Unreachable and not implemented
1026 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001027 if owner.endswith('Kind'):
1028 # See QAPISchema._make_implicit_enum_type()
1029 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001030 return '(%s of %s)' % (self.role, owner)
1031
1032 def describe(self):
1033 return "'%s' %s" % (self.name, self._pretty_owner())
1034
Markus Armbrusterac882192015-09-16 13:06:05 +02001035
Eric Blaked44f9ac2015-12-01 22:20:54 -07001036class QAPISchemaObjectTypeMember(QAPISchemaMember):
1037 def __init__(self, name, typ, optional):
1038 QAPISchemaMember.__init__(self, name)
1039 assert isinstance(typ, str)
1040 assert isinstance(optional, bool)
1041 self._type_name = typ
1042 self.type = None
1043 self.optional = optional
1044
1045 def check(self, schema):
1046 assert self.owner
1047 self.type = schema.lookup_type(self._type_name)
1048 assert self.type
1049
1050
Markus Armbrusterac882192015-09-16 13:06:05 +02001051class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001052 def __init__(self, tag_name, tag_member, variants):
1053 # Flat unions pass tag_name but not tag_member.
1054 # Simple unions and alternates pass tag_member but not tag_name.
1055 # After check(), tag_member is always set, and tag_name remains
1056 # a reliable witness of being used by a flat union.
1057 assert bool(tag_member) != bool(tag_name)
1058 assert (isinstance(tag_name, str) or
1059 isinstance(tag_member, QAPISchemaObjectTypeMember))
Markus Armbrusterac882192015-09-16 13:06:05 +02001060 for v in variants:
1061 assert isinstance(v, QAPISchemaObjectTypeVariant)
1062 self.tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001063 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001064 self.variants = variants
1065
Eric Blake88d4ef82015-11-18 01:52:50 -07001066 def set_owner(self, name):
1067 for v in self.variants:
1068 v.set_owner(name)
1069
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001070 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001071 if not self.tag_member: # flat union
Eric Blake27b60ab2015-11-18 01:52:51 -07001072 self.tag_member = seen[c_name(self.tag_name)]
1073 assert self.tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001074 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1075 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001076 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001077 # Union names must match enum values; alternate names are
1078 # checked separately. Use 'seen' to tell the two apart.
1079 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001080 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001081 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001082 v.type.check(schema)
1083
Eric Blake27b60ab2015-11-18 01:52:51 -07001084 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001085 for v in self.variants:
1086 # Reset seen map for each variant, since qapi names from one
1087 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001088 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001089 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001090
Eric Blake437db252015-09-29 16:21:02 -06001091
Markus Armbrusterac882192015-09-16 13:06:05 +02001092class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001093 role = 'branch'
1094
Markus Armbrusterac882192015-09-16 13:06:05 +02001095 def __init__(self, name, typ):
1096 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1097
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001098 # This function exists to support ugly simple union special cases
1099 # TODO get rid of them, and drop the function
1100 def simple_union_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001101 if (self.type.is_implicit() and
1102 isinstance(self.type, QAPISchemaObjectType)):
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001103 assert len(self.type.members) == 1
1104 assert not self.type.variants
1105 return self.type.members[0].type
1106 return None
1107
Markus Armbrusterac882192015-09-16 13:06:05 +02001108
1109class QAPISchemaAlternateType(QAPISchemaType):
1110 def __init__(self, name, info, variants):
1111 QAPISchemaType.__init__(self, name, info)
1112 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1113 assert not variants.tag_name
Eric Blake88d4ef82015-11-18 01:52:50 -07001114 variants.set_owner(name)
1115 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001116 self.variants = variants
1117
1118 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001119 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001120 # Not calling self.variants.check_clash(), because there's nothing
1121 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001122 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001123 # Alternate branch names have no relation to the tag enum values;
1124 # so we have to check for potential name collisions ourselves.
1125 seen = {}
1126 for v in self.variants.variants:
1127 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001128
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001129 def json_type(self):
1130 return 'value'
1131
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001132 def visit(self, visitor):
1133 visitor.visit_alternate_type(self.name, self.info, self.variants)
1134
Markus Armbrusterac882192015-09-16 13:06:05 +02001135
1136class QAPISchemaCommand(QAPISchemaEntity):
1137 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1138 QAPISchemaEntity.__init__(self, name, info)
1139 assert not arg_type or isinstance(arg_type, str)
1140 assert not ret_type or isinstance(ret_type, str)
1141 self._arg_type_name = arg_type
1142 self.arg_type = None
1143 self._ret_type_name = ret_type
1144 self.ret_type = None
1145 self.gen = gen
1146 self.success_response = success_response
1147
1148 def check(self, schema):
1149 if self._arg_type_name:
1150 self.arg_type = schema.lookup_type(self._arg_type_name)
1151 assert isinstance(self.arg_type, QAPISchemaObjectType)
1152 assert not self.arg_type.variants # not implemented
1153 if self._ret_type_name:
1154 self.ret_type = schema.lookup_type(self._ret_type_name)
1155 assert isinstance(self.ret_type, QAPISchemaType)
1156
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001157 def visit(self, visitor):
1158 visitor.visit_command(self.name, self.info,
1159 self.arg_type, self.ret_type,
1160 self.gen, self.success_response)
1161
Markus Armbrusterac882192015-09-16 13:06:05 +02001162
1163class QAPISchemaEvent(QAPISchemaEntity):
1164 def __init__(self, name, info, arg_type):
1165 QAPISchemaEntity.__init__(self, name, info)
1166 assert not arg_type or isinstance(arg_type, str)
1167 self._arg_type_name = arg_type
1168 self.arg_type = None
1169
1170 def check(self, schema):
1171 if self._arg_type_name:
1172 self.arg_type = schema.lookup_type(self._arg_type_name)
1173 assert isinstance(self.arg_type, QAPISchemaObjectType)
1174 assert not self.arg_type.variants # not implemented
1175
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001176 def visit(self, visitor):
1177 visitor.visit_event(self.name, self.info, self.arg_type)
1178
Markus Armbrusterac882192015-09-16 13:06:05 +02001179
1180class QAPISchema(object):
1181 def __init__(self, fname):
1182 try:
1183 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001184 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001185 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001186 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001187 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001188 self._def_exprs()
1189 self.check()
Markus Armbrusterac882192015-09-16 13:06:05 +02001190 except (QAPISchemaError, QAPIExprError), err:
1191 print >>sys.stderr, err
1192 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001193
Markus Armbrusterac882192015-09-16 13:06:05 +02001194 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001195 # Only the predefined types are allowed to not have info
1196 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001197 assert ent.name not in self._entity_dict
1198 self._entity_dict[ent.name] = ent
1199
1200 def lookup_entity(self, name, typ=None):
1201 ent = self._entity_dict.get(name)
1202 if typ and not isinstance(ent, typ):
1203 return None
1204 return ent
1205
1206 def lookup_type(self, name):
1207 return self.lookup_entity(name, QAPISchemaType)
1208
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001209 def _def_builtin_type(self, name, json_type, c_type, c_null):
1210 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1211 c_type, c_null))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001212 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1213 # qapi-types.h from a single .c, all arrays of builtins must be
1214 # declared in the first file whether or not they are used. Nicer
1215 # would be to use lazy instantiation, while figuring out how to
1216 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001217 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001218
1219 def _def_predefineds(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001220 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1221 ('number', 'number', 'double', '0'),
1222 ('int', 'int', 'int64_t', '0'),
1223 ('int8', 'int', 'int8_t', '0'),
1224 ('int16', 'int', 'int16_t', '0'),
1225 ('int32', 'int', 'int32_t', '0'),
1226 ('int64', 'int', 'int64_t', '0'),
1227 ('uint8', 'int', 'uint8_t', '0'),
1228 ('uint16', 'int', 'uint16_t', '0'),
1229 ('uint32', 'int', 'uint32_t', '0'),
1230 ('uint64', 'int', 'uint64_t', '0'),
1231 ('size', 'int', 'uint64_t', '0'),
1232 ('bool', 'boolean', 'bool', 'false'),
Markus Armbruster28770e02015-09-16 13:06:24 +02001233 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001234 self._def_builtin_type(*t)
Markus Armbruster39a18152015-09-16 13:06:28 +02001235 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1236 [], None)
1237 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001238 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1239 'qstring', 'qdict', 'qlist',
1240 'qfloat', 'qbool'])
1241 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001242 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001243
Eric Blake93bda4d2015-12-01 22:20:55 -07001244 def _make_enum_members(self, values):
1245 return [QAPISchemaMember(v) for v in values]
1246
Eric Blake99df5282015-10-12 22:22:32 -06001247 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001248 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001249 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001250 self._def_entity(QAPISchemaEnumType(
1251 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001252 return name
1253
Eric Blake99df5282015-10-12 22:22:32 -06001254 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001255 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001256 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001257 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001258 return name
1259
Eric Blake99df5282015-10-12 22:22:32 -06001260 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001261 if not members:
1262 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001263 # See also QAPISchemaObjectTypeMember._pretty_owner()
Markus Armbrusterac882192015-09-16 13:06:05 +02001264 name = ':obj-%s-%s' % (name, role)
1265 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001266 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001267 members, None))
1268 return name
1269
1270 def _def_enum_type(self, expr, info):
1271 name = expr['enum']
1272 data = expr['data']
1273 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001274 self._def_entity(QAPISchemaEnumType(
1275 name, info, self._make_enum_members(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
Markus Armbrusterac882192015-09-16 13:06:05 +02001310 def _def_union_type(self, expr, info):
1311 name = expr['union']
1312 data = expr['data']
1313 base = expr.get('base')
1314 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001315 tag_member = None
Markus Armbrusterac882192015-09-16 13:06:05 +02001316 if tag_name:
1317 variants = [self._make_variant(key, value)
1318 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001319 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001320 else:
Eric Blake99df5282015-10-12 22:22:32 -06001321 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001322 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001323 typ = self._make_implicit_enum_type(name, info,
1324 [v.name for v in variants])
1325 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001326 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001327 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001328 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001329 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001330 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001331 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001332
1333 def _def_alternate_type(self, expr, info):
1334 name = expr['alternate']
1335 data = expr['data']
1336 variants = [self._make_variant(key, value)
1337 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001338 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001339 self._def_entity(
1340 QAPISchemaAlternateType(name, info,
1341 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001342 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001343 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001344
1345 def _def_command(self, expr, info):
1346 name = expr['command']
1347 data = expr.get('data')
1348 rets = expr.get('returns')
1349 gen = expr.get('gen', True)
1350 success_response = expr.get('success-response', True)
1351 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001352 data = self._make_implicit_object_type(
1353 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001354 if isinstance(rets, list):
1355 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001356 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001357 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1358 success_response))
1359
1360 def _def_event(self, expr, info):
1361 name = expr['event']
1362 data = expr.get('data')
1363 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001364 data = self._make_implicit_object_type(
1365 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001366 self._def_entity(QAPISchemaEvent(name, info, data))
1367
1368 def _def_exprs(self):
1369 for expr_elem in self.exprs:
1370 expr = expr_elem['expr']
1371 info = expr_elem['info']
1372 if 'enum' in expr:
1373 self._def_enum_type(expr, info)
1374 elif 'struct' in expr:
1375 self._def_struct_type(expr, info)
1376 elif 'union' in expr:
1377 self._def_union_type(expr, info)
1378 elif 'alternate' in expr:
1379 self._def_alternate_type(expr, info)
1380 elif 'command' in expr:
1381 self._def_command(expr, info)
1382 elif 'event' in expr:
1383 self._def_event(expr, info)
1384 else:
1385 assert False
1386
1387 def check(self):
1388 for ent in self._entity_dict.values():
1389 ent.check(self)
1390
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001391 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001392 visitor.visit_begin(self)
1393 for (name, entity) in sorted(self._entity_dict.items()):
1394 if visitor.visit_needed(entity):
1395 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001396 visitor.visit_end()
1397
Markus Armbruster2caba362013-07-27 17:41:56 +02001398
Markus Armbruster00e4b282015-06-10 10:04:36 +02001399#
1400# Code generation helpers
1401#
1402
Michael Roth0f923be2011-07-19 14:50:39 -05001403def camel_case(name):
1404 new_name = ''
1405 first = True
1406 for ch in name:
1407 if ch in ['_', '-']:
1408 first = True
1409 elif first:
1410 new_name += ch.upper()
1411 first = False
1412 else:
1413 new_name += ch.lower()
1414 return new_name
1415
Eric Blake437db252015-09-29 16:21:02 -06001416
Markus Armbruster849bc532015-05-14 06:50:53 -06001417# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1418# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1419# ENUM24_Name -> ENUM24_NAME
1420def camel_to_upper(value):
1421 c_fun_str = c_name(value, False)
1422 if value.isupper():
1423 return c_fun_str
1424
1425 new_name = ''
1426 l = len(c_fun_str)
1427 for i in range(l):
1428 c = c_fun_str[i]
1429 # When c is upper and no "_" appears before, do more checks
1430 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001431 if i < l - 1 and c_fun_str[i + 1].islower():
1432 new_name += '_'
1433 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001434 new_name += '_'
1435 new_name += c
1436 return new_name.lstrip('_').upper()
1437
Eric Blake437db252015-09-29 16:21:02 -06001438
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001439def c_enum_const(type_name, const_name, prefix=None):
1440 if prefix is not None:
1441 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001442 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001443
Eric Blake18df5152015-05-14 06:50:48 -06001444c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001445
Eric Blake437db252015-09-29 16:21:02 -06001446
Eric Blakec6405b52015-05-14 06:50:55 -06001447# Map @name to a valid C identifier.
1448# If @protect, avoid returning certain ticklish identifiers (like
1449# C keywords) by prepending "q_".
1450#
1451# Used for converting 'name' from a 'name':'type' qapi definition
1452# into a generated struct member, as well as converting type names
1453# into substrings of a generated C function name.
1454# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1455# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001456def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001457 # ANSI X3J11/88-090, 3.1.1
1458 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001459 'default', 'do', 'double', 'else', 'enum', 'extern',
1460 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1461 'return', 'short', 'signed', 'sizeof', 'static',
1462 'struct', 'switch', 'typedef', 'union', 'unsigned',
1463 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001464 # ISO/IEC 9899:1999, 6.4.1
1465 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1466 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001467 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1468 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001469 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1470 # excluding _.*
1471 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001472 # C++ ISO/IEC 14882:2003 2.11
1473 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1474 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1475 'namespace', 'new', 'operator', 'private', 'protected',
1476 'public', 'reinterpret_cast', 'static_cast', 'template',
1477 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1478 'using', 'virtual', 'wchar_t',
1479 # alternative representations
1480 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1481 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001482 # namespace pollution:
Max Reitz8592a542013-12-20 19:28:18 +01001483 polluted_words = set(['unix', 'errno'])
Eric Blakec43567c2015-11-18 01:52:52 -07001484 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001485 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1486 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001487 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001488 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001489
Amos Kong05dfb262014-06-10 19:25:53 +08001490eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001491pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001492
Eric Blake437db252015-09-29 16:21:02 -06001493
Michael Roth0f923be2011-07-19 14:50:39 -05001494def genindent(count):
1495 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001496 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001497 ret += " "
1498 return ret
1499
1500indent_level = 0
1501
Eric Blake437db252015-09-29 16:21:02 -06001502
Michael Roth0f923be2011-07-19 14:50:39 -05001503def push_indent(indent_amount=4):
1504 global indent_level
1505 indent_level += indent_amount
1506
Eric Blake437db252015-09-29 16:21:02 -06001507
Michael Roth0f923be2011-07-19 14:50:39 -05001508def pop_indent(indent_amount=4):
1509 global indent_level
1510 indent_level -= indent_amount
1511
Eric Blake437db252015-09-29 16:21:02 -06001512
Markus Armbruster77e703b2015-06-24 19:27:32 +02001513# Generate @code with @kwds interpolated.
1514# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001515def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001516 raw = code % kwds
1517 if indent_level:
1518 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001519 # re.subn() lacks flags support before Python 2.7, use re.compile()
1520 raw = re.subn(re.compile("^.", re.MULTILINE),
1521 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001522 raw = raw[0]
1523 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001524
Eric Blake437db252015-09-29 16:21:02 -06001525
Michael Roth0f923be2011-07-19 14:50:39 -05001526def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001527 if code[0] == '\n':
1528 code = code[1:]
1529 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001530
Michael Roth0f923be2011-07-19 14:50:39 -05001531
1532def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001533 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001534
Eric Blake437db252015-09-29 16:21:02 -06001535
Michael Rothc0afa9c2013-05-10 17:46:00 -05001536def guardstart(name):
1537 return mcgen('''
1538
1539#ifndef %(name)s
1540#define %(name)s
1541
1542''',
1543 name=guardname(name))
1544
Eric Blake437db252015-09-29 16:21:02 -06001545
Michael Rothc0afa9c2013-05-10 17:46:00 -05001546def guardend(name):
1547 return mcgen('''
1548
1549#endif /* %(name)s */
1550
1551''',
1552 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001553
Eric Blake437db252015-09-29 16:21:02 -06001554
Markus Armbrustere98859a2015-09-16 13:06:16 +02001555def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001556 ret = mcgen('''
1557
Markus Armbrustere98859a2015-09-16 13:06:16 +02001558const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001559''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001560 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001561 for value in values:
1562 index = c_enum_const(name, value, prefix)
1563 ret += mcgen('''
1564 [%(index)s] = "%(value)s",
1565''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001566 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001567
Eric Blake7fb1cf12015-11-18 01:52:57 -07001568 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001569 ret += mcgen('''
1570 [%(max_index)s] = NULL,
1571};
1572''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001573 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001574 return ret
1575
Eric Blake437db252015-09-29 16:21:02 -06001576
Markus Armbrustere98859a2015-09-16 13:06:16 +02001577def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001578 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001579 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001580
1581 ret = mcgen('''
1582
1583typedef enum %(c_name)s {
1584''',
1585 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001586
1587 i = 0
1588 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001589 ret += mcgen('''
1590 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001591''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001592 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001593 i=i)
1594 i += 1
1595
Markus Armbrustere98859a2015-09-16 13:06:16 +02001596 ret += mcgen('''
1597} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001598''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001599 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001600
Markus Armbrustere98859a2015-09-16 13:06:16 +02001601 ret += mcgen('''
1602
1603extern const char *const %(c_name)s_lookup[];
1604''',
1605 c_name=c_name(name))
1606 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001607
Eric Blake437db252015-09-29 16:21:02 -06001608
Markus Armbruster03b43672015-09-16 13:06:20 +02001609def gen_params(arg_type, extra):
1610 if not arg_type:
1611 return extra
1612 assert not arg_type.variants
1613 ret = ''
1614 sep = ''
1615 for memb in arg_type.members:
1616 ret += sep
1617 sep = ', '
1618 if memb.optional:
1619 ret += 'bool has_%s, ' % c_name(memb.name)
1620 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1621 if extra:
1622 ret += sep + extra
1623 return ret
1624
Eric Blake1f353342015-09-29 16:21:13 -06001625
Eric Blake18bdbc32015-09-29 16:21:15 -06001626def gen_err_check(label='out', skiperr=False):
1627 if skiperr:
Eric Blake1f353342015-09-29 16:21:13 -06001628 return ''
1629 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001630 if (err) {
Eric Blake1f353342015-09-29 16:21:13 -06001631 goto %(label)s;
1632 }
1633''',
Eric Blake18bdbc32015-09-29 16:21:15 -06001634 label=label)
Eric Blake1f353342015-09-29 16:21:13 -06001635
1636
Eric Blake18bdbc32015-09-29 16:21:15 -06001637def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
Eric Blake82ca8e42015-09-29 16:21:14 -06001638 ret = ''
Eric Blake18bdbc32015-09-29 16:21:15 -06001639 if skiperr:
Eric Blake82ca8e42015-09-29 16:21:14 -06001640 errparg = 'NULL'
Eric Blake18bdbc32015-09-29 16:21:15 -06001641 else:
1642 errparg = '&err'
Eric Blake82ca8e42015-09-29 16:21:14 -06001643
1644 for memb in members:
1645 if memb.optional:
1646 ret += mcgen('''
Eric Blake29637a62015-12-01 22:20:53 -07001647 if (visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s")) {
Eric Blake82ca8e42015-09-29 16:21:14 -06001648''',
1649 prefix=prefix, c_name=c_name(memb.name),
1650 name=memb.name, errp=errparg)
Eric Blake82ca8e42015-09-29 16:21:14 -06001651 push_indent()
1652
1653 # Ugly: sometimes we need to cast away const
1654 if need_cast and memb.type.name == 'str':
1655 cast = '(char **)'
1656 else:
1657 cast = ''
1658
1659 ret += mcgen('''
1660 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1661''',
1662 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1663 c_name=c_name(memb.name), name=memb.name,
1664 errp=errparg)
Eric Blake18bdbc32015-09-29 16:21:15 -06001665 ret += gen_err_check(skiperr=skiperr)
Eric Blake82ca8e42015-09-29 16:21:14 -06001666
1667 if memb.optional:
1668 pop_indent()
1669 ret += mcgen('''
1670 }
1671''')
1672 return ret
1673
1674
Markus Armbruster00e4b282015-06-10 10:04:36 +02001675#
1676# Common command line parsing
1677#
1678
Eric Blake437db252015-09-29 16:21:02 -06001679
1680def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001681
1682 try:
1683 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001684 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001685 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001686 "output-dir="] + extra_long_options)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001687 except getopt.GetoptError, err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001688 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001689 sys.exit(1)
1690
1691 output_dir = ""
1692 prefix = ""
1693 do_c = False
1694 do_h = False
1695 extra_opts = []
1696
1697 for oa in opts:
1698 o, a = oa
1699 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001700 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1701 if match.end() != len(a):
1702 print >>sys.stderr, \
1703 "%s: 'funny character '%s' in argument of --prefix" \
1704 % (sys.argv[0], a[match.end()])
1705 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001706 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001707 elif o in ("-o", "--output-dir"):
1708 output_dir = a + "/"
1709 elif o in ("-c", "--source"):
1710 do_c = True
1711 elif o in ("-h", "--header"):
1712 do_h = True
1713 else:
1714 extra_opts.append(oa)
1715
1716 if not do_c and not do_h:
1717 do_c = True
1718 do_h = True
1719
Markus Armbruster16d80f62015-04-02 13:32:16 +02001720 if len(args) != 1:
1721 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001722 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001723 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001724
Markus Armbruster54414042015-06-09 16:22:45 +02001725 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001726
Markus Armbruster00e4b282015-06-10 10:04:36 +02001727#
1728# Generate output files with boilerplate
1729#
1730
Eric Blake437db252015-09-29 16:21:02 -06001731
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001732def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1733 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001734 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001735 c_file = output_dir + prefix + c_file
1736 h_file = output_dir + prefix + h_file
1737
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001738 if output_dir:
1739 try:
1740 os.makedirs(output_dir)
1741 except os.error, e:
1742 if e.errno != errno.EEXIST:
1743 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001744
1745 def maybe_open(really, name, opt):
1746 if really:
1747 return open(name, opt)
1748 else:
1749 import StringIO
1750 return StringIO.StringIO()
1751
1752 fdef = maybe_open(do_c, c_file, 'w')
1753 fdecl = maybe_open(do_h, h_file, 'w')
1754
1755 fdef.write(mcgen('''
1756/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1757%(comment)s
1758''',
Eric Blake437db252015-09-29 16:21:02 -06001759 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001760
1761 fdecl.write(mcgen('''
1762/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1763%(comment)s
1764#ifndef %(guard)s
1765#define %(guard)s
1766
1767''',
Eric Blake437db252015-09-29 16:21:02 -06001768 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001769
1770 return (fdef, fdecl)
1771
Eric Blake437db252015-09-29 16:21:02 -06001772
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001773def close_output(fdef, fdecl):
1774 fdecl.write('''
1775#endif
1776''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001777 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001778 fdef.close()