blob: 8497777d941a6e7e8edee230d598b4a029c6ea65 [file] [log] [blame]
Michael Roth0f923be2011-07-19 14:50:39 -05001#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
Eric Blakee4083112016-01-29 06:48:41 -07005# Copyright (c) 2013-2016 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
Eric Blake02a57ae2016-02-17 23:48:16 -0700593 # Check every branch; don't allow an empty union
594 if len(members) == 0:
595 raise QAPIExprError(expr_info,
596 "Union '%s' cannot have empty 'data'" % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800597 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600598 check_name(expr_info, "Member of union '%s'" % name, key)
599
Eric Blake01cfbaa2015-12-01 22:20:58 -0700600 # Each value must name a known type
Eric Blakedd883c62015-05-04 09:05:21 -0600601 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200602 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakedd883c62015-05-04 09:05:21 -0600603
Eric Blake44bd1272015-05-04 09:05:08 -0600604 # If the discriminator names an enum type, then all members
Eric Blake61a94662015-11-18 01:52:49 -0700605 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600606 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600607 if key not in enum_define['enum_values']:
Eric Blake44bd1272015-05-04 09:05:08 -0600608 raise QAPIExprError(expr_info,
609 "Discriminator value '%s' is not found in "
610 "enum '%s'" %
611 (key, enum_define["enum_name"]))
612
Eric Blake437db252015-09-29 16:21:02 -0600613
Eric Blake811d04f2015-05-04 09:05:10 -0600614def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600615 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600616 members = expr['data']
Eric Blake811d04f2015-05-04 09:05:10 -0600617 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600618
Eric Blake02a57ae2016-02-17 23:48:16 -0700619 # Check every branch; require at least two branches
620 if len(members) < 2:
621 raise QAPIExprError(expr_info,
622 "Alternate '%s' should have at least two branches "
623 "in 'data'" % name)
Eric Blake811d04f2015-05-04 09:05:10 -0600624 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600625 check_name(expr_info, "Member of alternate '%s'" % name, key)
626
Eric Blake811d04f2015-05-04 09:05:10 -0600627 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600628 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
629 value,
630 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600631 qtype = find_alternate_member_qtype(value)
Eric Blake46534302016-02-17 23:48:17 -0700632 if not qtype:
633 raise QAPIExprError(expr_info,
634 "Alternate '%s' member '%s' cannot use "
635 "type '%s'" % (name, key, value))
Eric Blake811d04f2015-05-04 09:05:10 -0600636 if qtype in types_seen:
637 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600638 "Alternate '%s' member '%s' can't "
Eric Blake811d04f2015-05-04 09:05:10 -0600639 "be distinguished from member '%s'"
640 % (name, key, types_seen[qtype]))
641 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800642
Eric Blake437db252015-09-29 16:21:02 -0600643
Eric Blakecf393592015-05-04 09:05:04 -0600644def check_enum(expr, expr_info):
645 name = expr['enum']
646 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100647 prefix = expr.get('prefix')
Eric Blakecf393592015-05-04 09:05:04 -0600648
649 if not isinstance(members, list):
650 raise QAPIExprError(expr_info,
651 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100652 if prefix is not None and not isinstance(prefix, str):
653 raise QAPIExprError(expr_info,
654 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600655 for member in members:
Eric Blake437db252015-09-29 16:21:02 -0600656 check_name(expr_info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600657 enum_member=True)
Eric Blakecf393592015-05-04 09:05:04 -0600658
Eric Blake437db252015-09-29 16:21:02 -0600659
Eric Blakedd883c62015-05-04 09:05:21 -0600660def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600661 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600662 members = expr['data']
663
Eric Blakefd41dd42015-05-04 09:05:25 -0600664 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600665 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600666 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600667 allow_metas=['struct'])
668
Eric Blake437db252015-09-29 16:21:02 -0600669
Eric Blake0545f6b2015-05-04 09:05:15 -0600670def check_keys(expr_elem, meta, required, optional=[]):
671 expr = expr_elem['expr']
672 info = expr_elem['info']
673 name = expr[meta]
674 if not isinstance(name, str):
675 raise QAPIExprError(info,
676 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600677 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600678 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600679 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600680 raise QAPIExprError(info,
681 "Unknown key '%s' in %s '%s'"
682 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600683 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600684 raise QAPIExprError(info,
685 "'%s' of %s '%s' should only use false value"
686 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600687 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600688 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600689 raise QAPIExprError(info,
690 "Key '%s' is missing from %s '%s'"
691 % (key, meta, name))
692
Eric Blake437db252015-09-29 16:21:02 -0600693
Markus Armbruster4d076d62015-06-10 08:55:21 +0200694def check_exprs(exprs):
695 global all_names
696
697 # Learn the types and check for valid expression keys
698 for builtin in builtin_types.keys():
699 all_names[builtin] = 'built-in'
700 for expr_elem in exprs:
701 expr = expr_elem['expr']
702 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600703 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100704 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200705 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600706 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200707 check_keys(expr_elem, 'union', ['data'],
708 ['base', 'discriminator'])
709 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600710 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200711 check_keys(expr_elem, 'alternate', ['data'])
712 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600713 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200714 check_keys(expr_elem, 'struct', ['data'], ['base'])
715 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600716 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200717 check_keys(expr_elem, 'command', [],
718 ['data', 'returns', 'gen', 'success-response'])
719 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600720 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200721 check_keys(expr_elem, 'event', [], ['data'])
722 add_name(expr['event'], info, 'event')
723 else:
724 raise QAPIExprError(expr_elem['info'],
725 "Expression is missing metatype")
726
727 # Try again for hidden UnionKind enum
728 for expr_elem in exprs:
729 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600730 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200731 if not discriminator_find_enum_define(expr):
732 add_enum('%sKind' % expr['union'], expr_elem['info'],
733 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600734 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200735 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
736 implicit=True)
737
738 # Validate that exprs make sense
739 for expr_elem in exprs:
740 expr = expr_elem['expr']
741 info = expr_elem['info']
742
Eric Blake437db252015-09-29 16:21:02 -0600743 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200744 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600745 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200746 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600747 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200748 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600749 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200750 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600751 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200752 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600753 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200754 check_event(expr, info)
755 else:
756 assert False, 'unexpected meta type'
757
Markus Armbrusterac882192015-09-16 13:06:05 +0200758 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600759
Markus Armbrusterac882192015-09-16 13:06:05 +0200760
761#
762# Schema compiler frontend
763#
764
765class QAPISchemaEntity(object):
766 def __init__(self, name, info):
767 assert isinstance(name, str)
768 self.name = name
Eric Blake99df5282015-10-12 22:22:32 -0600769 # For explicitly defined entities, info points to the (explicit)
770 # definition. For builtins (and their arrays), info is None.
771 # For implicitly defined entities, info points to a place that
772 # triggered the implicit definition (there may be more than one
773 # such place).
Markus Armbrusterac882192015-09-16 13:06:05 +0200774 self.info = info
775
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200776 def c_name(self):
777 return c_name(self.name)
778
Markus Armbrusterac882192015-09-16 13:06:05 +0200779 def check(self, schema):
780 pass
781
Eric Blake49823c42015-10-12 22:22:27 -0600782 def is_implicit(self):
783 return not self.info
784
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200785 def visit(self, visitor):
786 pass
787
788
789class QAPISchemaVisitor(object):
790 def visit_begin(self, schema):
791 pass
792
793 def visit_end(self):
794 pass
795
Eric Blake25a0d9c2015-10-12 22:22:21 -0600796 def visit_needed(self, entity):
797 # Default to visiting everything
798 return True
799
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200800 def visit_builtin_type(self, name, info, json_type):
801 pass
802
803 def visit_enum_type(self, name, info, values, prefix):
804 pass
805
806 def visit_array_type(self, name, info, element_type):
807 pass
808
809 def visit_object_type(self, name, info, base, members, variants):
810 pass
811
Markus Armbruster39a18152015-09-16 13:06:28 +0200812 def visit_object_type_flat(self, name, info, members, variants):
813 pass
814
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200815 def visit_alternate_type(self, name, info, variants):
816 pass
817
818 def visit_command(self, name, info, arg_type, ret_type,
819 gen, success_response):
820 pass
821
822 def visit_event(self, name, info, arg_type):
823 pass
824
Markus Armbrusterac882192015-09-16 13:06:05 +0200825
826class QAPISchemaType(QAPISchemaEntity):
Eric Blakebecceed2016-02-17 23:48:26 -0700827 def c_type(self, is_param=False, is_unboxed=False):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200828 return c_name(self.name) + pointer_suffix
829
830 def c_null(self):
831 return 'NULL'
832
833 def json_type(self):
834 pass
835
836 def alternate_qtype(self):
837 json2qtype = {
838 'string': 'QTYPE_QSTRING',
839 'number': 'QTYPE_QFLOAT',
840 'int': 'QTYPE_QINT',
841 'boolean': 'QTYPE_QBOOL',
842 'object': 'QTYPE_QDICT'
843 }
844 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200845
846
847class QAPISchemaBuiltinType(QAPISchemaType):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200848 def __init__(self, name, json_type, c_type, c_null):
Markus Armbrusterac882192015-09-16 13:06:05 +0200849 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200850 assert not c_type or isinstance(c_type, str)
851 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
852 'value')
853 self._json_type_name = json_type
854 self._c_type_name = c_type
855 self._c_null_val = c_null
856
857 def c_name(self):
858 return self.name
859
Eric Blakebecceed2016-02-17 23:48:26 -0700860 def c_type(self, is_param=False, is_unboxed=False):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200861 if is_param and self.name == 'str':
862 return 'const ' + self._c_type_name
863 return self._c_type_name
864
865 def c_null(self):
866 return self._c_null_val
867
868 def json_type(self):
869 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200870
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200871 def visit(self, visitor):
872 visitor.visit_builtin_type(self.name, self.info, self.json_type())
873
Markus Armbrusterac882192015-09-16 13:06:05 +0200874
875class QAPISchemaEnumType(QAPISchemaType):
876 def __init__(self, name, info, values, prefix):
877 QAPISchemaType.__init__(self, name, info)
878 for v in values:
Eric Blake93bda4d2015-12-01 22:20:55 -0700879 assert isinstance(v, QAPISchemaMember)
880 v.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200881 assert prefix is None or isinstance(prefix, str)
882 self.values = values
883 self.prefix = prefix
884
885 def check(self, schema):
Eric Blake93bda4d2015-12-01 22:20:55 -0700886 seen = {}
887 for v in self.values:
888 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200889
Eric Blake99df5282015-10-12 22:22:32 -0600890 def is_implicit(self):
891 # See QAPISchema._make_implicit_enum_type()
Eric Blake8712fa52015-10-26 16:34:41 -0600892 return self.name.endswith('Kind')
Eric Blake99df5282015-10-12 22:22:32 -0600893
Eric Blakebecceed2016-02-17 23:48:26 -0700894 def c_type(self, is_param=False, is_unboxed=False):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200895 return c_name(self.name)
896
Eric Blake93bda4d2015-12-01 22:20:55 -0700897 def member_names(self):
898 return [v.name for v in self.values]
899
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200900 def c_null(self):
Eric Blake93bda4d2015-12-01 22:20:55 -0700901 return c_enum_const(self.name, (self.member_names() + ['_MAX'])[0],
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200902 self.prefix)
903
904 def json_type(self):
905 return 'string'
906
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200907 def visit(self, visitor):
908 visitor.visit_enum_type(self.name, self.info,
Eric Blake93bda4d2015-12-01 22:20:55 -0700909 self.member_names(), self.prefix)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200910
Markus Armbrusterac882192015-09-16 13:06:05 +0200911
912class QAPISchemaArrayType(QAPISchemaType):
913 def __init__(self, name, info, element_type):
914 QAPISchemaType.__init__(self, name, info)
915 assert isinstance(element_type, str)
916 self._element_type_name = element_type
917 self.element_type = None
918
919 def check(self, schema):
920 self.element_type = schema.lookup_type(self._element_type_name)
921 assert self.element_type
922
Eric Blake99df5282015-10-12 22:22:32 -0600923 def is_implicit(self):
924 return True
925
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200926 def json_type(self):
927 return 'array'
928
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200929 def visit(self, visitor):
930 visitor.visit_array_type(self.name, self.info, self.element_type)
931
Markus Armbrusterac882192015-09-16 13:06:05 +0200932
933class QAPISchemaObjectType(QAPISchemaType):
934 def __init__(self, name, info, base, local_members, variants):
Eric Blakeda34a9b2015-11-18 01:52:36 -0700935 # struct has local_members, optional base, and no variants
936 # flat union has base, variants, and no local_members
937 # simple union has local_members, variants, and no base
Markus Armbrusterac882192015-09-16 13:06:05 +0200938 QAPISchemaType.__init__(self, name, info)
939 assert base is None or isinstance(base, str)
940 for m in local_members:
941 assert isinstance(m, QAPISchemaObjectTypeMember)
Eric Blake88d4ef82015-11-18 01:52:50 -0700942 m.set_owner(name)
943 if variants is not None:
944 assert isinstance(variants, QAPISchemaObjectTypeVariants)
945 variants.set_owner(name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200946 self._base_name = base
947 self.base = None
948 self.local_members = local_members
949 self.variants = variants
950 self.members = None
951
952 def check(self, schema):
Eric Blakebac54292015-12-01 22:20:59 -0700953 if self.members is False: # check for cycles
954 raise QAPIExprError(self.info,
955 "Object %s contains itself" % self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +0200956 if self.members:
957 return
958 self.members = False # mark as being checked
Markus Armbruster23a4b2c2015-11-18 01:52:43 -0700959 seen = OrderedDict()
Markus Armbrusterac882192015-09-16 13:06:05 +0200960 if self._base_name:
961 self.base = schema.lookup_type(self._base_name)
962 assert isinstance(self.base, QAPISchemaObjectType)
Markus Armbrusterac882192015-09-16 13:06:05 +0200963 self.base.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700964 self.base.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200965 for m in self.local_members:
Markus Armbrustere564e2d2015-11-18 01:52:40 -0700966 m.check(schema)
Eric Blake27b60ab2015-11-18 01:52:51 -0700967 m.check_clash(self.info, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700968 self.members = seen.values()
Markus Armbrusterac882192015-09-16 13:06:05 +0200969 if self.variants:
Markus Armbrustercdc5fa32015-11-18 01:52:41 -0700970 self.variants.check(schema, seen)
Markus Armbruster14ff8462015-11-18 01:52:45 -0700971 assert self.variants.tag_member in self.members
Eric Blake27b60ab2015-11-18 01:52:51 -0700972 self.variants.check_clash(schema, self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +0200973
Eric Blake27b60ab2015-11-18 01:52:51 -0700974 # Check that the members of this type do not cause duplicate JSON fields,
975 # and update seen to track the members seen so far. Report any errors
976 # on behalf of info, which is not necessarily self.info
977 def check_clash(self, schema, info, seen):
Eric Blakec2183d22015-11-18 01:52:47 -0700978 assert not self.variants # not implemented
979 for m in self.members:
Eric Blake27b60ab2015-11-18 01:52:51 -0700980 m.check_clash(info, seen)
Eric Blakec2183d22015-11-18 01:52:47 -0700981
Eric Blake99df5282015-10-12 22:22:32 -0600982 def is_implicit(self):
983 # See QAPISchema._make_implicit_object_type()
984 return self.name[0] == ':'
985
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200986 def c_name(self):
Eric Blake49823c42015-10-12 22:22:27 -0600987 assert not self.is_implicit()
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200988 return QAPISchemaType.c_name(self)
989
Eric Blakebecceed2016-02-17 23:48:26 -0700990 def c_type(self, is_param=False, is_unboxed=False):
Eric Blake49823c42015-10-12 22:22:27 -0600991 assert not self.is_implicit()
Eric Blakebecceed2016-02-17 23:48:26 -0700992 if is_unboxed:
993 return c_name(self.name)
994 return c_name(self.name) + pointer_suffix
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200995
996 def json_type(self):
997 return 'object'
998
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200999 def visit(self, visitor):
1000 visitor.visit_object_type(self.name, self.info,
1001 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +02001002 visitor.visit_object_type_flat(self.name, self.info,
1003 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001004
Markus Armbrusterac882192015-09-16 13:06:05 +02001005
Eric Blaked44f9ac2015-12-01 22:20:54 -07001006class QAPISchemaMember(object):
Eric Blake88d4ef82015-11-18 01:52:50 -07001007 role = 'member'
1008
Eric Blaked44f9ac2015-12-01 22:20:54 -07001009 def __init__(self, name):
Markus Armbrusterac882192015-09-16 13:06:05 +02001010 assert isinstance(name, str)
Markus Armbrusterac882192015-09-16 13:06:05 +02001011 self.name = name
Eric Blake88d4ef82015-11-18 01:52:50 -07001012 self.owner = None
1013
1014 def set_owner(self, name):
1015 assert not self.owner
1016 self.owner = name
Markus Armbrusterac882192015-09-16 13:06:05 +02001017
Eric Blake27b60ab2015-11-18 01:52:51 -07001018 def check_clash(self, info, seen):
1019 cname = c_name(self.name)
Eric Blake893e1f22015-12-01 22:20:57 -07001020 if cname.lower() != cname and self.owner not in case_whitelist:
1021 raise QAPIExprError(info,
1022 "%s should not use uppercase" % self.describe())
Eric Blake27b60ab2015-11-18 01:52:51 -07001023 if cname in seen:
1024 raise QAPIExprError(info,
1025 "%s collides with %s"
1026 % (self.describe(), seen[cname].describe()))
1027 seen[cname] = self
Markus Armbruster577de122015-11-18 01:52:44 -07001028
Eric Blake88d4ef82015-11-18 01:52:50 -07001029 def _pretty_owner(self):
1030 owner = self.owner
1031 if owner.startswith(':obj-'):
1032 # See QAPISchema._make_implicit_object_type() - reverse the
1033 # mapping there to create a nice human-readable description
1034 owner = owner[5:]
1035 if owner.endswith('-arg'):
1036 return '(parameter of %s)' % owner[:-4]
1037 else:
1038 assert owner.endswith('-wrapper')
1039 # Unreachable and not implemented
1040 assert False
Eric Blake93bda4d2015-12-01 22:20:55 -07001041 if owner.endswith('Kind'):
1042 # See QAPISchema._make_implicit_enum_type()
1043 return '(branch of %s)' % owner[:-4]
Eric Blake88d4ef82015-11-18 01:52:50 -07001044 return '(%s of %s)' % (self.role, owner)
1045
1046 def describe(self):
1047 return "'%s' %s" % (self.name, self._pretty_owner())
1048
Markus Armbrusterac882192015-09-16 13:06:05 +02001049
Eric Blaked44f9ac2015-12-01 22:20:54 -07001050class QAPISchemaObjectTypeMember(QAPISchemaMember):
1051 def __init__(self, name, typ, optional):
1052 QAPISchemaMember.__init__(self, name)
1053 assert isinstance(typ, str)
1054 assert isinstance(optional, bool)
1055 self._type_name = typ
1056 self.type = None
1057 self.optional = optional
1058
1059 def check(self, schema):
1060 assert self.owner
1061 self.type = schema.lookup_type(self._type_name)
1062 assert self.type
1063
1064
Markus Armbrusterac882192015-09-16 13:06:05 +02001065class QAPISchemaObjectTypeVariants(object):
Eric Blake46292ba2015-10-12 22:22:29 -06001066 def __init__(self, tag_name, tag_member, variants):
1067 # Flat unions pass tag_name but not tag_member.
1068 # Simple unions and alternates pass tag_member but not tag_name.
1069 # After check(), tag_member is always set, and tag_name remains
1070 # a reliable witness of being used by a flat union.
1071 assert bool(tag_member) != bool(tag_name)
1072 assert (isinstance(tag_name, str) or
1073 isinstance(tag_member, QAPISchemaObjectTypeMember))
Eric Blake02a57ae2016-02-17 23:48:16 -07001074 assert len(variants) > 0
Markus Armbrusterac882192015-09-16 13:06:05 +02001075 for v in variants:
1076 assert isinstance(v, QAPISchemaObjectTypeVariant)
1077 self.tag_name = tag_name
Eric Blake46292ba2015-10-12 22:22:29 -06001078 self.tag_member = tag_member
Markus Armbrusterac882192015-09-16 13:06:05 +02001079 self.variants = variants
1080
Eric Blake88d4ef82015-11-18 01:52:50 -07001081 def set_owner(self, name):
1082 for v in self.variants:
1083 v.set_owner(name)
1084
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001085 def check(self, schema, seen):
Markus Armbruster14ff8462015-11-18 01:52:45 -07001086 if not self.tag_member: # flat union
Eric Blake27b60ab2015-11-18 01:52:51 -07001087 self.tag_member = seen[c_name(self.tag_name)]
1088 assert self.tag_name == self.tag_member.name
Markus Armbrusterac882192015-09-16 13:06:05 +02001089 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1090 for v in self.variants:
Eric Blake10565ca2015-11-18 01:52:48 -07001091 v.check(schema)
Eric Blake0426d532015-12-01 22:20:48 -07001092 # Union names must match enum values; alternate names are
1093 # checked separately. Use 'seen' to tell the two apart.
1094 if seen:
Eric Blake93bda4d2015-12-01 22:20:55 -07001095 assert v.name in self.tag_member.type.member_names()
Eric Blake0426d532015-12-01 22:20:48 -07001096 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001097 v.type.check(schema)
1098
Eric Blake27b60ab2015-11-18 01:52:51 -07001099 def check_clash(self, schema, info, seen):
Eric Blakeb807a1e2015-11-18 01:52:46 -07001100 for v in self.variants:
1101 # Reset seen map for each variant, since qapi names from one
1102 # branch do not affect another branch
Eric Blakeb807a1e2015-11-18 01:52:46 -07001103 assert isinstance(v.type, QAPISchemaObjectType)
Eric Blake27b60ab2015-11-18 01:52:51 -07001104 v.type.check_clash(schema, info, dict(seen))
Markus Armbrusterac882192015-09-16 13:06:05 +02001105
Eric Blake437db252015-09-29 16:21:02 -06001106
Markus Armbrusterac882192015-09-16 13:06:05 +02001107class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
Eric Blake88d4ef82015-11-18 01:52:50 -07001108 role = 'branch'
1109
Markus Armbrusterac882192015-09-16 13:06:05 +02001110 def __init__(self, name, typ):
1111 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1112
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001113 # This function exists to support ugly simple union special cases
1114 # TODO get rid of them, and drop the function
1115 def simple_union_type(self):
Eric Blake49823c42015-10-12 22:22:27 -06001116 if (self.type.is_implicit() and
1117 isinstance(self.type, QAPISchemaObjectType)):
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001118 assert len(self.type.members) == 1
1119 assert not self.type.variants
1120 return self.type.members[0].type
1121 return None
1122
Markus Armbrusterac882192015-09-16 13:06:05 +02001123
1124class QAPISchemaAlternateType(QAPISchemaType):
1125 def __init__(self, name, info, variants):
1126 QAPISchemaType.__init__(self, name, info)
1127 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1128 assert not variants.tag_name
Eric Blake88d4ef82015-11-18 01:52:50 -07001129 variants.set_owner(name)
1130 variants.tag_member.set_owner(self.name)
Markus Armbrusterac882192015-09-16 13:06:05 +02001131 self.variants = variants
1132
1133 def check(self, schema):
Markus Armbrustere564e2d2015-11-18 01:52:40 -07001134 self.variants.tag_member.check(schema)
Eric Blakeb807a1e2015-11-18 01:52:46 -07001135 # Not calling self.variants.check_clash(), because there's nothing
1136 # to clash with
Markus Armbrustercdc5fa32015-11-18 01:52:41 -07001137 self.variants.check(schema, {})
Eric Blake0426d532015-12-01 22:20:48 -07001138 # Alternate branch names have no relation to the tag enum values;
1139 # so we have to check for potential name collisions ourselves.
1140 seen = {}
1141 for v in self.variants.variants:
1142 v.check_clash(self.info, seen)
Markus Armbrusterac882192015-09-16 13:06:05 +02001143
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001144 def json_type(self):
1145 return 'value'
1146
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001147 def visit(self, visitor):
1148 visitor.visit_alternate_type(self.name, self.info, self.variants)
1149
Markus Armbrusterac882192015-09-16 13:06:05 +02001150
1151class QAPISchemaCommand(QAPISchemaEntity):
1152 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1153 QAPISchemaEntity.__init__(self, name, info)
1154 assert not arg_type or isinstance(arg_type, str)
1155 assert not ret_type or isinstance(ret_type, str)
1156 self._arg_type_name = arg_type
1157 self.arg_type = None
1158 self._ret_type_name = ret_type
1159 self.ret_type = None
1160 self.gen = gen
1161 self.success_response = success_response
1162
1163 def check(self, schema):
1164 if self._arg_type_name:
1165 self.arg_type = schema.lookup_type(self._arg_type_name)
1166 assert isinstance(self.arg_type, QAPISchemaObjectType)
1167 assert not self.arg_type.variants # not implemented
1168 if self._ret_type_name:
1169 self.ret_type = schema.lookup_type(self._ret_type_name)
1170 assert isinstance(self.ret_type, QAPISchemaType)
1171
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001172 def visit(self, visitor):
1173 visitor.visit_command(self.name, self.info,
1174 self.arg_type, self.ret_type,
1175 self.gen, self.success_response)
1176
Markus Armbrusterac882192015-09-16 13:06:05 +02001177
1178class QAPISchemaEvent(QAPISchemaEntity):
1179 def __init__(self, name, info, arg_type):
1180 QAPISchemaEntity.__init__(self, name, info)
1181 assert not arg_type or isinstance(arg_type, str)
1182 self._arg_type_name = arg_type
1183 self.arg_type = None
1184
1185 def check(self, schema):
1186 if self._arg_type_name:
1187 self.arg_type = schema.lookup_type(self._arg_type_name)
1188 assert isinstance(self.arg_type, QAPISchemaObjectType)
1189 assert not self.arg_type.variants # not implemented
1190
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001191 def visit(self, visitor):
1192 visitor.visit_event(self.name, self.info, self.arg_type)
1193
Markus Armbrusterac882192015-09-16 13:06:05 +02001194
1195class QAPISchema(object):
1196 def __init__(self, fname):
1197 try:
1198 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
Eric Blake7618b912015-10-12 22:22:22 -06001199 self._entity_dict = {}
Eric Blake99df5282015-10-12 22:22:32 -06001200 self._predefining = True
Eric Blake7618b912015-10-12 22:22:22 -06001201 self._def_predefineds()
Eric Blake99df5282015-10-12 22:22:32 -06001202 self._predefining = False
Eric Blake7618b912015-10-12 22:22:22 -06001203 self._def_exprs()
1204 self.check()
Markus Armbruster291928a2015-12-18 08:52:41 +01001205 except (QAPISchemaError, QAPIExprError) as err:
Markus Armbrusterac882192015-09-16 13:06:05 +02001206 print >>sys.stderr, err
1207 exit(1)
Markus Armbrusterac882192015-09-16 13:06:05 +02001208
Markus Armbrusterac882192015-09-16 13:06:05 +02001209 def _def_entity(self, ent):
Eric Blake99df5282015-10-12 22:22:32 -06001210 # Only the predefined types are allowed to not have info
1211 assert ent.info or self._predefining
Markus Armbrusterac882192015-09-16 13:06:05 +02001212 assert ent.name not in self._entity_dict
1213 self._entity_dict[ent.name] = ent
1214
1215 def lookup_entity(self, name, typ=None):
1216 ent = self._entity_dict.get(name)
1217 if typ and not isinstance(ent, typ):
1218 return None
1219 return ent
1220
1221 def lookup_type(self, name):
1222 return self.lookup_entity(name, QAPISchemaType)
1223
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001224 def _def_builtin_type(self, name, json_type, c_type, c_null):
1225 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1226 c_type, c_null))
Eric Blake9f08c8e2015-10-12 22:22:28 -06001227 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1228 # qapi-types.h from a single .c, all arrays of builtins must be
1229 # declared in the first file whether or not they are used. Nicer
1230 # would be to use lazy instantiation, while figuring out how to
1231 # avoid compilation issues with multiple qapi-types.h.
Eric Blake99df5282015-10-12 22:22:32 -06001232 self._make_array_type(name, None)
Markus Armbrusterac882192015-09-16 13:06:05 +02001233
1234 def _def_predefineds(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001235 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1236 ('number', 'number', 'double', '0'),
1237 ('int', 'int', 'int64_t', '0'),
1238 ('int8', 'int', 'int8_t', '0'),
1239 ('int16', 'int', 'int16_t', '0'),
1240 ('int32', 'int', 'int32_t', '0'),
1241 ('int64', 'int', 'int64_t', '0'),
1242 ('uint8', 'int', 'uint8_t', '0'),
1243 ('uint16', 'int', 'uint16_t', '0'),
1244 ('uint32', 'int', 'uint32_t', '0'),
1245 ('uint64', 'int', 'uint64_t', '0'),
1246 ('size', 'int', 'uint64_t', '0'),
1247 ('bool', 'boolean', 'bool', 'false'),
Markus Armbruster28770e02015-09-16 13:06:24 +02001248 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001249 self._def_builtin_type(*t)
Markus Armbruster39a18152015-09-16 13:06:28 +02001250 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1251 [], None)
1252 self._def_entity(self.the_empty_object_type)
Eric Blake93bda4d2015-12-01 22:20:55 -07001253 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1254 'qstring', 'qdict', 'qlist',
1255 'qfloat', 'qbool'])
1256 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
Eric Blake7264f5c2015-12-01 22:20:47 -07001257 'QTYPE'))
Markus Armbrusterac882192015-09-16 13:06:05 +02001258
Eric Blake93bda4d2015-12-01 22:20:55 -07001259 def _make_enum_members(self, values):
1260 return [QAPISchemaMember(v) for v in values]
1261
Eric Blake99df5282015-10-12 22:22:32 -06001262 def _make_implicit_enum_type(self, name, info, values):
Eric Blake93bda4d2015-12-01 22:20:55 -07001263 # See also QAPISchemaObjectTypeMember._pretty_owner()
Eric Blake49823c42015-10-12 22:22:27 -06001264 name = name + 'Kind' # Use namespace reserved by add_name()
Eric Blake93bda4d2015-12-01 22:20:55 -07001265 self._def_entity(QAPISchemaEnumType(
1266 name, info, self._make_enum_members(values), None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001267 return name
1268
Eric Blake99df5282015-10-12 22:22:32 -06001269 def _make_array_type(self, element_type, info):
Eric Blake255960d2015-10-26 16:34:43 -06001270 name = element_type + 'List' # Use namespace reserved by add_name()
Markus Armbrusterac882192015-09-16 13:06:05 +02001271 if not self.lookup_type(name):
Eric Blake99df5282015-10-12 22:22:32 -06001272 self._def_entity(QAPISchemaArrayType(name, info, element_type))
Markus Armbrusterac882192015-09-16 13:06:05 +02001273 return name
1274
Eric Blake99df5282015-10-12 22:22:32 -06001275 def _make_implicit_object_type(self, name, info, role, members):
Markus Armbrusterac882192015-09-16 13:06:05 +02001276 if not members:
1277 return None
Eric Blake88d4ef82015-11-18 01:52:50 -07001278 # See also QAPISchemaObjectTypeMember._pretty_owner()
Markus Armbrusterac882192015-09-16 13:06:05 +02001279 name = ':obj-%s-%s' % (name, role)
1280 if not self.lookup_entity(name, QAPISchemaObjectType):
Eric Blake99df5282015-10-12 22:22:32 -06001281 self._def_entity(QAPISchemaObjectType(name, info, None,
Markus Armbrusterac882192015-09-16 13:06:05 +02001282 members, None))
1283 return name
1284
1285 def _def_enum_type(self, expr, info):
1286 name = expr['enum']
1287 data = expr['data']
1288 prefix = expr.get('prefix')
Eric Blake93bda4d2015-12-01 22:20:55 -07001289 self._def_entity(QAPISchemaEnumType(
1290 name, info, self._make_enum_members(data), prefix))
Markus Armbrusterac882192015-09-16 13:06:05 +02001291
Eric Blake99df5282015-10-12 22:22:32 -06001292 def _make_member(self, name, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001293 optional = False
1294 if name.startswith('*'):
1295 name = name[1:]
1296 optional = True
1297 if isinstance(typ, list):
1298 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001299 typ = self._make_array_type(typ[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001300 return QAPISchemaObjectTypeMember(name, typ, optional)
1301
Eric Blake99df5282015-10-12 22:22:32 -06001302 def _make_members(self, data, info):
1303 return [self._make_member(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001304 for (key, value) in data.iteritems()]
1305
1306 def _def_struct_type(self, expr, info):
1307 name = expr['struct']
1308 base = expr.get('base')
1309 data = expr['data']
1310 self._def_entity(QAPISchemaObjectType(name, info, base,
Eric Blake99df5282015-10-12 22:22:32 -06001311 self._make_members(data, info),
Markus Armbrusterac882192015-09-16 13:06:05 +02001312 None))
Markus Armbrusterac882192015-09-16 13:06:05 +02001313
1314 def _make_variant(self, case, typ):
1315 return QAPISchemaObjectTypeVariant(case, typ)
1316
Eric Blake99df5282015-10-12 22:22:32 -06001317 def _make_simple_variant(self, case, typ, info):
Markus Armbrusterac882192015-09-16 13:06:05 +02001318 if isinstance(typ, list):
1319 assert len(typ) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001320 typ = self._make_array_type(typ[0], info)
1321 typ = self._make_implicit_object_type(
1322 typ, info, 'wrapper', [self._make_member('data', typ, info)])
Markus Armbrusterac882192015-09-16 13:06:05 +02001323 return QAPISchemaObjectTypeVariant(case, typ)
1324
Markus Armbrusterac882192015-09-16 13:06:05 +02001325 def _def_union_type(self, expr, info):
1326 name = expr['union']
1327 data = expr['data']
1328 base = expr.get('base')
1329 tag_name = expr.get('discriminator')
Eric Blake46292ba2015-10-12 22:22:29 -06001330 tag_member = None
Markus Armbrusterac882192015-09-16 13:06:05 +02001331 if tag_name:
1332 variants = [self._make_variant(key, value)
1333 for (key, value) in data.iteritems()]
Eric Blakeda34a9b2015-11-18 01:52:36 -07001334 members = []
Markus Armbrusterac882192015-09-16 13:06:05 +02001335 else:
Eric Blake99df5282015-10-12 22:22:32 -06001336 variants = [self._make_simple_variant(key, value, info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001337 for (key, value) in data.iteritems()]
Eric Blake9d3f3492015-12-01 22:20:50 -07001338 typ = self._make_implicit_enum_type(name, info,
1339 [v.name for v in variants])
1340 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
Eric Blakeda34a9b2015-11-18 01:52:36 -07001341 members = [tag_member]
Markus Armbrusterac882192015-09-16 13:06:05 +02001342 self._def_entity(
Eric Blakeda34a9b2015-11-18 01:52:36 -07001343 QAPISchemaObjectType(name, info, base, members,
Markus Armbrusterac882192015-09-16 13:06:05 +02001344 QAPISchemaObjectTypeVariants(tag_name,
Eric Blake46292ba2015-10-12 22:22:29 -06001345 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001346 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001347
1348 def _def_alternate_type(self, expr, info):
1349 name = expr['alternate']
1350 data = expr['data']
1351 variants = [self._make_variant(key, value)
1352 for (key, value) in data.iteritems()]
Eric Blake0426d532015-12-01 22:20:48 -07001353 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
Markus Armbrusterac882192015-09-16 13:06:05 +02001354 self._def_entity(
1355 QAPISchemaAlternateType(name, info,
1356 QAPISchemaObjectTypeVariants(None,
Eric Blake46292ba2015-10-12 22:22:29 -06001357 tag_member,
Markus Armbrusterac882192015-09-16 13:06:05 +02001358 variants)))
Markus Armbrusterac882192015-09-16 13:06:05 +02001359
1360 def _def_command(self, expr, info):
1361 name = expr['command']
1362 data = expr.get('data')
1363 rets = expr.get('returns')
1364 gen = expr.get('gen', True)
1365 success_response = expr.get('success-response', True)
1366 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001367 data = self._make_implicit_object_type(
1368 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001369 if isinstance(rets, list):
1370 assert len(rets) == 1
Eric Blake99df5282015-10-12 22:22:32 -06001371 rets = self._make_array_type(rets[0], info)
Markus Armbrusterac882192015-09-16 13:06:05 +02001372 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1373 success_response))
1374
1375 def _def_event(self, expr, info):
1376 name = expr['event']
1377 data = expr.get('data')
1378 if isinstance(data, OrderedDict):
Eric Blake99df5282015-10-12 22:22:32 -06001379 data = self._make_implicit_object_type(
1380 name, info, 'arg', self._make_members(data, info))
Markus Armbrusterac882192015-09-16 13:06:05 +02001381 self._def_entity(QAPISchemaEvent(name, info, data))
1382
1383 def _def_exprs(self):
1384 for expr_elem in self.exprs:
1385 expr = expr_elem['expr']
1386 info = expr_elem['info']
1387 if 'enum' in expr:
1388 self._def_enum_type(expr, info)
1389 elif 'struct' in expr:
1390 self._def_struct_type(expr, info)
1391 elif 'union' in expr:
1392 self._def_union_type(expr, info)
1393 elif 'alternate' in expr:
1394 self._def_alternate_type(expr, info)
1395 elif 'command' in expr:
1396 self._def_command(expr, info)
1397 elif 'event' in expr:
1398 self._def_event(expr, info)
1399 else:
1400 assert False
1401
1402 def check(self):
1403 for ent in self._entity_dict.values():
1404 ent.check(self)
1405
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001406 def visit(self, visitor):
Eric Blake25a0d9c2015-10-12 22:22:21 -06001407 visitor.visit_begin(self)
1408 for (name, entity) in sorted(self._entity_dict.items()):
1409 if visitor.visit_needed(entity):
1410 entity.visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001411 visitor.visit_end()
1412
Markus Armbruster2caba362013-07-27 17:41:56 +02001413
Markus Armbruster00e4b282015-06-10 10:04:36 +02001414#
1415# Code generation helpers
1416#
1417
Michael Roth0f923be2011-07-19 14:50:39 -05001418def camel_case(name):
1419 new_name = ''
1420 first = True
1421 for ch in name:
1422 if ch in ['_', '-']:
1423 first = True
1424 elif first:
1425 new_name += ch.upper()
1426 first = False
1427 else:
1428 new_name += ch.lower()
1429 return new_name
1430
Eric Blake437db252015-09-29 16:21:02 -06001431
Markus Armbruster849bc532015-05-14 06:50:53 -06001432# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1433# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1434# ENUM24_Name -> ENUM24_NAME
1435def camel_to_upper(value):
1436 c_fun_str = c_name(value, False)
1437 if value.isupper():
1438 return c_fun_str
1439
1440 new_name = ''
1441 l = len(c_fun_str)
1442 for i in range(l):
1443 c = c_fun_str[i]
1444 # When c is upper and no "_" appears before, do more checks
1445 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001446 if i < l - 1 and c_fun_str[i + 1].islower():
1447 new_name += '_'
1448 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001449 new_name += '_'
1450 new_name += c
1451 return new_name.lstrip('_').upper()
1452
Eric Blake437db252015-09-29 16:21:02 -06001453
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001454def c_enum_const(type_name, const_name, prefix=None):
1455 if prefix is not None:
1456 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -07001457 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -06001458
Eric Blake18df5152015-05-14 06:50:48 -06001459c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001460
Eric Blake437db252015-09-29 16:21:02 -06001461
Eric Blakec6405b52015-05-14 06:50:55 -06001462# Map @name to a valid C identifier.
1463# If @protect, avoid returning certain ticklish identifiers (like
1464# C keywords) by prepending "q_".
1465#
1466# Used for converting 'name' from a 'name':'type' qapi definition
1467# into a generated struct member, as well as converting type names
1468# into substrings of a generated C function name.
1469# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1470# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001471def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001472 # ANSI X3J11/88-090, 3.1.1
1473 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001474 'default', 'do', 'double', 'else', 'enum', 'extern',
1475 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1476 'return', 'short', 'signed', 'sizeof', 'static',
1477 'struct', 'switch', 'typedef', 'union', 'unsigned',
1478 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001479 # ISO/IEC 9899:1999, 6.4.1
1480 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1481 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001482 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1483 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001484 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1485 # excluding _.*
1486 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001487 # C++ ISO/IEC 14882:2003 2.11
1488 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1489 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1490 'namespace', 'new', 'operator', 'private', 'protected',
1491 'public', 'reinterpret_cast', 'static_cast', 'template',
1492 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1493 'using', 'virtual', 'wchar_t',
1494 # alternative representations
1495 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1496 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001497 # namespace pollution:
Eric Blake86ae1912016-02-02 07:51:41 -07001498 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
Eric Blakec43567c2015-11-18 01:52:52 -07001499 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -06001500 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1501 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001502 return "q_" + name
Eric Blakec43567c2015-11-18 01:52:52 -07001503 return name
Michael Roth0f923be2011-07-19 14:50:39 -05001504
Amos Kong05dfb262014-06-10 19:25:53 +08001505eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001506pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001507
Eric Blake437db252015-09-29 16:21:02 -06001508
Michael Roth0f923be2011-07-19 14:50:39 -05001509def genindent(count):
1510 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001511 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001512 ret += " "
1513 return ret
1514
1515indent_level = 0
1516
Eric Blake437db252015-09-29 16:21:02 -06001517
Michael Roth0f923be2011-07-19 14:50:39 -05001518def push_indent(indent_amount=4):
1519 global indent_level
1520 indent_level += indent_amount
1521
Eric Blake437db252015-09-29 16:21:02 -06001522
Michael Roth0f923be2011-07-19 14:50:39 -05001523def pop_indent(indent_amount=4):
1524 global indent_level
1525 indent_level -= indent_amount
1526
Eric Blake437db252015-09-29 16:21:02 -06001527
Markus Armbruster77e703b2015-06-24 19:27:32 +02001528# Generate @code with @kwds interpolated.
1529# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001530def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001531 raw = code % kwds
1532 if indent_level:
1533 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001534 # re.subn() lacks flags support before Python 2.7, use re.compile()
1535 raw = re.subn(re.compile("^.", re.MULTILINE),
1536 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001537 raw = raw[0]
1538 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001539
Eric Blake437db252015-09-29 16:21:02 -06001540
Michael Roth0f923be2011-07-19 14:50:39 -05001541def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001542 if code[0] == '\n':
1543 code = code[1:]
1544 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001545
Michael Roth0f923be2011-07-19 14:50:39 -05001546
1547def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001548 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001549
Eric Blake437db252015-09-29 16:21:02 -06001550
Michael Rothc0afa9c2013-05-10 17:46:00 -05001551def guardstart(name):
1552 return mcgen('''
1553
1554#ifndef %(name)s
1555#define %(name)s
1556
1557''',
1558 name=guardname(name))
1559
Eric Blake437db252015-09-29 16:21:02 -06001560
Michael Rothc0afa9c2013-05-10 17:46:00 -05001561def guardend(name):
1562 return mcgen('''
1563
1564#endif /* %(name)s */
1565
1566''',
1567 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001568
Eric Blake437db252015-09-29 16:21:02 -06001569
Markus Armbrustere98859a2015-09-16 13:06:16 +02001570def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001571 ret = mcgen('''
1572
Markus Armbrustere98859a2015-09-16 13:06:16 +02001573const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001574''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001575 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001576 for value in values:
1577 index = c_enum_const(name, value, prefix)
1578 ret += mcgen('''
1579 [%(index)s] = "%(value)s",
1580''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001581 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001582
Eric Blake7fb1cf12015-11-18 01:52:57 -07001583 max_index = c_enum_const(name, '_MAX', prefix)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001584 ret += mcgen('''
1585 [%(max_index)s] = NULL,
1586};
1587''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001588 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001589 return ret
1590
Eric Blake437db252015-09-29 16:21:02 -06001591
Markus Armbrustere98859a2015-09-16 13:06:16 +02001592def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001593 # append automatically generated _MAX value
Eric Blake7fb1cf12015-11-18 01:52:57 -07001594 enum_values = values + ['_MAX']
Markus Armbrustere98859a2015-09-16 13:06:16 +02001595
1596 ret = mcgen('''
1597
1598typedef enum %(c_name)s {
1599''',
1600 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001601
1602 i = 0
1603 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001604 ret += mcgen('''
1605 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001606''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001607 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001608 i=i)
1609 i += 1
1610
Markus Armbrustere98859a2015-09-16 13:06:16 +02001611 ret += mcgen('''
1612} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001613''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001614 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001615
Markus Armbrustere98859a2015-09-16 13:06:16 +02001616 ret += mcgen('''
1617
1618extern const char *const %(c_name)s_lookup[];
1619''',
1620 c_name=c_name(name))
1621 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001622
Eric Blake437db252015-09-29 16:21:02 -06001623
Markus Armbruster03b43672015-09-16 13:06:20 +02001624def gen_params(arg_type, extra):
1625 if not arg_type:
1626 return extra
1627 assert not arg_type.variants
1628 ret = ''
1629 sep = ''
1630 for memb in arg_type.members:
1631 ret += sep
1632 sep = ', '
1633 if memb.optional:
1634 ret += 'bool has_%s, ' % c_name(memb.name)
1635 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1636 if extra:
1637 ret += sep + extra
1638 return ret
1639
Eric Blake1f353342015-09-29 16:21:13 -06001640
Eric Blake18bdbc32015-09-29 16:21:15 -06001641def gen_err_check(label='out', skiperr=False):
1642 if skiperr:
Eric Blake1f353342015-09-29 16:21:13 -06001643 return ''
1644 return mcgen('''
Eric Blake18bdbc32015-09-29 16:21:15 -06001645 if (err) {
Eric Blake1f353342015-09-29 16:21:13 -06001646 goto %(label)s;
1647 }
1648''',
Eric Blake18bdbc32015-09-29 16:21:15 -06001649 label=label)
Eric Blake1f353342015-09-29 16:21:13 -06001650
1651
Eric Blakea16e3e52016-01-29 06:48:46 -07001652def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False,
1653 label='out'):
Eric Blake82ca8e42015-09-29 16:21:14 -06001654 ret = ''
Eric Blake18bdbc32015-09-29 16:21:15 -06001655 if skiperr:
Eric Blake82ca8e42015-09-29 16:21:14 -06001656 errparg = 'NULL'
Eric Blake18bdbc32015-09-29 16:21:15 -06001657 else:
1658 errparg = '&err'
Eric Blake82ca8e42015-09-29 16:21:14 -06001659
1660 for memb in members:
1661 if memb.optional:
1662 ret += mcgen('''
Eric Blake51e72bc2016-01-29 06:48:54 -07001663 if (visit_optional(v, "%(name)s", &%(prefix)shas_%(c_name)s)) {
Eric Blake82ca8e42015-09-29 16:21:14 -06001664''',
1665 prefix=prefix, c_name=c_name(memb.name),
Eric Blakee4083112016-01-29 06:48:41 -07001666 name=memb.name)
Eric Blake82ca8e42015-09-29 16:21:14 -06001667 push_indent()
1668
1669 # Ugly: sometimes we need to cast away const
1670 if need_cast and memb.type.name == 'str':
1671 cast = '(char **)'
1672 else:
1673 cast = ''
1674
1675 ret += mcgen('''
Eric Blake51e72bc2016-01-29 06:48:54 -07001676 visit_type_%(c_type)s(v, "%(name)s", %(cast)s&%(prefix)s%(c_name)s, %(errp)s);
Eric Blake82ca8e42015-09-29 16:21:14 -06001677''',
1678 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1679 c_name=c_name(memb.name), name=memb.name,
1680 errp=errparg)
Eric Blakea16e3e52016-01-29 06:48:46 -07001681 ret += gen_err_check(skiperr=skiperr, label=label)
Eric Blake82ca8e42015-09-29 16:21:14 -06001682
1683 if memb.optional:
1684 pop_indent()
1685 ret += mcgen('''
1686 }
1687''')
1688 return ret
1689
1690
Markus Armbruster00e4b282015-06-10 10:04:36 +02001691#
1692# Common command line parsing
1693#
1694
Eric Blake437db252015-09-29 16:21:02 -06001695
1696def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001697
1698 try:
1699 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001700 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001701 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001702 "output-dir="] + extra_long_options)
Markus Armbruster291928a2015-12-18 08:52:41 +01001703 except getopt.GetoptError as err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001704 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001705 sys.exit(1)
1706
1707 output_dir = ""
1708 prefix = ""
1709 do_c = False
1710 do_h = False
1711 extra_opts = []
1712
1713 for oa in opts:
1714 o, a = oa
1715 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001716 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1717 if match.end() != len(a):
1718 print >>sys.stderr, \
1719 "%s: 'funny character '%s' in argument of --prefix" \
1720 % (sys.argv[0], a[match.end()])
1721 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001722 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001723 elif o in ("-o", "--output-dir"):
1724 output_dir = a + "/"
1725 elif o in ("-c", "--source"):
1726 do_c = True
1727 elif o in ("-h", "--header"):
1728 do_h = True
1729 else:
1730 extra_opts.append(oa)
1731
1732 if not do_c and not do_h:
1733 do_c = True
1734 do_h = True
1735
Markus Armbruster16d80f62015-04-02 13:32:16 +02001736 if len(args) != 1:
1737 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001738 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001739 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001740
Markus Armbruster54414042015-06-09 16:22:45 +02001741 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001742
Markus Armbruster00e4b282015-06-10 10:04:36 +02001743#
1744# Generate output files with boilerplate
1745#
1746
Eric Blake437db252015-09-29 16:21:02 -06001747
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001748def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1749 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001750 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001751 c_file = output_dir + prefix + c_file
1752 h_file = output_dir + prefix + h_file
1753
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001754 if output_dir:
1755 try:
1756 os.makedirs(output_dir)
Markus Armbruster291928a2015-12-18 08:52:41 +01001757 except os.error as e:
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001758 if e.errno != errno.EEXIST:
1759 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001760
1761 def maybe_open(really, name, opt):
1762 if really:
1763 return open(name, opt)
1764 else:
1765 import StringIO
1766 return StringIO.StringIO()
1767
1768 fdef = maybe_open(do_c, c_file, 'w')
1769 fdecl = maybe_open(do_h, h_file, 'w')
1770
1771 fdef.write(mcgen('''
1772/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1773%(comment)s
1774''',
Eric Blake437db252015-09-29 16:21:02 -06001775 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001776
1777 fdecl.write(mcgen('''
1778/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1779%(comment)s
1780#ifndef %(guard)s
1781#define %(guard)s
1782
1783''',
Eric Blake437db252015-09-29 16:21:02 -06001784 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001785
1786 return (fdef, fdecl)
1787
Eric Blake437db252015-09-29 16:21:02 -06001788
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001789def close_output(fdef, fdecl):
1790 fdecl.write('''
1791#endif
1792''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001793 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001794 fdef.close()