blob: 4b5d574e0d62bbb4ebdf162bb14532938f12a9eb [file] [log] [blame]
Michael Roth0f923be2011-07-19 14:50:39 -05001#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
Eric Blakefe2a9302015-05-04 09:05:02 -06005# Copyright (c) 2013-2015 Red Hat Inc.
Michael Roth0f923be2011-07-19 14:50:39 -05006#
7# Authors:
8# Anthony Liguori <aliguori@us.ibm.com>
Markus Armbrusterc7a3f252013-07-27 17:41:55 +02009# Markus Armbruster <armbru@redhat.com>
Michael Roth0f923be2011-07-19 14:50:39 -050010#
Markus Armbruster678e48a2014-03-01 08:40:34 +010011# This work is licensed under the terms of the GNU GPL, version 2.
12# See the COPYING file in the top-level directory.
Michael Roth0f923be2011-07-19 14:50:39 -050013
Lluís Vilanovaa719a272014-05-07 20:46:15 +020014import re
Michael Roth0f923be2011-07-19 14:50:39 -050015from ordereddict import OrderedDict
Markus Armbruster12f8e1b2015-04-02 14:46:39 +020016import errno
Markus Armbruster2114f5a2015-04-02 13:12:21 +020017import getopt
Lluís Vilanova33aaad52014-05-02 15:52:35 +020018import os
Markus Armbruster2caba362013-07-27 17:41:56 +020019import sys
Markus Armbruster47299262015-05-14 06:50:47 -060020import string
Michael Roth0f923be2011-07-19 14:50:39 -050021
Eric Blakeb52c4b92015-05-04 09:05:00 -060022builtin_types = {
Kevin Wolf69dd62d2013-07-08 16:14:21 +020023 'str': 'QTYPE_QSTRING',
24 'int': 'QTYPE_QINT',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
27 'int8': 'QTYPE_QINT',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
Eric Blakecb17f792015-05-04 09:05:01 -060035 'size': 'QTYPE_QINT',
Markus Armbruster28770e02015-09-16 13:06:24 +020036 'any': None, # any qtype_code possible, actually
Kevin Wolf69dd62d2013-07-08 16:14:21 +020037}
38
Eric Blake10d4d992015-05-04 09:05:23 -060039# Whitelist of commands allowed to return a non-dictionary
40returns_whitelist = [
41 # From QMP:
42 'human-monitor-command',
Markus Armbruster6eb39372015-09-16 13:06:25 +020043 'qom-get',
Eric Blake10d4d992015-05-04 09:05:23 -060044 'query-migrate-cache-size',
45 'query-tpm-models',
46 'query-tpm-types',
47 'ringbuf-read',
48
49 # From QGA:
50 'guest-file-open',
51 'guest-fsfreeze-freeze',
52 'guest-fsfreeze-freeze-list',
53 'guest-fsfreeze-status',
54 'guest-fsfreeze-thaw',
55 'guest-get-time',
56 'guest-set-vcpus',
57 'guest-sync',
58 'guest-sync-delimited',
59
60 # From qapi-schema-test:
61 'user_def_cmd3',
62]
63
Eric Blake4dc2e692015-05-04 09:05:17 -060064enum_types = []
65struct_types = []
66union_types = []
67events = []
68all_names = {}
69
Markus Armbruster00e4b282015-06-10 10:04:36 +020070#
71# Parsing the schema into expressions
72#
73
Eric Blake437db252015-09-29 16:21:02 -060074
Lluís Vilanovaa719a272014-05-07 20:46:15 +020075def error_path(parent):
76 res = ""
77 while parent:
78 res = ("In file included from %s:%d:\n" % (parent['file'],
79 parent['line'])) + res
80 parent = parent['parent']
81 return res
82
Eric Blake437db252015-09-29 16:21:02 -060083
Markus Armbruster2caba362013-07-27 17:41:56 +020084class QAPISchemaError(Exception):
85 def __init__(self, schema, msg):
Eric Blake59b00542015-09-29 16:21:01 -060086 Exception.__init__(self)
Markus Armbruster54414042015-06-09 16:22:45 +020087 self.fname = schema.fname
Markus Armbruster2caba362013-07-27 17:41:56 +020088 self.msg = msg
Wenchao Xia515b9432014-03-04 18:44:33 -080089 self.col = 1
90 self.line = schema.line
91 for ch in schema.src[schema.line_pos:schema.pos]:
92 if ch == '\t':
Markus Armbruster2caba362013-07-27 17:41:56 +020093 self.col = (self.col + 7) % 8 + 1
94 else:
95 self.col += 1
Markus Armbruster54414042015-06-09 16:22:45 +020096 self.info = schema.incl_info
Markus Armbruster2caba362013-07-27 17:41:56 +020097
98 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +020099 return error_path(self.info) + \
Markus Armbruster54414042015-06-09 16:22:45 +0200100 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
Markus Armbruster2caba362013-07-27 17:41:56 +0200101
Eric Blake437db252015-09-29 16:21:02 -0600102
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800103class QAPIExprError(Exception):
104 def __init__(self, expr_info, msg):
Eric Blake59b00542015-09-29 16:21:01 -0600105 Exception.__init__(self)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200106 self.info = expr_info
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800107 self.msg = msg
108
109 def __str__(self):
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200110 return error_path(self.info['parent']) + \
111 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800112
Eric Blake437db252015-09-29 16:21:02 -0600113
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200114class QAPISchemaParser(object):
Michael Roth0f923be2011-07-19 14:50:39 -0500115
Eric Blake437db252015-09-29 16:21:02 -0600116 def __init__(self, fp, previously_included=[], incl_info=None):
Markus Armbruster54414042015-06-09 16:22:45 +0200117 abs_fname = os.path.abspath(fp.name)
Markus Armbruster8608d252015-06-09 18:32:29 +0200118 fname = fp.name
Markus Armbruster54414042015-06-09 16:22:45 +0200119 self.fname = fname
Markus Armbruster54414042015-06-09 16:22:45 +0200120 previously_included.append(abs_fname)
121 self.incl_info = incl_info
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200122 self.src = fp.read()
123 if self.src == '' or self.src[-1] != '\n':
124 self.src += '\n'
125 self.cursor = 0
Wenchao Xia515b9432014-03-04 18:44:33 -0800126 self.line = 1
127 self.line_pos = 0
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200128 self.exprs = []
129 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500130
Eric Blake437db252015-09-29 16:21:02 -0600131 while self.tok is not None:
Markus Armbruster54414042015-06-09 16:22:45 +0200132 expr_info = {'file': fname, 'line': self.line,
133 'parent': self.incl_info}
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200134 expr = self.get_expr(False)
135 if isinstance(expr, dict) and "include" in expr:
136 if len(expr) != 1:
Eric Blake437db252015-09-29 16:21:02 -0600137 raise QAPIExprError(expr_info,
138 "Invalid 'include' directive")
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200139 include = expr["include"]
140 if not isinstance(include, str):
141 raise QAPIExprError(expr_info,
Eric Blake7408fb62015-09-29 16:21:00 -0600142 "Value of 'include' must be a string")
Markus Armbruster54414042015-06-09 16:22:45 +0200143 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
144 include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200145 # catch inclusion cycle
146 inf = expr_info
147 while inf:
148 if incl_abs_fname == os.path.abspath(inf['file']):
Stefan Hajnoczi7ac9a9d2014-08-27 12:08:51 +0100149 raise QAPIExprError(expr_info, "Inclusion loop for %s"
150 % include)
Markus Armbrustera1366082015-06-09 16:54:09 +0200151 inf = inf['parent']
Benoît Canet24fd8482014-05-16 12:51:56 +0200152 # skip multiple include of the same file
Markus Armbruster54414042015-06-09 16:22:45 +0200153 if incl_abs_fname in previously_included:
Benoît Canet24fd8482014-05-16 12:51:56 +0200154 continue
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200155 try:
Markus Armbruster54414042015-06-09 16:22:45 +0200156 fobj = open(incl_abs_fname, 'r')
Luiz Capitulino34788812014-05-20 13:50:19 -0400157 except IOError, e:
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200158 raise QAPIExprError(expr_info,
159 '%s: %s' % (e.strerror, include))
Markus Armbrustera4bcb202015-09-16 13:06:04 +0200160 exprs_include = QAPISchemaParser(fobj, previously_included,
161 expr_info)
Lluís Vilanovaa719a272014-05-07 20:46:15 +0200162 self.exprs.extend(exprs_include.exprs)
163 else:
164 expr_elem = {'expr': expr,
165 'info': expr_info}
166 self.exprs.append(expr_elem)
Michael Roth0f923be2011-07-19 14:50:39 -0500167
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200168 def accept(self):
169 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200170 self.tok = self.src[self.cursor]
Markus Armbruster2caba362013-07-27 17:41:56 +0200171 self.pos = self.cursor
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200172 self.cursor += 1
173 self.val = None
Michael Roth0f923be2011-07-19 14:50:39 -0500174
Markus Armbrusterf1a145e2013-07-27 17:42:01 +0200175 if self.tok == '#':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200176 self.cursor = self.src.find('\n', self.cursor)
177 elif self.tok in ['{', '}', ':', ',', '[', ']']:
178 return
179 elif self.tok == "'":
180 string = ''
181 esc = False
182 while True:
183 ch = self.src[self.cursor]
184 self.cursor += 1
185 if ch == '\n':
Markus Armbruster2caba362013-07-27 17:41:56 +0200186 raise QAPISchemaError(self,
187 'Missing terminating "\'"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200188 if esc:
Eric Blakea7f59662015-05-04 09:05:36 -0600189 if ch == 'b':
190 string += '\b'
191 elif ch == 'f':
192 string += '\f'
193 elif ch == 'n':
194 string += '\n'
195 elif ch == 'r':
196 string += '\r'
197 elif ch == 't':
198 string += '\t'
199 elif ch == 'u':
200 value = 0
Eric Blake437db252015-09-29 16:21:02 -0600201 for _ in range(0, 4):
Eric Blakea7f59662015-05-04 09:05:36 -0600202 ch = self.src[self.cursor]
203 self.cursor += 1
204 if ch not in "0123456789abcdefABCDEF":
205 raise QAPISchemaError(self,
206 '\\u escape needs 4 '
207 'hex digits')
208 value = (value << 4) + int(ch, 16)
209 # If Python 2 and 3 didn't disagree so much on
210 # how to handle Unicode, then we could allow
211 # Unicode string defaults. But most of QAPI is
212 # ASCII-only, so we aren't losing much for now.
213 if not value or value > 0x7f:
214 raise QAPISchemaError(self,
215 'For now, \\u escape '
216 'only supports non-zero '
217 'values up to \\u007f')
218 string += chr(value)
219 elif ch in "\\/'\"":
220 string += ch
221 else:
222 raise QAPISchemaError(self,
Eric Blake437db252015-09-29 16:21:02 -0600223 "Unknown escape \\%s" % ch)
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200224 esc = False
225 elif ch == "\\":
226 esc = True
227 elif ch == "'":
228 self.val = string
229 return
230 else:
231 string += ch
Markus Armbrustere565d932015-06-10 08:24:58 +0200232 elif self.src.startswith("true", self.pos):
233 self.val = True
234 self.cursor += 3
235 return
236 elif self.src.startswith("false", self.pos):
237 self.val = False
238 self.cursor += 4
239 return
240 elif self.src.startswith("null", self.pos):
241 self.val = None
242 self.cursor += 3
243 return
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200244 elif self.tok == '\n':
245 if self.cursor == len(self.src):
246 self.tok = None
247 return
Wenchao Xia515b9432014-03-04 18:44:33 -0800248 self.line += 1
249 self.line_pos = self.cursor
Markus Armbruster9213aa52013-07-27 17:41:57 +0200250 elif not self.tok.isspace():
251 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
Michael Roth0f923be2011-07-19 14:50:39 -0500252
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200253 def get_members(self):
254 expr = OrderedDict()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200255 if self.tok == '}':
256 self.accept()
257 return expr
258 if self.tok != "'":
259 raise QAPISchemaError(self, 'Expected string or "}"')
260 while True:
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200261 key = self.val
262 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200263 if self.tok != ':':
264 raise QAPISchemaError(self, 'Expected ":"')
265 self.accept()
Wenchao Xia4b359912014-03-04 18:44:32 -0800266 if key in expr:
267 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200268 expr[key] = self.get_expr(True)
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200269 if self.tok == '}':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200270 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200271 return expr
272 if self.tok != ',':
273 raise QAPISchemaError(self, 'Expected "," or "}"')
274 self.accept()
275 if self.tok != "'":
276 raise QAPISchemaError(self, 'Expected string')
Michael Roth0f923be2011-07-19 14:50:39 -0500277
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200278 def get_values(self):
279 expr = []
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200280 if self.tok == ']':
281 self.accept()
282 return expr
Eric Blake437db252015-09-29 16:21:02 -0600283 if self.tok not in "{['tfn":
Fam Zhenge53188a2015-05-04 09:05:18 -0600284 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
285 'boolean or "null"')
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200286 while True:
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200287 expr.append(self.get_expr(True))
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200288 if self.tok == ']':
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200289 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200290 return expr
291 if self.tok != ',':
292 raise QAPISchemaError(self, 'Expected "," or "]"')
293 self.accept()
Michael Roth0f923be2011-07-19 14:50:39 -0500294
Markus Armbruster5f3cd2b2013-07-27 17:41:59 +0200295 def get_expr(self, nested):
296 if self.tok != '{' and not nested:
297 raise QAPISchemaError(self, 'Expected "{"')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200298 if self.tok == '{':
299 self.accept()
300 expr = self.get_members()
301 elif self.tok == '[':
302 self.accept()
303 expr = self.get_values()
Fam Zhenge53188a2015-05-04 09:05:18 -0600304 elif self.tok in "'tfn":
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200305 expr = self.val
306 self.accept()
Markus Armbruster6974ccd2013-07-27 17:41:58 +0200307 else:
308 raise QAPISchemaError(self, 'Expected "{", "[" or string')
Markus Armbrusterc7a3f252013-07-27 17:41:55 +0200309 return expr
Kevin Wolfbd9927f2013-07-01 16:31:50 +0200310
Markus Armbruster00e4b282015-06-10 10:04:36 +0200311#
312# Semantic analysis of schema expressions
Markus Armbrusterac882192015-09-16 13:06:05 +0200313# TODO fold into QAPISchema
314# TODO catching name collisions in generated code would be nice
Markus Armbruster00e4b282015-06-10 10:04:36 +0200315#
316
Eric Blake437db252015-09-29 16:21:02 -0600317
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800318def find_base_fields(base):
319 base_struct_define = find_struct(base)
320 if not base_struct_define:
321 return None
322 return base_struct_define['data']
323
Eric Blake437db252015-09-29 16:21:02 -0600324
Eric Blake811d04f2015-05-04 09:05:10 -0600325# Return the qtype of an alternate branch, or None on error.
326def find_alternate_member_qtype(qapi_type):
Eric Blake437db252015-09-29 16:21:02 -0600327 if qapi_type in builtin_types:
Eric Blake44bd1272015-05-04 09:05:08 -0600328 return builtin_types[qapi_type]
329 elif find_struct(qapi_type):
330 return "QTYPE_QDICT"
331 elif find_enum(qapi_type):
332 return "QTYPE_QSTRING"
Eric Blake811d04f2015-05-04 09:05:10 -0600333 elif find_union(qapi_type):
334 return "QTYPE_QDICT"
Eric Blake44bd1272015-05-04 09:05:08 -0600335 return None
336
Eric Blake437db252015-09-29 16:21:02 -0600337
Wenchao Xiabceae762014-03-06 17:08:56 -0800338# Return the discriminator enum define if discriminator is specified as an
339# enum type, otherwise return None.
340def discriminator_find_enum_define(expr):
341 base = expr.get('base')
342 discriminator = expr.get('discriminator')
343
344 if not (discriminator and base):
345 return None
346
347 base_fields = find_base_fields(base)
348 if not base_fields:
349 return None
350
351 discriminator_type = base_fields.get(discriminator)
352 if not discriminator_type:
353 return None
354
355 return find_enum(discriminator_type)
356
Eric Blake437db252015-09-29 16:21:02 -0600357
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200358# FIXME should enforce "other than downstream extensions [...], all
359# names should begin with a letter".
Eric Blakec9e0a792015-05-04 09:05:22 -0600360valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
Eric Blake437db252015-09-29 16:21:02 -0600361
362
363def check_name(expr_info, source, name, allow_optional=False,
364 enum_member=False):
Eric Blakec9e0a792015-05-04 09:05:22 -0600365 global valid_name
366 membername = name
367
368 if not isinstance(name, str):
369 raise QAPIExprError(expr_info,
370 "%s requires a string name" % source)
371 if name.startswith('*'):
372 membername = name[1:]
373 if not allow_optional:
374 raise QAPIExprError(expr_info,
375 "%s does not allow optional name '%s'"
376 % (source, name))
377 # Enum members can start with a digit, because the generated C
378 # code always prefixes it with the enum name
379 if enum_member:
380 membername = '_' + membername
381 if not valid_name.match(membername):
382 raise QAPIExprError(expr_info,
383 "%s uses invalid name '%s'" % (source, name))
384
Eric Blake437db252015-09-29 16:21:02 -0600385
386def add_name(name, info, meta, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200387 global all_names
388 check_name(info, "'%s'" % meta, name)
Markus Armbrusterd90675f2015-07-31 11:33:52 +0200389 # FIXME should reject names that differ only in '_' vs. '.'
390 # vs. '-', because they're liable to clash in generated C.
Markus Armbruster00e4b282015-06-10 10:04:36 +0200391 if name in all_names:
392 raise QAPIExprError(info,
393 "%s '%s' is already defined"
394 % (all_names[name], name))
395 if not implicit and name[-4:] == 'Kind':
396 raise QAPIExprError(info,
397 "%s '%s' should not end in 'Kind'"
398 % (meta, name))
399 all_names[name] = meta
400
Eric Blake437db252015-09-29 16:21:02 -0600401
Markus Armbruster00e4b282015-06-10 10:04:36 +0200402def add_struct(definition, info):
403 global struct_types
404 name = definition['struct']
405 add_name(name, info, 'struct')
406 struct_types.append(definition)
407
Eric Blake437db252015-09-29 16:21:02 -0600408
Markus Armbruster00e4b282015-06-10 10:04:36 +0200409def find_struct(name):
410 global struct_types
411 for struct in struct_types:
412 if struct['struct'] == name:
413 return struct
414 return None
415
Eric Blake437db252015-09-29 16:21:02 -0600416
Markus Armbruster00e4b282015-06-10 10:04:36 +0200417def add_union(definition, info):
418 global union_types
419 name = definition['union']
420 add_name(name, info, 'union')
421 union_types.append(definition)
422
Eric Blake437db252015-09-29 16:21:02 -0600423
Markus Armbruster00e4b282015-06-10 10:04:36 +0200424def find_union(name):
425 global union_types
426 for union in union_types:
427 if union['union'] == name:
428 return union
429 return None
430
Eric Blake437db252015-09-29 16:21:02 -0600431
432def add_enum(name, info, enum_values=None, implicit=False):
Markus Armbruster00e4b282015-06-10 10:04:36 +0200433 global enum_types
434 add_name(name, info, 'enum', implicit)
435 enum_types.append({"enum_name": name, "enum_values": enum_values})
436
Eric Blake437db252015-09-29 16:21:02 -0600437
Markus Armbruster00e4b282015-06-10 10:04:36 +0200438def find_enum(name):
439 global enum_types
440 for enum in enum_types:
441 if enum['enum_name'] == name:
442 return enum
443 return None
444
Markus Armbruster00e4b282015-06-10 10:04:36 +0200445
Eric Blake437db252015-09-29 16:21:02 -0600446def is_enum(name):
447 return find_enum(name) is not None
448
449
450def check_type(expr_info, source, value, allow_array=False,
451 allow_dict=False, allow_optional=False,
452 allow_metas=[]):
Eric Blakedd883c62015-05-04 09:05:21 -0600453 global all_names
Eric Blakedd883c62015-05-04 09:05:21 -0600454
455 if value is None:
456 return
457
Eric Blakedd883c62015-05-04 09:05:21 -0600458 # Check if array type for value is okay
459 if isinstance(value, list):
460 if not allow_array:
461 raise QAPIExprError(expr_info,
462 "%s cannot be an array" % source)
463 if len(value) != 1 or not isinstance(value[0], str):
464 raise QAPIExprError(expr_info,
465 "%s: array type must contain single type name"
466 % source)
467 value = value[0]
Eric Blakedd883c62015-05-04 09:05:21 -0600468
469 # Check if type name for value is okay
470 if isinstance(value, str):
Eric Blake437db252015-09-29 16:21:02 -0600471 if value not in all_names:
Eric Blakedd883c62015-05-04 09:05:21 -0600472 raise QAPIExprError(expr_info,
473 "%s uses unknown type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200474 % (source, value))
Eric Blakedd883c62015-05-04 09:05:21 -0600475 if not all_names[value] in allow_metas:
476 raise QAPIExprError(expr_info,
477 "%s cannot use %s type '%s'"
Markus Armbrustereddf8172015-08-31 13:54:39 +0200478 % (source, all_names[value], value))
Eric Blakedd883c62015-05-04 09:05:21 -0600479 return
480
Eric Blakedd883c62015-05-04 09:05:21 -0600481 if not allow_dict:
482 raise QAPIExprError(expr_info,
483 "%s should be a type name" % source)
Markus Armbrusterc6b71e52015-08-31 17:28:52 +0200484
485 if not isinstance(value, OrderedDict):
486 raise QAPIExprError(expr_info,
487 "%s should be a dictionary or type name" % source)
488
489 # value is a dictionary, check that each member is okay
Eric Blakedd883c62015-05-04 09:05:21 -0600490 for (key, arg) in value.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600491 check_name(expr_info, "Member of %s" % source, key,
492 allow_optional=allow_optional)
Eric Blake6b5abc72015-05-04 09:05:33 -0600493 # Todo: allow dictionaries to represent default values of
494 # an optional argument.
Eric Blakedd883c62015-05-04 09:05:21 -0600495 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
Markus Armbruster2d212912015-09-16 13:06:27 +0200496 allow_array=True,
Eric Blakedd883c62015-05-04 09:05:21 -0600497 allow_metas=['built-in', 'union', 'alternate', 'struct',
Eric Blake6b5abc72015-05-04 09:05:33 -0600498 'enum'])
Eric Blakedd883c62015-05-04 09:05:21 -0600499
Eric Blake437db252015-09-29 16:21:02 -0600500
501def check_member_clash(expr_info, base_name, data, source=""):
Eric Blakeff55d722015-05-04 09:05:37 -0600502 base = find_struct(base_name)
503 assert base
504 base_members = base['data']
505 for key in data.keys():
506 if key.startswith('*'):
507 key = key[1:]
508 if key in base_members or "*" + key in base_members:
509 raise QAPIExprError(expr_info,
510 "Member name '%s'%s clashes with base '%s'"
511 % (key, source, base_name))
512 if base.get('base'):
513 check_member_clash(expr_info, base['base'], data, source)
514
Eric Blake437db252015-09-29 16:21:02 -0600515
Eric Blakedd883c62015-05-04 09:05:21 -0600516def check_command(expr, expr_info):
517 name = expr['command']
Eric Blake2cbf0992015-05-04 09:05:24 -0600518
Eric Blakedd883c62015-05-04 09:05:21 -0600519 check_type(expr_info, "'data' for command '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600520 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200521 allow_metas=['struct'])
Eric Blake10d4d992015-05-04 09:05:23 -0600522 returns_meta = ['union', 'struct']
523 if name in returns_whitelist:
524 returns_meta += ['built-in', 'alternate', 'enum']
Eric Blakedd883c62015-05-04 09:05:21 -0600525 check_type(expr_info, "'returns' for command '%s'" % name,
Markus Armbruster9b090d42015-07-31 17:59:38 +0200526 expr.get('returns'), allow_array=True,
Markus Armbruster2d212912015-09-16 13:06:27 +0200527 allow_optional=True, allow_metas=returns_meta)
Eric Blakedd883c62015-05-04 09:05:21 -0600528
Eric Blake437db252015-09-29 16:21:02 -0600529
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200530def check_event(expr, expr_info):
Eric Blake4dc2e692015-05-04 09:05:17 -0600531 global events
532 name = expr['event']
Eric Blake4dc2e692015-05-04 09:05:17 -0600533
534 if name.upper() == 'MAX':
535 raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
536 events.append(name)
Eric Blakedd883c62015-05-04 09:05:21 -0600537 check_type(expr_info, "'data' for event '%s'" % name,
Eric Blakec9e0a792015-05-04 09:05:22 -0600538 expr.get('data'), allow_dict=True, allow_optional=True,
Markus Armbruster315932b2015-07-01 10:12:24 +0200539 allow_metas=['struct'])
Wenchao Xia21cd70d2014-06-18 08:43:28 +0200540
Eric Blake437db252015-09-29 16:21:02 -0600541
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800542def check_union(expr, expr_info):
543 name = expr['union']
544 base = expr.get('base')
545 discriminator = expr.get('discriminator')
546 members = expr['data']
Eric Blake437db252015-09-29 16:21:02 -0600547 values = {'MAX': '(automatic)'}
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800548
Eric Blake811d04f2015-05-04 09:05:10 -0600549 # Two types of unions, determined by discriminator.
Eric Blake811d04f2015-05-04 09:05:10 -0600550
551 # With no discriminator it is a simple union.
552 if discriminator is None:
Eric Blake44bd1272015-05-04 09:05:08 -0600553 enum_define = None
Eric Blake437db252015-09-29 16:21:02 -0600554 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
Eric Blake44bd1272015-05-04 09:05:08 -0600555 if base is not None:
556 raise QAPIExprError(expr_info,
Eric Blake811d04f2015-05-04 09:05:10 -0600557 "Simple union '%s' must not have a base"
Eric Blake44bd1272015-05-04 09:05:08 -0600558 % name)
559
560 # Else, it's a flat union.
561 else:
562 # The object must have a string member 'base'.
563 if not isinstance(base, str):
564 raise QAPIExprError(expr_info,
565 "Flat union '%s' must have a string base field"
566 % name)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800567 base_fields = find_base_fields(base)
568 if not base_fields:
569 raise QAPIExprError(expr_info,
Eric Blakefd41dd42015-05-04 09:05:25 -0600570 "Base '%s' is not a valid struct"
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800571 % base)
572
Eric Blakec9e0a792015-05-04 09:05:22 -0600573 # The value of member 'discriminator' must name a non-optional
Eric Blakefd41dd42015-05-04 09:05:25 -0600574 # member of the base struct.
Eric Blakec9e0a792015-05-04 09:05:22 -0600575 check_name(expr_info, "Discriminator of flat union '%s'" % name,
576 discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800577 discriminator_type = base_fields.get(discriminator)
578 if not discriminator_type:
579 raise QAPIExprError(expr_info,
580 "Discriminator '%s' is not a member of base "
Eric Blakefd41dd42015-05-04 09:05:25 -0600581 "struct '%s'"
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800582 % (discriminator, base))
583 enum_define = find_enum(discriminator_type)
Eric Blake437db252015-09-29 16:21:02 -0600584 allow_metas = ['struct']
Wenchao Xia52230702014-03-04 18:44:39 -0800585 # Do not allow string discriminator
586 if not enum_define:
587 raise QAPIExprError(expr_info,
588 "Discriminator '%s' must be of enumeration "
589 "type" % discriminator)
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800590
591 # Check every branch
592 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600593 check_name(expr_info, "Member of union '%s'" % name, key)
594
Eric Blakedd883c62015-05-04 09:05:21 -0600595 # Each value must name a known type; furthermore, in flat unions,
Eric Blakeff55d722015-05-04 09:05:37 -0600596 # branches must be a struct with no overlapping member names
Eric Blakedd883c62015-05-04 09:05:21 -0600597 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
Markus Armbrusterf9a14272015-06-10 13:07:43 +0200598 value, allow_array=not base, allow_metas=allow_metas)
Eric Blakeff55d722015-05-04 09:05:37 -0600599 if base:
600 branch_struct = find_struct(value)
601 assert branch_struct
602 check_member_clash(expr_info, base, branch_struct['data'],
603 " of branch '%s'" % key)
Eric Blakedd883c62015-05-04 09:05:21 -0600604
Eric Blake44bd1272015-05-04 09:05:08 -0600605 # If the discriminator names an enum type, then all members
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800606 # of 'data' must also be members of the enum type.
Eric Blake44bd1272015-05-04 09:05:08 -0600607 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600608 if key not in enum_define['enum_values']:
Eric Blake44bd1272015-05-04 09:05:08 -0600609 raise QAPIExprError(expr_info,
610 "Discriminator value '%s' is not found in "
611 "enum '%s'" %
612 (key, enum_define["enum_name"]))
613
614 # Otherwise, check for conflicts in the generated enum
615 else:
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600616 c_key = camel_to_upper(key)
Eric Blake44bd1272015-05-04 09:05:08 -0600617 if c_key in values:
618 raise QAPIExprError(expr_info,
619 "Union '%s' member '%s' clashes with '%s'"
620 % (name, key, values[c_key]))
621 values[c_key] = key
622
Eric Blake437db252015-09-29 16:21:02 -0600623
Eric Blake811d04f2015-05-04 09:05:10 -0600624def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600625 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600626 members = expr['data']
Eric Blake437db252015-09-29 16:21:02 -0600627 values = {'MAX': '(automatic)'}
Eric Blake811d04f2015-05-04 09:05:10 -0600628 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600629
Eric Blake811d04f2015-05-04 09:05:10 -0600630 # Check every branch
631 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600632 check_name(expr_info, "Member of alternate '%s'" % name, key)
633
Eric Blake811d04f2015-05-04 09:05:10 -0600634 # Check for conflicts in the generated enum
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600635 c_key = camel_to_upper(key)
Eric Blake811d04f2015-05-04 09:05:10 -0600636 if c_key in values:
637 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600638 "Alternate '%s' member '%s' clashes with '%s'"
639 % (name, key, values[c_key]))
Eric Blake811d04f2015-05-04 09:05:10 -0600640 values[c_key] = key
641
642 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600643 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
644 value,
645 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600646 qtype = find_alternate_member_qtype(value)
Eric Blakedd883c62015-05-04 09:05:21 -0600647 assert qtype
Eric Blake811d04f2015-05-04 09:05:10 -0600648 if qtype in types_seen:
649 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600650 "Alternate '%s' member '%s' can't "
Eric Blake811d04f2015-05-04 09:05:10 -0600651 "be distinguished from member '%s'"
652 % (name, key, types_seen[qtype]))
653 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800654
Eric Blake437db252015-09-29 16:21:02 -0600655
Eric Blakecf393592015-05-04 09:05:04 -0600656def check_enum(expr, expr_info):
657 name = expr['enum']
658 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100659 prefix = expr.get('prefix')
Eric Blake437db252015-09-29 16:21:02 -0600660 values = {'MAX': '(automatic)'}
Eric Blakecf393592015-05-04 09:05:04 -0600661
662 if not isinstance(members, list):
663 raise QAPIExprError(expr_info,
664 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100665 if prefix is not None and not isinstance(prefix, str):
666 raise QAPIExprError(expr_info,
667 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600668 for member in members:
Eric Blake437db252015-09-29 16:21:02 -0600669 check_name(expr_info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600670 enum_member=True)
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600671 key = camel_to_upper(member)
Eric Blakecf393592015-05-04 09:05:04 -0600672 if key in values:
673 raise QAPIExprError(expr_info,
674 "Enum '%s' member '%s' clashes with '%s'"
675 % (name, member, values[key]))
676 values[key] = member
677
Eric Blake437db252015-09-29 16:21:02 -0600678
Eric Blakedd883c62015-05-04 09:05:21 -0600679def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600680 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600681 members = expr['data']
682
Eric Blakefd41dd42015-05-04 09:05:25 -0600683 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600684 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600685 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600686 allow_metas=['struct'])
Eric Blakeff55d722015-05-04 09:05:37 -0600687 if expr.get('base'):
688 check_member_clash(expr_info, expr['base'], expr['data'])
Eric Blakedd883c62015-05-04 09:05:21 -0600689
Eric Blake437db252015-09-29 16:21:02 -0600690
Eric Blake0545f6b2015-05-04 09:05:15 -0600691def check_keys(expr_elem, meta, required, optional=[]):
692 expr = expr_elem['expr']
693 info = expr_elem['info']
694 name = expr[meta]
695 if not isinstance(name, str):
696 raise QAPIExprError(info,
697 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600698 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600699 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600700 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600701 raise QAPIExprError(info,
702 "Unknown key '%s' in %s '%s'"
703 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600704 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600705 raise QAPIExprError(info,
706 "'%s' of %s '%s' should only use false value"
707 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600708 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600709 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600710 raise QAPIExprError(info,
711 "Key '%s' is missing from %s '%s'"
712 % (key, meta, name))
713
Eric Blake437db252015-09-29 16:21:02 -0600714
Markus Armbruster4d076d62015-06-10 08:55:21 +0200715def check_exprs(exprs):
716 global all_names
717
718 # Learn the types and check for valid expression keys
719 for builtin in builtin_types.keys():
720 all_names[builtin] = 'built-in'
721 for expr_elem in exprs:
722 expr = expr_elem['expr']
723 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600724 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100725 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200726 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600727 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200728 check_keys(expr_elem, 'union', ['data'],
729 ['base', 'discriminator'])
730 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600731 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200732 check_keys(expr_elem, 'alternate', ['data'])
733 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600734 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200735 check_keys(expr_elem, 'struct', ['data'], ['base'])
736 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600737 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200738 check_keys(expr_elem, 'command', [],
739 ['data', 'returns', 'gen', 'success-response'])
740 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600741 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200742 check_keys(expr_elem, 'event', [], ['data'])
743 add_name(expr['event'], info, 'event')
744 else:
745 raise QAPIExprError(expr_elem['info'],
746 "Expression is missing metatype")
747
748 # Try again for hidden UnionKind enum
749 for expr_elem in exprs:
750 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600751 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200752 if not discriminator_find_enum_define(expr):
753 add_enum('%sKind' % expr['union'], expr_elem['info'],
754 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600755 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200756 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
757 implicit=True)
758
759 # Validate that exprs make sense
760 for expr_elem in exprs:
761 expr = expr_elem['expr']
762 info = expr_elem['info']
763
Eric Blake437db252015-09-29 16:21:02 -0600764 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200765 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600766 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200767 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600768 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200769 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600770 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200771 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600772 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200773 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600774 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200775 check_event(expr, info)
776 else:
777 assert False, 'unexpected meta type'
778
Markus Armbrusterac882192015-09-16 13:06:05 +0200779 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600780
Markus Armbrusterac882192015-09-16 13:06:05 +0200781
782#
783# Schema compiler frontend
784#
785
786class QAPISchemaEntity(object):
787 def __init__(self, name, info):
788 assert isinstance(name, str)
789 self.name = name
790 self.info = info
791
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200792 def c_name(self):
793 return c_name(self.name)
794
Markus Armbrusterac882192015-09-16 13:06:05 +0200795 def check(self, schema):
796 pass
797
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200798 def visit(self, visitor):
799 pass
800
801
802class QAPISchemaVisitor(object):
803 def visit_begin(self, schema):
804 pass
805
806 def visit_end(self):
807 pass
808
809 def visit_builtin_type(self, name, info, json_type):
810 pass
811
812 def visit_enum_type(self, name, info, values, prefix):
813 pass
814
815 def visit_array_type(self, name, info, element_type):
816 pass
817
818 def visit_object_type(self, name, info, base, members, variants):
819 pass
820
Markus Armbruster39a18152015-09-16 13:06:28 +0200821 def visit_object_type_flat(self, name, info, members, variants):
822 pass
823
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200824 def visit_alternate_type(self, name, info, variants):
825 pass
826
827 def visit_command(self, name, info, arg_type, ret_type,
828 gen, success_response):
829 pass
830
831 def visit_event(self, name, info, arg_type):
832 pass
833
Markus Armbrusterac882192015-09-16 13:06:05 +0200834
835class QAPISchemaType(QAPISchemaEntity):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200836 def c_type(self, is_param=False):
837 return c_name(self.name) + pointer_suffix
838
839 def c_null(self):
840 return 'NULL'
841
842 def json_type(self):
843 pass
844
845 def alternate_qtype(self):
846 json2qtype = {
847 'string': 'QTYPE_QSTRING',
848 'number': 'QTYPE_QFLOAT',
849 'int': 'QTYPE_QINT',
850 'boolean': 'QTYPE_QBOOL',
851 'object': 'QTYPE_QDICT'
852 }
853 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200854
855
856class QAPISchemaBuiltinType(QAPISchemaType):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200857 def __init__(self, name, json_type, c_type, c_null):
Markus Armbrusterac882192015-09-16 13:06:05 +0200858 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200859 assert not c_type or isinstance(c_type, str)
860 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
861 'value')
862 self._json_type_name = json_type
863 self._c_type_name = c_type
864 self._c_null_val = c_null
865
866 def c_name(self):
867 return self.name
868
869 def c_type(self, is_param=False):
870 if is_param and self.name == 'str':
871 return 'const ' + self._c_type_name
872 return self._c_type_name
873
874 def c_null(self):
875 return self._c_null_val
876
877 def json_type(self):
878 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200879
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200880 def visit(self, visitor):
881 visitor.visit_builtin_type(self.name, self.info, self.json_type())
882
Markus Armbrusterac882192015-09-16 13:06:05 +0200883
884class QAPISchemaEnumType(QAPISchemaType):
885 def __init__(self, name, info, values, prefix):
886 QAPISchemaType.__init__(self, name, info)
887 for v in values:
888 assert isinstance(v, str)
889 assert prefix is None or isinstance(prefix, str)
890 self.values = values
891 self.prefix = prefix
892
893 def check(self, schema):
894 assert len(set(self.values)) == len(self.values)
895
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200896 def c_type(self, is_param=False):
897 return c_name(self.name)
898
899 def c_null(self):
900 return c_enum_const(self.name, (self.values + ['MAX'])[0],
901 self.prefix)
902
903 def json_type(self):
904 return 'string'
905
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200906 def visit(self, visitor):
907 visitor.visit_enum_type(self.name, self.info,
908 self.values, self.prefix)
909
Markus Armbrusterac882192015-09-16 13:06:05 +0200910
911class QAPISchemaArrayType(QAPISchemaType):
912 def __init__(self, name, info, element_type):
913 QAPISchemaType.__init__(self, name, info)
914 assert isinstance(element_type, str)
915 self._element_type_name = element_type
916 self.element_type = None
917
918 def check(self, schema):
919 self.element_type = schema.lookup_type(self._element_type_name)
920 assert self.element_type
921
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200922 def json_type(self):
923 return 'array'
924
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200925 def visit(self, visitor):
926 visitor.visit_array_type(self.name, self.info, self.element_type)
927
Markus Armbrusterac882192015-09-16 13:06:05 +0200928
929class QAPISchemaObjectType(QAPISchemaType):
930 def __init__(self, name, info, base, local_members, variants):
931 QAPISchemaType.__init__(self, name, info)
932 assert base is None or isinstance(base, str)
933 for m in local_members:
934 assert isinstance(m, QAPISchemaObjectTypeMember)
935 assert (variants is None or
936 isinstance(variants, QAPISchemaObjectTypeVariants))
937 self._base_name = base
938 self.base = None
939 self.local_members = local_members
940 self.variants = variants
941 self.members = None
942
943 def check(self, schema):
944 assert self.members is not False # not running in cycles
945 if self.members:
946 return
947 self.members = False # mark as being checked
948 if self._base_name:
949 self.base = schema.lookup_type(self._base_name)
950 assert isinstance(self.base, QAPISchemaObjectType)
951 assert not self.base.variants # not implemented
952 self.base.check(schema)
953 members = list(self.base.members)
954 else:
955 members = []
956 seen = {}
957 for m in members:
958 seen[m.name] = m
959 for m in self.local_members:
960 m.check(schema, members, seen)
961 if self.variants:
962 self.variants.check(schema, members, seen)
963 self.members = members
964
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200965 def c_name(self):
966 assert self.info
967 return QAPISchemaType.c_name(self)
968
969 def c_type(self, is_param=False):
970 assert self.info
971 return QAPISchemaType.c_type(self)
972
973 def json_type(self):
974 return 'object'
975
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200976 def visit(self, visitor):
977 visitor.visit_object_type(self.name, self.info,
978 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +0200979 visitor.visit_object_type_flat(self.name, self.info,
980 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200981
Markus Armbrusterac882192015-09-16 13:06:05 +0200982
983class QAPISchemaObjectTypeMember(object):
984 def __init__(self, name, typ, optional):
985 assert isinstance(name, str)
986 assert isinstance(typ, str)
987 assert isinstance(optional, bool)
988 self.name = name
989 self._type_name = typ
990 self.type = None
991 self.optional = optional
992
993 def check(self, schema, all_members, seen):
994 assert self.name not in seen
995 self.type = schema.lookup_type(self._type_name)
996 assert self.type
997 all_members.append(self)
998 seen[self.name] = self
999
1000
1001class QAPISchemaObjectTypeVariants(object):
1002 def __init__(self, tag_name, tag_enum, variants):
1003 assert tag_name is None or isinstance(tag_name, str)
1004 assert tag_enum is None or isinstance(tag_enum, str)
1005 for v in variants:
1006 assert isinstance(v, QAPISchemaObjectTypeVariant)
1007 self.tag_name = tag_name
1008 if tag_name:
1009 assert not tag_enum
1010 self.tag_member = None
1011 else:
1012 self.tag_member = QAPISchemaObjectTypeMember('type', tag_enum,
1013 False)
1014 self.variants = variants
1015
1016 def check(self, schema, members, seen):
1017 if self.tag_name:
1018 self.tag_member = seen[self.tag_name]
1019 else:
1020 self.tag_member.check(schema, members, seen)
1021 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1022 for v in self.variants:
1023 vseen = dict(seen)
1024 v.check(schema, self.tag_member.type, vseen)
1025
Eric Blake437db252015-09-29 16:21:02 -06001026
Markus Armbrusterac882192015-09-16 13:06:05 +02001027class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1028 def __init__(self, name, typ):
1029 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1030
1031 def check(self, schema, tag_type, seen):
1032 QAPISchemaObjectTypeMember.check(self, schema, [], seen)
1033 assert self.name in tag_type.values
1034
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001035 # This function exists to support ugly simple union special cases
1036 # TODO get rid of them, and drop the function
1037 def simple_union_type(self):
1038 if isinstance(self.type, QAPISchemaObjectType) and not self.type.info:
1039 assert len(self.type.members) == 1
1040 assert not self.type.variants
1041 return self.type.members[0].type
1042 return None
1043
Markus Armbrusterac882192015-09-16 13:06:05 +02001044
1045class QAPISchemaAlternateType(QAPISchemaType):
1046 def __init__(self, name, info, variants):
1047 QAPISchemaType.__init__(self, name, info)
1048 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1049 assert not variants.tag_name
1050 self.variants = variants
1051
1052 def check(self, schema):
1053 self.variants.check(schema, [], {})
1054
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001055 def json_type(self):
1056 return 'value'
1057
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001058 def visit(self, visitor):
1059 visitor.visit_alternate_type(self.name, self.info, self.variants)
1060
Markus Armbrusterac882192015-09-16 13:06:05 +02001061
1062class QAPISchemaCommand(QAPISchemaEntity):
1063 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1064 QAPISchemaEntity.__init__(self, name, info)
1065 assert not arg_type or isinstance(arg_type, str)
1066 assert not ret_type or isinstance(ret_type, str)
1067 self._arg_type_name = arg_type
1068 self.arg_type = None
1069 self._ret_type_name = ret_type
1070 self.ret_type = None
1071 self.gen = gen
1072 self.success_response = success_response
1073
1074 def check(self, schema):
1075 if self._arg_type_name:
1076 self.arg_type = schema.lookup_type(self._arg_type_name)
1077 assert isinstance(self.arg_type, QAPISchemaObjectType)
1078 assert not self.arg_type.variants # not implemented
1079 if self._ret_type_name:
1080 self.ret_type = schema.lookup_type(self._ret_type_name)
1081 assert isinstance(self.ret_type, QAPISchemaType)
1082
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001083 def visit(self, visitor):
1084 visitor.visit_command(self.name, self.info,
1085 self.arg_type, self.ret_type,
1086 self.gen, self.success_response)
1087
Markus Armbrusterac882192015-09-16 13:06:05 +02001088
1089class QAPISchemaEvent(QAPISchemaEntity):
1090 def __init__(self, name, info, arg_type):
1091 QAPISchemaEntity.__init__(self, name, info)
1092 assert not arg_type or isinstance(arg_type, str)
1093 self._arg_type_name = arg_type
1094 self.arg_type = None
1095
1096 def check(self, schema):
1097 if self._arg_type_name:
1098 self.arg_type = schema.lookup_type(self._arg_type_name)
1099 assert isinstance(self.arg_type, QAPISchemaObjectType)
1100 assert not self.arg_type.variants # not implemented
1101
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001102 def visit(self, visitor):
1103 visitor.visit_event(self.name, self.info, self.arg_type)
1104
Markus Armbrusterac882192015-09-16 13:06:05 +02001105
1106class QAPISchema(object):
1107 def __init__(self, fname):
1108 try:
1109 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1110 except (QAPISchemaError, QAPIExprError), err:
1111 print >>sys.stderr, err
1112 exit(1)
1113 self._entity_dict = {}
1114 self._def_predefineds()
1115 self._def_exprs()
1116 self.check()
1117
Markus Armbrusterac882192015-09-16 13:06:05 +02001118 def _def_entity(self, ent):
1119 assert ent.name not in self._entity_dict
1120 self._entity_dict[ent.name] = ent
1121
1122 def lookup_entity(self, name, typ=None):
1123 ent = self._entity_dict.get(name)
1124 if typ and not isinstance(ent, typ):
1125 return None
1126 return ent
1127
1128 def lookup_type(self, name):
1129 return self.lookup_entity(name, QAPISchemaType)
1130
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001131 def _def_builtin_type(self, name, json_type, c_type, c_null):
1132 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1133 c_type, c_null))
Markus Armbruster28770e02015-09-16 13:06:24 +02001134 self._make_array_type(name) # TODO really needed?
Markus Armbrusterac882192015-09-16 13:06:05 +02001135
1136 def _def_predefineds(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001137 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1138 ('number', 'number', 'double', '0'),
1139 ('int', 'int', 'int64_t', '0'),
1140 ('int8', 'int', 'int8_t', '0'),
1141 ('int16', 'int', 'int16_t', '0'),
1142 ('int32', 'int', 'int32_t', '0'),
1143 ('int64', 'int', 'int64_t', '0'),
1144 ('uint8', 'int', 'uint8_t', '0'),
1145 ('uint16', 'int', 'uint16_t', '0'),
1146 ('uint32', 'int', 'uint32_t', '0'),
1147 ('uint64', 'int', 'uint64_t', '0'),
1148 ('size', 'int', 'uint64_t', '0'),
1149 ('bool', 'boolean', 'bool', 'false'),
Markus Armbruster28770e02015-09-16 13:06:24 +02001150 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001151 self._def_builtin_type(*t)
Markus Armbruster39a18152015-09-16 13:06:28 +02001152 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1153 [], None)
1154 self._def_entity(self.the_empty_object_type)
Markus Armbrusterac882192015-09-16 13:06:05 +02001155
1156 def _make_implicit_enum_type(self, name, values):
1157 name = name + 'Kind'
1158 self._def_entity(QAPISchemaEnumType(name, None, values, None))
1159 return name
1160
1161 def _make_array_type(self, element_type):
1162 name = element_type + 'List'
1163 if not self.lookup_type(name):
1164 self._def_entity(QAPISchemaArrayType(name, None, element_type))
1165 return name
1166
1167 def _make_implicit_object_type(self, name, role, members):
1168 if not members:
1169 return None
1170 name = ':obj-%s-%s' % (name, role)
1171 if not self.lookup_entity(name, QAPISchemaObjectType):
1172 self._def_entity(QAPISchemaObjectType(name, None, None,
1173 members, None))
1174 return name
1175
1176 def _def_enum_type(self, expr, info):
1177 name = expr['enum']
1178 data = expr['data']
1179 prefix = expr.get('prefix')
1180 self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
1181 self._make_array_type(name) # TODO really needed?
1182
1183 def _make_member(self, name, typ):
1184 optional = False
1185 if name.startswith('*'):
1186 name = name[1:]
1187 optional = True
1188 if isinstance(typ, list):
1189 assert len(typ) == 1
1190 typ = self._make_array_type(typ[0])
1191 return QAPISchemaObjectTypeMember(name, typ, optional)
1192
1193 def _make_members(self, data):
1194 return [self._make_member(key, value)
1195 for (key, value) in data.iteritems()]
1196
1197 def _def_struct_type(self, expr, info):
1198 name = expr['struct']
1199 base = expr.get('base')
1200 data = expr['data']
1201 self._def_entity(QAPISchemaObjectType(name, info, base,
1202 self._make_members(data),
1203 None))
1204 self._make_array_type(name) # TODO really needed?
1205
1206 def _make_variant(self, case, typ):
1207 return QAPISchemaObjectTypeVariant(case, typ)
1208
1209 def _make_simple_variant(self, case, typ):
1210 if isinstance(typ, list):
1211 assert len(typ) == 1
1212 typ = self._make_array_type(typ[0])
1213 typ = self._make_implicit_object_type(typ, 'wrapper',
1214 [self._make_member('data', typ)])
1215 return QAPISchemaObjectTypeVariant(case, typ)
1216
1217 def _make_tag_enum(self, type_name, variants):
1218 return self._make_implicit_enum_type(type_name,
1219 [v.name for v in variants])
1220
1221 def _def_union_type(self, expr, info):
1222 name = expr['union']
1223 data = expr['data']
1224 base = expr.get('base')
1225 tag_name = expr.get('discriminator')
1226 tag_enum = None
1227 if tag_name:
1228 variants = [self._make_variant(key, value)
1229 for (key, value) in data.iteritems()]
1230 else:
1231 variants = [self._make_simple_variant(key, value)
1232 for (key, value) in data.iteritems()]
1233 tag_enum = self._make_tag_enum(name, variants)
1234 self._def_entity(
1235 QAPISchemaObjectType(name, info, base,
1236 self._make_members(OrderedDict()),
1237 QAPISchemaObjectTypeVariants(tag_name,
1238 tag_enum,
1239 variants)))
1240 self._make_array_type(name) # TODO really needed?
1241
1242 def _def_alternate_type(self, expr, info):
1243 name = expr['alternate']
1244 data = expr['data']
1245 variants = [self._make_variant(key, value)
1246 for (key, value) in data.iteritems()]
1247 tag_enum = self._make_tag_enum(name, variants)
1248 self._def_entity(
1249 QAPISchemaAlternateType(name, info,
1250 QAPISchemaObjectTypeVariants(None,
1251 tag_enum,
1252 variants)))
1253 self._make_array_type(name) # TODO really needed?
1254
1255 def _def_command(self, expr, info):
1256 name = expr['command']
1257 data = expr.get('data')
1258 rets = expr.get('returns')
1259 gen = expr.get('gen', True)
1260 success_response = expr.get('success-response', True)
1261 if isinstance(data, OrderedDict):
1262 data = self._make_implicit_object_type(name, 'arg',
1263 self._make_members(data))
1264 if isinstance(rets, list):
1265 assert len(rets) == 1
1266 rets = self._make_array_type(rets[0])
1267 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1268 success_response))
1269
1270 def _def_event(self, expr, info):
1271 name = expr['event']
1272 data = expr.get('data')
1273 if isinstance(data, OrderedDict):
1274 data = self._make_implicit_object_type(name, 'arg',
1275 self._make_members(data))
1276 self._def_entity(QAPISchemaEvent(name, info, data))
1277
1278 def _def_exprs(self):
1279 for expr_elem in self.exprs:
1280 expr = expr_elem['expr']
1281 info = expr_elem['info']
1282 if 'enum' in expr:
1283 self._def_enum_type(expr, info)
1284 elif 'struct' in expr:
1285 self._def_struct_type(expr, info)
1286 elif 'union' in expr:
1287 self._def_union_type(expr, info)
1288 elif 'alternate' in expr:
1289 self._def_alternate_type(expr, info)
1290 elif 'command' in expr:
1291 self._def_command(expr, info)
1292 elif 'event' in expr:
1293 self._def_event(expr, info)
1294 else:
1295 assert False
1296
1297 def check(self):
1298 for ent in self._entity_dict.values():
1299 ent.check(self)
1300
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001301 def visit(self, visitor):
Markus Armbruster39a18152015-09-16 13:06:28 +02001302 ignore = visitor.visit_begin(self)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001303 for name in sorted(self._entity_dict.keys()):
Markus Armbruster39a18152015-09-16 13:06:28 +02001304 if not ignore or not isinstance(self._entity_dict[name], ignore):
1305 self._entity_dict[name].visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001306 visitor.visit_end()
1307
Markus Armbruster2caba362013-07-27 17:41:56 +02001308
Markus Armbruster00e4b282015-06-10 10:04:36 +02001309#
1310# Code generation helpers
1311#
1312
Michael Roth0f923be2011-07-19 14:50:39 -05001313def camel_case(name):
1314 new_name = ''
1315 first = True
1316 for ch in name:
1317 if ch in ['_', '-']:
1318 first = True
1319 elif first:
1320 new_name += ch.upper()
1321 first = False
1322 else:
1323 new_name += ch.lower()
1324 return new_name
1325
Eric Blake437db252015-09-29 16:21:02 -06001326
Markus Armbruster849bc532015-05-14 06:50:53 -06001327# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1328# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1329# ENUM24_Name -> ENUM24_NAME
1330def camel_to_upper(value):
1331 c_fun_str = c_name(value, False)
1332 if value.isupper():
1333 return c_fun_str
1334
1335 new_name = ''
1336 l = len(c_fun_str)
1337 for i in range(l):
1338 c = c_fun_str[i]
1339 # When c is upper and no "_" appears before, do more checks
1340 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001341 if i < l - 1 and c_fun_str[i + 1].islower():
1342 new_name += '_'
1343 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001344 new_name += '_'
1345 new_name += c
1346 return new_name.lstrip('_').upper()
1347
Eric Blake437db252015-09-29 16:21:02 -06001348
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001349def c_enum_const(type_name, const_name, prefix=None):
1350 if prefix is not None:
1351 type_name = prefix
Markus Armbruster849bc532015-05-14 06:50:53 -06001352 return camel_to_upper(type_name + '_' + const_name)
1353
Eric Blake18df5152015-05-14 06:50:48 -06001354c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001355
Eric Blake437db252015-09-29 16:21:02 -06001356
Eric Blakec6405b52015-05-14 06:50:55 -06001357# Map @name to a valid C identifier.
1358# If @protect, avoid returning certain ticklish identifiers (like
1359# C keywords) by prepending "q_".
1360#
1361# Used for converting 'name' from a 'name':'type' qapi definition
1362# into a generated struct member, as well as converting type names
1363# into substrings of a generated C function name.
1364# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1365# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001366def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001367 # ANSI X3J11/88-090, 3.1.1
1368 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001369 'default', 'do', 'double', 'else', 'enum', 'extern',
1370 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1371 'return', 'short', 'signed', 'sizeof', 'static',
1372 'struct', 'switch', 'typedef', 'union', 'unsigned',
1373 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001374 # ISO/IEC 9899:1999, 6.4.1
1375 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1376 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001377 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1378 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001379 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1380 # excluding _.*
1381 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001382 # C++ ISO/IEC 14882:2003 2.11
1383 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1384 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1385 'namespace', 'new', 'operator', 'private', 'protected',
1386 'public', 'reinterpret_cast', 'static_cast', 'template',
1387 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1388 'using', 'virtual', 'wchar_t',
1389 # alternative representations
1390 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1391 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001392 # namespace pollution:
Max Reitz8592a542013-12-20 19:28:18 +01001393 polluted_words = set(['unix', 'errno'])
Eric Blake437db252015-09-29 16:21:02 -06001394 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1395 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001396 return "q_" + name
Eric Blake18df5152015-05-14 06:50:48 -06001397 return name.translate(c_name_trans)
Michael Roth0f923be2011-07-19 14:50:39 -05001398
Amos Kong05dfb262014-06-10 19:25:53 +08001399eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001400pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001401
Eric Blake437db252015-09-29 16:21:02 -06001402
Michael Roth0f923be2011-07-19 14:50:39 -05001403def genindent(count):
1404 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001405 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001406 ret += " "
1407 return ret
1408
1409indent_level = 0
1410
Eric Blake437db252015-09-29 16:21:02 -06001411
Michael Roth0f923be2011-07-19 14:50:39 -05001412def push_indent(indent_amount=4):
1413 global indent_level
1414 indent_level += indent_amount
1415
Eric Blake437db252015-09-29 16:21:02 -06001416
Michael Roth0f923be2011-07-19 14:50:39 -05001417def pop_indent(indent_amount=4):
1418 global indent_level
1419 indent_level -= indent_amount
1420
Eric Blake437db252015-09-29 16:21:02 -06001421
Markus Armbruster77e703b2015-06-24 19:27:32 +02001422# Generate @code with @kwds interpolated.
1423# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001424def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001425 raw = code % kwds
1426 if indent_level:
1427 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001428 # re.subn() lacks flags support before Python 2.7, use re.compile()
1429 raw = re.subn(re.compile("^.", re.MULTILINE),
1430 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001431 raw = raw[0]
1432 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001433
Eric Blake437db252015-09-29 16:21:02 -06001434
Michael Roth0f923be2011-07-19 14:50:39 -05001435def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001436 if code[0] == '\n':
1437 code = code[1:]
1438 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001439
Michael Roth0f923be2011-07-19 14:50:39 -05001440
1441def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001442 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001443
Eric Blake437db252015-09-29 16:21:02 -06001444
Michael Rothc0afa9c2013-05-10 17:46:00 -05001445def guardstart(name):
1446 return mcgen('''
1447
1448#ifndef %(name)s
1449#define %(name)s
1450
1451''',
1452 name=guardname(name))
1453
Eric Blake437db252015-09-29 16:21:02 -06001454
Michael Rothc0afa9c2013-05-10 17:46:00 -05001455def guardend(name):
1456 return mcgen('''
1457
1458#endif /* %(name)s */
1459
1460''',
1461 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001462
Eric Blake437db252015-09-29 16:21:02 -06001463
Markus Armbrustere98859a2015-09-16 13:06:16 +02001464def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001465 ret = mcgen('''
1466
Markus Armbrustere98859a2015-09-16 13:06:16 +02001467const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001468''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001469 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001470 for value in values:
1471 index = c_enum_const(name, value, prefix)
1472 ret += mcgen('''
1473 [%(index)s] = "%(value)s",
1474''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001475 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001476
1477 max_index = c_enum_const(name, 'MAX', prefix)
1478 ret += mcgen('''
1479 [%(max_index)s] = NULL,
1480};
1481''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001482 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001483 return ret
1484
Eric Blake437db252015-09-29 16:21:02 -06001485
Markus Armbrustere98859a2015-09-16 13:06:16 +02001486def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001487 # append automatically generated _MAX value
Markus Armbrustere98859a2015-09-16 13:06:16 +02001488 enum_values = values + ['MAX']
1489
1490 ret = mcgen('''
1491
1492typedef enum %(c_name)s {
1493''',
1494 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001495
1496 i = 0
1497 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001498 ret += mcgen('''
1499 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001500''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001501 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001502 i=i)
1503 i += 1
1504
Markus Armbrustere98859a2015-09-16 13:06:16 +02001505 ret += mcgen('''
1506} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001507''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001508 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001509
Markus Armbrustere98859a2015-09-16 13:06:16 +02001510 ret += mcgen('''
1511
1512extern const char *const %(c_name)s_lookup[];
1513''',
1514 c_name=c_name(name))
1515 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001516
Eric Blake437db252015-09-29 16:21:02 -06001517
Markus Armbruster03b43672015-09-16 13:06:20 +02001518def gen_params(arg_type, extra):
1519 if not arg_type:
1520 return extra
1521 assert not arg_type.variants
1522 ret = ''
1523 sep = ''
1524 for memb in arg_type.members:
1525 ret += sep
1526 sep = ', '
1527 if memb.optional:
1528 ret += 'bool has_%s, ' % c_name(memb.name)
1529 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1530 if extra:
1531 ret += sep + extra
1532 return ret
1533
Markus Armbruster00e4b282015-06-10 10:04:36 +02001534#
1535# Common command line parsing
1536#
1537
Eric Blake437db252015-09-29 16:21:02 -06001538
1539def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001540
1541 try:
1542 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001543 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001544 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001545 "output-dir="] + extra_long_options)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001546 except getopt.GetoptError, err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001547 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001548 sys.exit(1)
1549
1550 output_dir = ""
1551 prefix = ""
1552 do_c = False
1553 do_h = False
1554 extra_opts = []
1555
1556 for oa in opts:
1557 o, a = oa
1558 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001559 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1560 if match.end() != len(a):
1561 print >>sys.stderr, \
1562 "%s: 'funny character '%s' in argument of --prefix" \
1563 % (sys.argv[0], a[match.end()])
1564 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001565 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001566 elif o in ("-o", "--output-dir"):
1567 output_dir = a + "/"
1568 elif o in ("-c", "--source"):
1569 do_c = True
1570 elif o in ("-h", "--header"):
1571 do_h = True
1572 else:
1573 extra_opts.append(oa)
1574
1575 if not do_c and not do_h:
1576 do_c = True
1577 do_h = True
1578
Markus Armbruster16d80f62015-04-02 13:32:16 +02001579 if len(args) != 1:
1580 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001581 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001582 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001583
Markus Armbruster54414042015-06-09 16:22:45 +02001584 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001585
Markus Armbruster00e4b282015-06-10 10:04:36 +02001586#
1587# Generate output files with boilerplate
1588#
1589
Eric Blake437db252015-09-29 16:21:02 -06001590
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001591def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1592 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001593 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001594 c_file = output_dir + prefix + c_file
1595 h_file = output_dir + prefix + h_file
1596
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001597 if output_dir:
1598 try:
1599 os.makedirs(output_dir)
1600 except os.error, e:
1601 if e.errno != errno.EEXIST:
1602 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001603
1604 def maybe_open(really, name, opt):
1605 if really:
1606 return open(name, opt)
1607 else:
1608 import StringIO
1609 return StringIO.StringIO()
1610
1611 fdef = maybe_open(do_c, c_file, 'w')
1612 fdecl = maybe_open(do_h, h_file, 'w')
1613
1614 fdef.write(mcgen('''
1615/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1616%(comment)s
1617''',
Eric Blake437db252015-09-29 16:21:02 -06001618 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001619
1620 fdecl.write(mcgen('''
1621/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1622%(comment)s
1623#ifndef %(guard)s
1624#define %(guard)s
1625
1626''',
Eric Blake437db252015-09-29 16:21:02 -06001627 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001628
1629 return (fdef, fdecl)
1630
Eric Blake437db252015-09-29 16:21:02 -06001631
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001632def close_output(fdef, fdecl):
1633 fdecl.write('''
1634#endif
1635''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001636 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001637 fdef.close()