blob: 645dcf142724ec39477382b679f01bf20caf6180 [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')
Markus Armbruster291928a2015-12-18 08:52:41 +0100170 except IOError as 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):
Eric Blakebac54292015-12-01 22:20:59 -0700943 if self.members is False: # check for cycles
944 raise QAPIExprError(self.info,
945 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200946 if self.members:
947 return
948 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -0700949 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +0200950 if self._base_name:
951 self.base = schema.lookup_type(self._base_name)
952 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +0200953 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700954 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200955 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -0700956 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700957 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700958 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +0200959 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -0700960 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700961 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -0700962 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200963
Eric Blake27b60ab2015-11-18 01:52:51 -0700964 # Check that the members of this type do not cause duplicate JSON fields,
965 # and update seen to track the members seen so far. Report any errors
966 # on behalf of info, which is not necessarily self.info
967 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -0700968 assert not self.variants # not implemented
969 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -0700970 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -0700971
Eric Blake99df5282015-10-12 22:22:32 -0600972 def is_implicit(self):
973 # See QAPISchema._make_implicit_object_type()
974 return self.name[0] == ':'
975
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200976 def c_name(self):
Eric Blake49823c42015-10-12 22:22:27 -0600977 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200978 return QAPISchemaType.c_name(self)
979
980 def c_type(self, is_param=False):
Eric Blake49823c42015-10-12 22:22:27 -0600981 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200982 return QAPISchemaType.c_type(self)
983
984 def json_type(self):
985 return 'object'
986
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200987 def visit(self, visitor):
988 visitor.visit_object_type(self.name, self.info,
989 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +0200990 visitor.visit_object_type_flat(self.name, self.info,
991 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200992
Markus Armbrusterac882192015-09-16 13:06:05 +0200993
Eric Blaked44f9ac2015-12-01 22:20:54 -0700994class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -0700995 role = 'member'
996
Eric Blaked44f9ac2015-12-01 22:20:54 -0700997 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +0200998 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +0200999 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001000 self.owner = None
1001
1002 def set_owner(self, name):
1003 assert not self.owner
1004 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001005
Eric Blake27b60ab2015-11-18 01:52:51 -07001006 def check_clash(self, info, seen):
1007 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001008 if cname.lower() != cname and self.owner not in case_whitelist:
1009 raise QAPIExprError(info,
1010 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001011 if cname in seen:
1012 raise QAPIExprError(info,
1013 "%s collides with %s"
1014 % (self.describe(), seen[cname].describe()))
1015 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001016
Eric Blake88d4ef82015-11-18 01:52:50 -07001017 def _pretty_owner(self):
1018 owner = self.owner
1019 if owner.startswith(':obj-'):
1020 # See QAPISchema._make_implicit_object_type() - reverse the
1021 # mapping there to create a nice human-readable description
1022 owner = owner[5:]
1023 if owner.endswith('-arg'):
1024 return '(parameter of %s)' % owner[:-4]
1025 else:
1026 assert owner.endswith('-wrapper')
1027 # Unreachable and not implemented
1028 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001029 if owner.endswith('Kind'):
1030 # See QAPISchema._make_implicit_enum_type()
1031 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001032 return '(%s of %s)' % (self.role, owner)
1033
1034 def describe(self):
1035 return "'%s' %s" % (self.name, self._pretty_owner())
1036
Markus Armbrusterac882192015-09-16 13:06:05 +02001037
Eric Blaked44f9ac2015-12-01 22:20:54 -07001038class QAPISchemaObjectTypeMember(QAPISchemaMember):
1039 def __init__(self, name, typ, optional):
1040 QAPISchemaMember.__init__(self, name)
1041 assert isinstance(typ, str)
1042 assert isinstance(optional, bool)
1043 self._type_name = typ
1044 self.type = None
1045 self.optional = optional
1046
1047 def check(self, schema):
1048 assert self.owner
1049 self.type = schema.lookup_type(self._type_name)
1050 assert self.type
1051
1052
Markus Armbrusterac882192015-09-16 13:06:05 +02001053class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001054 def __init__(self, tag_name, tag_member, variants):
1055 # Flat unions pass tag_name but not tag_member.
1056 # Simple unions and alternates pass tag_member but not tag_name.
1057 # After check(), tag_member is always set, and tag_name remains
1058 # a reliable witness of being used by a flat union.
1059 assert bool(tag_member) != bool(tag_name)
1060 assert (isinstance(tag_name, str) or
1061 isinstance(tag_member, QAPISchemaObjectTypeMember))
Markus Armbrusterac882192015-09-16 13:06:05 +02001062 for v in variants:
1063 assert isinstance(v, QAPISchemaObjectTypeVariant)
1064 self.tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001065 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001066 self.variants = variants
1067
Eric Blake88d4ef82015-11-18 01:52:50 -07001068 def set_owner(self, name):
1069 for v in self.variants:
1070 v.set_owner(name)
1071
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001072 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001073 if not self.tag_member: # flat union
Eric Blake27b60ab2015-11-18 01:52:51 -07001074 self.tag_member = seen[c_name(self.tag_name)]
1075 assert self.tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001076 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1077 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001078 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001079 # Union names must match enum values; alternate names are
1080 # checked separately. Use 'seen' to tell the two apart.
1081 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001082 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001083 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001084 v.type.check(schema)
1085
Eric Blake27b60ab2015-11-18 01:52:51 -07001086 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001087 for v in self.variants:
1088 # Reset seen map for each variant, since qapi names from one
1089 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001090 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001091 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001092
Eric Blake437db252015-09-29 16:21:02 -06001093
Markus Armbrusterac882192015-09-16 13:06:05 +02001094class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001095 role = 'branch'
1096
Markus Armbrusterac882192015-09-16 13:06:05 +02001097 def __init__(self, name, typ):
1098 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1099
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001100 # This function exists to support ugly simple union special cases
1101 # TODO get rid of them, and drop the function
1102 def simple_union_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001103 if (self.type.is_implicit() and
1104 isinstance(self.type, QAPISchemaObjectType)):
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001105 assert len(self.type.members) == 1
1106 assert not self.type.variants
1107 return self.type.members[0].type
1108 return None
1109
Markus Armbrusterac882192015-09-16 13:06:05 +02001110
1111class QAPISchemaAlternateType(QAPISchemaType):
1112 def __init__(self, name, info, variants):
1113 QAPISchemaType.__init__(self, name, info)
1114 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1115 assert not variants.tag_name
Eric Blake88d4ef82015-11-18 01:52:50 -07001116 variants.set_owner(name)
1117 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001118 self.variants = variants
1119
1120 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001121 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001122 # Not calling self.variants.check_clash(), because there's nothing
1123 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001124 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001125 # Alternate branch names have no relation to the tag enum values;
1126 # so we have to check for potential name collisions ourselves.
1127 seen = {}
1128 for v in self.variants.variants:
1129 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001130
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001131 def json_type(self):
1132 return 'value'
1133
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001134 def visit(self, visitor):
1135 visitor.visit_alternate_type(self.name, self.info, self.variants)
1136
Markus Armbrusterac882192015-09-16 13:06:05 +02001137
1138class QAPISchemaCommand(QAPISchemaEntity):
1139 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1140 QAPISchemaEntity.__init__(self, name, info)
1141 assert not arg_type or isinstance(arg_type, str)
1142 assert not ret_type or isinstance(ret_type, str)
1143 self._arg_type_name = arg_type
1144 self.arg_type = None
1145 self._ret_type_name = ret_type
1146 self.ret_type = None
1147 self.gen = gen
1148 self.success_response = success_response
1149
1150 def check(self, schema):
1151 if self._arg_type_name:
1152 self.arg_type = schema.lookup_type(self._arg_type_name)
1153 assert isinstance(self.arg_type, QAPISchemaObjectType)
1154 assert not self.arg_type.variants # not implemented
1155 if self._ret_type_name:
1156 self.ret_type = schema.lookup_type(self._ret_type_name)
1157 assert isinstance(self.ret_type, QAPISchemaType)
1158
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001159 def visit(self, visitor):
1160 visitor.visit_command(self.name, self.info,
1161 self.arg_type, self.ret_type,
1162 self.gen, self.success_response)
1163
Markus Armbrusterac882192015-09-16 13:06:05 +02001164
1165class QAPISchemaEvent(QAPISchemaEntity):
1166 def __init__(self, name, info, arg_type):
1167 QAPISchemaEntity.__init__(self, name, info)
1168 assert not arg_type or isinstance(arg_type, str)
1169 self._arg_type_name = arg_type
1170 self.arg_type = None
1171
1172 def check(self, schema):
1173 if self._arg_type_name:
1174 self.arg_type = schema.lookup_type(self._arg_type_name)
1175 assert isinstance(self.arg_type, QAPISchemaObjectType)
1176 assert not self.arg_type.variants # not implemented
1177
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001178 def visit(self, visitor):
1179 visitor.visit_event(self.name, self.info, self.arg_type)
1180
Markus Armbrusterac882192015-09-16 13:06:05 +02001181
1182class QAPISchema(object):
1183 def __init__(self, fname):
1184 try:
1185 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001186 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001187 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001188 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001189 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001190 self._def_exprs()
1191 self.check()
Markus Armbruster291928a2015-12-18 08:52:41 +01001192 except (QAPISchemaError, QAPIExprError) as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001193 print >>sys.stderr, err
1194 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001195
Markus Armbrusterac882192015-09-16 13:06:05 +02001196 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001197 # Only the predefined types are allowed to not have info
1198 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001199 assert ent.name not in self._entity_dict
1200 self._entity_dict[ent.name] = ent
1201
1202 def lookup_entity(self, name, typ=None):
1203 ent = self._entity_dict.get(name)
1204 if typ and not isinstance(ent, typ):
1205 return None
1206 return ent
1207
1208 def lookup_type(self, name):
1209 return self.lookup_entity(name, QAPISchemaType)
1210
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001211 def _def_builtin_type(self, name, json_type, c_type, c_null):
1212 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1213 c_type, c_null))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001214 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1215 # qapi-types.h from a single .c, all arrays of builtins must be
1216 # declared in the first file whether or not they are used. Nicer
1217 # would be to use lazy instantiation, while figuring out how to
1218 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001219 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001220
1221 def _def_predefineds(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001222 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1223 ('number', 'number', 'double', '0'),
1224 ('int', 'int', 'int64_t', '0'),
1225 ('int8', 'int', 'int8_t', '0'),
1226 ('int16', 'int', 'int16_t', '0'),
1227 ('int32', 'int', 'int32_t', '0'),
1228 ('int64', 'int', 'int64_t', '0'),
1229 ('uint8', 'int', 'uint8_t', '0'),
1230 ('uint16', 'int', 'uint16_t', '0'),
1231 ('uint32', 'int', 'uint32_t', '0'),
1232 ('uint64', 'int', 'uint64_t', '0'),
1233 ('size', 'int', 'uint64_t', '0'),
1234 ('bool', 'boolean', 'bool', 'false'),
Markus Armbruster28770e02015-09-16 13:06:24 +02001235 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001236 self._def_builtin_type(*t)
Markus Armbruster39a18152015-09-16 13:06:28 +02001237 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1238 [], None)
1239 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001240 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1241 'qstring', 'qdict', 'qlist',
1242 'qfloat', 'qbool'])
1243 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001244 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001245
Eric Blake93bda4d2015-12-01 22:20:55 -07001246 def _make_enum_members(self, values):
1247 return [QAPISchemaMember(v) for v in values]
1248
Eric Blake99df5282015-10-12 22:22:32 -06001249 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001250 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001251 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001252 self._def_entity(QAPISchemaEnumType(
1253 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001254 return name
1255
Eric Blake99df5282015-10-12 22:22:32 -06001256 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001257 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001258 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001259 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001260 return name
1261
Eric Blake99df5282015-10-12 22:22:32 -06001262 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001263 if not members:
1264 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001265 # See also QAPISchemaObjectTypeMember._pretty_owner()
Markus Armbrusterac882192015-09-16 13:06:05 +02001266 name = ':obj-%s-%s' % (name, role)
1267 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001268 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001269 members, None))
1270 return name
1271
1272 def _def_enum_type(self, expr, info):
1273 name = expr['enum']
1274 data = expr['data']
1275 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001276 self._def_entity(QAPISchemaEnumType(
1277 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001278
Eric Blake99df5282015-10-12 22:22:32 -06001279 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001280 optional = False
1281 if name.startswith('*'):
1282 name = name[1:]
1283 optional = True
1284 if isinstance(typ, list):
1285 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001286 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001287 return QAPISchemaObjectTypeMember(name, typ, optional)
1288
Eric Blake99df5282015-10-12 22:22:32 -06001289 def _make_members(self, data, info):
1290 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001291 for (key, value) in data.iteritems()]
1292
1293 def _def_struct_type(self, expr, info):
1294 name = expr['struct']
1295 base = expr.get('base')
1296 data = expr['data']
1297 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001298 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001299 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001300
1301 def _make_variant(self, case, typ):
1302 return QAPISchemaObjectTypeVariant(case, typ)
1303
Eric Blake99df5282015-10-12 22:22:32 -06001304 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001305 if isinstance(typ, list):
1306 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001307 typ = self._make_array_type(typ[0], info)
1308 typ = self._make_implicit_object_type(
1309 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001310 return QAPISchemaObjectTypeVariant(case, typ)
1311
Markus Armbrusterac882192015-09-16 13:06:05 +02001312 def _def_union_type(self, expr, info):
1313 name = expr['union']
1314 data = expr['data']
1315 base = expr.get('base')
1316 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001317 tag_member = None
Markus Armbrusterac882192015-09-16 13:06:05 +02001318 if tag_name:
1319 variants = [self._make_variant(key, value)
1320 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001321 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001322 else:
Eric Blake99df5282015-10-12 22:22:32 -06001323 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001324 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001325 typ = self._make_implicit_enum_type(name, info,
1326 [v.name for v in variants])
1327 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001328 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001329 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001330 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001331 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001332 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001333 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001334
1335 def _def_alternate_type(self, expr, info):
1336 name = expr['alternate']
1337 data = expr['data']
1338 variants = [self._make_variant(key, value)
1339 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001340 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001341 self._def_entity(
1342 QAPISchemaAlternateType(name, info,
1343 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001344 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001345 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001346
1347 def _def_command(self, expr, info):
1348 name = expr['command']
1349 data = expr.get('data')
1350 rets = expr.get('returns')
1351 gen = expr.get('gen', True)
1352 success_response = expr.get('success-response', True)
1353 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001354 data = self._make_implicit_object_type(
1355 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001356 if isinstance(rets, list):
1357 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001358 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001359 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1360 success_response))
1361
1362 def _def_event(self, expr, info):
1363 name = expr['event']
1364 data = expr.get('data')
1365 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001366 data = self._make_implicit_object_type(
1367 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001368 self._def_entity(QAPISchemaEvent(name, info, data))
1369
1370 def _def_exprs(self):
1371 for expr_elem in self.exprs:
1372 expr = expr_elem['expr']
1373 info = expr_elem['info']
1374 if 'enum' in expr:
1375 self._def_enum_type(expr, info)
1376 elif 'struct' in expr:
1377 self._def_struct_type(expr, info)
1378 elif 'union' in expr:
1379 self._def_union_type(expr, info)
1380 elif 'alternate' in expr:
1381 self._def_alternate_type(expr, info)
1382 elif 'command' in expr:
1383 self._def_command(expr, info)
1384 elif 'event' in expr:
1385 self._def_event(expr, info)
1386 else:
1387 assert False
1388
1389 def check(self):
1390 for ent in self._entity_dict.values():
1391 ent.check(self)
1392
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001393 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001394 visitor.visit_begin(self)
1395 for (name, entity) in sorted(self._entity_dict.items()):
1396 if visitor.visit_needed(entity):
1397 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001398 visitor.visit_end()
1399
Markus Armbruster2caba362013-07-27 17:41:56 +02001400
Markus Armbruster00e4b282015-06-10 10:04:36 +02001401#
1402# Code generation helpers
1403#
1404
Michael Roth0f923be2011-07-19 14:50:39 -05001405def camel_case(name):
1406 new_name = ''
1407 first = True
1408 for ch in name:
1409 if ch in ['_', '-']:
1410 first = True
1411 elif first:
1412 new_name += ch.upper()
1413 first = False
1414 else:
1415 new_name += ch.lower()
1416 return new_name
1417
Eric Blake437db252015-09-29 16:21:02 -06001418
Markus Armbruster849bc532015-05-14 06:50:53 -06001419# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1420# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1421# ENUM24_Name -> ENUM24_NAME
1422def camel_to_upper(value):
1423 c_fun_str = c_name(value, False)
1424 if value.isupper():
1425 return c_fun_str
1426
1427 new_name = ''
1428 l = len(c_fun_str)
1429 for i in range(l):
1430 c = c_fun_str[i]
1431 # When c is upper and no "_" appears before, do more checks
1432 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001433 if i < l - 1 and c_fun_str[i + 1].islower():
1434 new_name += '_'
1435 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001436 new_name += '_'
1437 new_name += c
1438 return new_name.lstrip('_').upper()
1439
Eric Blake437db252015-09-29 16:21:02 -06001440
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001441def c_enum_const(type_name, const_name, prefix=None):
1442 if prefix is not None:
1443 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001444 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001445
Eric Blake18df5152015-05-14 06:50:48 -06001446c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001447
Eric Blake437db252015-09-29 16:21:02 -06001448
Eric Blakec6405b52015-05-14 06:50:55 -06001449# Map @name to a valid C identifier.
1450# If @protect, avoid returning certain ticklish identifiers (like
1451# C keywords) by prepending "q_".
1452#
1453# Used for converting 'name' from a 'name':'type' qapi definition
1454# into a generated struct member, as well as converting type names
1455# into substrings of a generated C function name.
1456# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1457# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001458def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001459 # ANSI X3J11/88-090, 3.1.1
1460 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001461 'default', 'do', 'double', 'else', 'enum', 'extern',
1462 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1463 'return', 'short', 'signed', 'sizeof', 'static',
1464 'struct', 'switch', 'typedef', 'union', 'unsigned',
1465 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001466 # ISO/IEC 9899:1999, 6.4.1
1467 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1468 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001469 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1470 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001471 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1472 # excluding _.*
1473 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001474 # C++ ISO/IEC 14882:2003 2.11
1475 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1476 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1477 'namespace', 'new', 'operator', 'private', 'protected',
1478 'public', 'reinterpret_cast', 'static_cast', 'template',
1479 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1480 'using', 'virtual', 'wchar_t',
1481 # alternative representations
1482 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1483 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001484 # namespace pollution:
Max Reitz8592a542013-12-20 19:28:18 +01001485 polluted_words = set(['unix', 'errno'])
Eric Blakec43567c2015-11-18 01:52:52 -07001486 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001487 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1488 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001489 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001490 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001491
Amos Kong05dfb262014-06-10 19:25:53 +08001492eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001493pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001494
Eric Blake437db252015-09-29 16:21:02 -06001495
Michael Roth0f923be2011-07-19 14:50:39 -05001496def genindent(count):
1497 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001498 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001499 ret += " "
1500 return ret
1501
1502indent_level = 0
1503
Eric Blake437db252015-09-29 16:21:02 -06001504
Michael Roth0f923be2011-07-19 14:50:39 -05001505def push_indent(indent_amount=4):
1506 global indent_level
1507 indent_level += indent_amount
1508
Eric Blake437db252015-09-29 16:21:02 -06001509
Michael Roth0f923be2011-07-19 14:50:39 -05001510def pop_indent(indent_amount=4):
1511 global indent_level
1512 indent_level -= indent_amount
1513
Eric Blake437db252015-09-29 16:21:02 -06001514
Markus Armbruster77e703b2015-06-24 19:27:32 +02001515# Generate @code with @kwds interpolated.
1516# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001517def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001518 raw = code % kwds
1519 if indent_level:
1520 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001521 # re.subn() lacks flags support before Python 2.7, use re.compile()
1522 raw = re.subn(re.compile("^.", re.MULTILINE),
1523 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001524 raw = raw[0]
1525 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001526
Eric Blake437db252015-09-29 16:21:02 -06001527
Michael Roth0f923be2011-07-19 14:50:39 -05001528def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001529 if code[0] == '\n':
1530 code = code[1:]
1531 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001532
Michael Roth0f923be2011-07-19 14:50:39 -05001533
1534def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001535 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001536
Eric Blake437db252015-09-29 16:21:02 -06001537
Michael Rothc0afa9c2013-05-10 17:46:00 -05001538def guardstart(name):
1539 return mcgen('''
1540
1541#ifndef %(name)s
1542#define %(name)s
1543
1544''',
1545 name=guardname(name))
1546
Eric Blake437db252015-09-29 16:21:02 -06001547
Michael Rothc0afa9c2013-05-10 17:46:00 -05001548def guardend(name):
1549 return mcgen('''
1550
1551#endif /* %(name)s */
1552
1553''',
1554 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001555
Eric Blake437db252015-09-29 16:21:02 -06001556
Markus Armbrustere98859a2015-09-16 13:06:16 +02001557def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001558 ret = mcgen('''
1559
Markus Armbrustere98859a2015-09-16 13:06:16 +02001560const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001561''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001562 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001563 for value in values:
1564 index = c_enum_const(name, value, prefix)
1565 ret += mcgen('''
1566 [%(index)s] = "%(value)s",
1567''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001568 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001569
Eric Blake7fb1cf12015-11-18 01:52:57 -07001570 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001571 ret += mcgen('''
1572 [%(max_index)s] = NULL,
1573};
1574''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001575 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001576 return ret
1577
Eric Blake437db252015-09-29 16:21:02 -06001578
Markus Armbrustere98859a2015-09-16 13:06:16 +02001579def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001580 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001581 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001582
1583 ret = mcgen('''
1584
1585typedef enum %(c_name)s {
1586''',
1587 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001588
1589 i = 0
1590 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001591 ret += mcgen('''
1592 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001593''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001594 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001595 i=i)
1596 i += 1
1597
Markus Armbrustere98859a2015-09-16 13:06:16 +02001598 ret += mcgen('''
1599} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001600''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001601 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001602
Markus Armbrustere98859a2015-09-16 13:06:16 +02001603 ret += mcgen('''
1604
1605extern const char *const %(c_name)s_lookup[];
1606''',
1607 c_name=c_name(name))
1608 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001609
Eric Blake437db252015-09-29 16:21:02 -06001610
Markus Armbruster03b43672015-09-16 13:06:20 +02001611def gen_params(arg_type, extra):
1612 if not arg_type:
1613 return extra
1614 assert not arg_type.variants
1615 ret = ''
1616 sep = ''
1617 for memb in arg_type.members:
1618 ret += sep
1619 sep = ', '
1620 if memb.optional:
1621 ret += 'bool has_%s, ' % c_name(memb.name)
1622 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1623 if extra:
1624 ret += sep + extra
1625 return ret
1626
Eric Blake1f353342015-09-29 16:21:13 -06001627
Eric Blake18bdbc32015-09-29 16:21:15 -06001628def gen_err_check(label='out', skiperr=False):
1629 if skiperr:
Eric Blake1f353342015-09-29 16:21:13 -06001630 return ''
1631 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001632 if (err) {
Eric Blake1f353342015-09-29 16:21:13 -06001633 goto %(label)s;
1634 }
1635''',
Eric Blake18bdbc32015-09-29 16:21:15 -06001636 label=label)
Eric Blake1f353342015-09-29 16:21:13 -06001637
1638
Eric Blake18bdbc32015-09-29 16:21:15 -06001639def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
Eric Blake82ca8e42015-09-29 16:21:14 -06001640 ret = ''
Eric Blake18bdbc32015-09-29 16:21:15 -06001641 if skiperr:
Eric Blake82ca8e42015-09-29 16:21:14 -06001642 errparg = 'NULL'
Eric Blake18bdbc32015-09-29 16:21:15 -06001643 else:
1644 errparg = '&err'
Eric Blake82ca8e42015-09-29 16:21:14 -06001645
1646 for memb in members:
1647 if memb.optional:
1648 ret += mcgen('''
Eric Blake29637a62015-12-01 22:20:53 -07001649 if (visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s")) {
Eric Blake82ca8e42015-09-29 16:21:14 -06001650''',
1651 prefix=prefix, c_name=c_name(memb.name),
1652 name=memb.name, errp=errparg)
Eric Blake82ca8e42015-09-29 16:21:14 -06001653 push_indent()
1654
1655 # Ugly: sometimes we need to cast away const
1656 if need_cast and memb.type.name == 'str':
1657 cast = '(char **)'
1658 else:
1659 cast = ''
1660
1661 ret += mcgen('''
1662 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1663''',
1664 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1665 c_name=c_name(memb.name), name=memb.name,
1666 errp=errparg)
Eric Blake18bdbc32015-09-29 16:21:15 -06001667 ret += gen_err_check(skiperr=skiperr)
Eric Blake82ca8e42015-09-29 16:21:14 -06001668
1669 if memb.optional:
1670 pop_indent()
1671 ret += mcgen('''
1672 }
1673''')
1674 return ret
1675
1676
Markus Armbruster00e4b282015-06-10 10:04:36 +02001677#
1678# Common command line parsing
1679#
1680
Eric Blake437db252015-09-29 16:21:02 -06001681
1682def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001683
1684 try:
1685 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001686 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001687 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001688 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001689 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001690 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001691 sys.exit(1)
1692
1693 output_dir = ""
1694 prefix = ""
1695 do_c = False
1696 do_h = False
1697 extra_opts = []
1698
1699 for oa in opts:
1700 o, a = oa
1701 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001702 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1703 if match.end() != len(a):
1704 print >>sys.stderr, \
1705 "%s: 'funny character '%s' in argument of --prefix" \
1706 % (sys.argv[0], a[match.end()])
1707 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001708 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001709 elif o in ("-o", "--output-dir"):
1710 output_dir = a + "/"
1711 elif o in ("-c", "--source"):
1712 do_c = True
1713 elif o in ("-h", "--header"):
1714 do_h = True
1715 else:
1716 extra_opts.append(oa)
1717
1718 if not do_c and not do_h:
1719 do_c = True
1720 do_h = True
1721
Markus Armbruster16d80f62015-04-02 13:32:16 +02001722 if len(args) != 1:
1723 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001724 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001725 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001726
Markus Armbruster54414042015-06-09 16:22:45 +02001727 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001728
Markus Armbruster00e4b282015-06-10 10:04:36 +02001729#
1730# Generate output files with boilerplate
1731#
1732
Eric Blake437db252015-09-29 16:21:02 -06001733
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001734def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1735 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001736 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001737 c_file = output_dir + prefix + c_file
1738 h_file = output_dir + prefix + h_file
1739
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001740 if output_dir:
1741 try:
1742 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01001743 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001744 if e.errno != errno.EEXIST:
1745 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001746
1747 def maybe_open(really, name, opt):
1748 if really:
1749 return open(name, opt)
1750 else:
1751 import StringIO
1752 return StringIO.StringIO()
1753
1754 fdef = maybe_open(do_c, c_file, 'w')
1755 fdecl = maybe_open(do_h, h_file, 'w')
1756
1757 fdef.write(mcgen('''
1758/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1759%(comment)s
1760''',
Eric Blake437db252015-09-29 16:21:02 -06001761 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001762
1763 fdecl.write(mcgen('''
1764/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1765%(comment)s
1766#ifndef %(guard)s
1767#define %(guard)s
1768
1769''',
Eric Blake437db252015-09-29 16:21:02 -06001770 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001771
1772 return (fdef, fdecl)
1773
Eric Blake437db252015-09-29 16:21:02 -06001774
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001775def close_output(fdef, fdecl):
1776 fdecl.write('''
1777#endif
1778''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001779 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001780 fdef.close()