blob: 8d2681b24bb79432da9337de20465fb4468a21b2 [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 Blake7b2a5c22015-09-29 16:21:04 -0600547 values = {'MAX': '(automatic)', 'KIND': '(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
Eric Blake7b2a5c22015-09-29 16:21:04 -0600606 # of 'data' must also be members of the enum type, which in turn
607 # must not collide with the discriminator name.
Eric Blake44bd1272015-05-04 09:05:08 -0600608 if enum_define:
Eric Blake437db252015-09-29 16:21:02 -0600609 if key not in enum_define['enum_values']:
Eric Blake44bd1272015-05-04 09:05:08 -0600610 raise QAPIExprError(expr_info,
611 "Discriminator value '%s' is not found in "
612 "enum '%s'" %
613 (key, enum_define["enum_name"]))
Eric Blake7b2a5c22015-09-29 16:21:04 -0600614 if discriminator in enum_define['enum_values']:
615 raise QAPIExprError(expr_info,
616 "Discriminator name '%s' collides with "
617 "enum value in '%s'" %
618 (discriminator, enum_define["enum_name"]))
Eric Blake44bd1272015-05-04 09:05:08 -0600619
620 # Otherwise, check for conflicts in the generated enum
621 else:
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600622 c_key = camel_to_upper(key)
Eric Blake44bd1272015-05-04 09:05:08 -0600623 if c_key in values:
624 raise QAPIExprError(expr_info,
625 "Union '%s' member '%s' clashes with '%s'"
626 % (name, key, values[c_key]))
627 values[c_key] = key
628
Eric Blake437db252015-09-29 16:21:02 -0600629
Eric Blake811d04f2015-05-04 09:05:10 -0600630def check_alternate(expr, expr_info):
Eric Blakeab916fa2015-05-04 09:05:13 -0600631 name = expr['alternate']
Eric Blake811d04f2015-05-04 09:05:10 -0600632 members = expr['data']
Eric Blake437db252015-09-29 16:21:02 -0600633 values = {'MAX': '(automatic)'}
Eric Blake811d04f2015-05-04 09:05:10 -0600634 types_seen = {}
Eric Blake44bd1272015-05-04 09:05:08 -0600635
Eric Blake811d04f2015-05-04 09:05:10 -0600636 # Check every branch
637 for (key, value) in members.items():
Eric Blakec9e0a792015-05-04 09:05:22 -0600638 check_name(expr_info, "Member of alternate '%s'" % name, key)
639
Eric Blake811d04f2015-05-04 09:05:10 -0600640 # Check for conflicts in the generated enum
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600641 c_key = camel_to_upper(key)
Eric Blake811d04f2015-05-04 09:05:10 -0600642 if c_key in values:
643 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600644 "Alternate '%s' member '%s' clashes with '%s'"
645 % (name, key, values[c_key]))
Eric Blake811d04f2015-05-04 09:05:10 -0600646 values[c_key] = key
647
648 # Ensure alternates have no type conflicts.
Eric Blakedd883c62015-05-04 09:05:21 -0600649 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
650 value,
651 allow_metas=['built-in', 'union', 'struct', 'enum'])
Eric Blake811d04f2015-05-04 09:05:10 -0600652 qtype = find_alternate_member_qtype(value)
Eric Blakedd883c62015-05-04 09:05:21 -0600653 assert qtype
Eric Blake811d04f2015-05-04 09:05:10 -0600654 if qtype in types_seen:
655 raise QAPIExprError(expr_info,
Eric Blakeab916fa2015-05-04 09:05:13 -0600656 "Alternate '%s' member '%s' can't "
Eric Blake811d04f2015-05-04 09:05:10 -0600657 "be distinguished from member '%s'"
658 % (name, key, types_seen[qtype]))
659 types_seen[qtype] = key
Wenchao Xiab86b05e2014-03-04 18:44:34 -0800660
Eric Blake437db252015-09-29 16:21:02 -0600661
Eric Blakecf393592015-05-04 09:05:04 -0600662def check_enum(expr, expr_info):
663 name = expr['enum']
664 members = expr.get('data')
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100665 prefix = expr.get('prefix')
Eric Blake437db252015-09-29 16:21:02 -0600666 values = {'MAX': '(automatic)'}
Eric Blakecf393592015-05-04 09:05:04 -0600667
668 if not isinstance(members, list):
669 raise QAPIExprError(expr_info,
670 "Enum '%s' requires an array for 'data'" % name)
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100671 if prefix is not None and not isinstance(prefix, str):
672 raise QAPIExprError(expr_info,
673 "Enum '%s' requires a string for 'prefix'" % name)
Eric Blakecf393592015-05-04 09:05:04 -0600674 for member in members:
Eric Blake437db252015-09-29 16:21:02 -0600675 check_name(expr_info, "Member of enum '%s'" % name, member,
Eric Blakec9e0a792015-05-04 09:05:22 -0600676 enum_member=True)
Markus Armbrusterfa6068a2015-05-14 06:50:49 -0600677 key = camel_to_upper(member)
Eric Blakecf393592015-05-04 09:05:04 -0600678 if key in values:
679 raise QAPIExprError(expr_info,
680 "Enum '%s' member '%s' clashes with '%s'"
681 % (name, member, values[key]))
682 values[key] = member
683
Eric Blake437db252015-09-29 16:21:02 -0600684
Eric Blakedd883c62015-05-04 09:05:21 -0600685def check_struct(expr, expr_info):
Eric Blakefd41dd42015-05-04 09:05:25 -0600686 name = expr['struct']
Eric Blakedd883c62015-05-04 09:05:21 -0600687 members = expr['data']
688
Eric Blakefd41dd42015-05-04 09:05:25 -0600689 check_type(expr_info, "'data' for struct '%s'" % name, members,
Eric Blakec9e0a792015-05-04 09:05:22 -0600690 allow_dict=True, allow_optional=True)
Eric Blakefd41dd42015-05-04 09:05:25 -0600691 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
Eric Blakedd883c62015-05-04 09:05:21 -0600692 allow_metas=['struct'])
Eric Blakeff55d722015-05-04 09:05:37 -0600693 if expr.get('base'):
694 check_member_clash(expr_info, expr['base'], expr['data'])
Eric Blakedd883c62015-05-04 09:05:21 -0600695
Eric Blake437db252015-09-29 16:21:02 -0600696
Eric Blake0545f6b2015-05-04 09:05:15 -0600697def check_keys(expr_elem, meta, required, optional=[]):
698 expr = expr_elem['expr']
699 info = expr_elem['info']
700 name = expr[meta]
701 if not isinstance(name, str):
702 raise QAPIExprError(info,
703 "'%s' key must have a string value" % meta)
Eric Blake437db252015-09-29 16:21:02 -0600704 required = required + [meta]
Eric Blake0545f6b2015-05-04 09:05:15 -0600705 for (key, value) in expr.items():
Eric Blake437db252015-09-29 16:21:02 -0600706 if key not in required and key not in optional:
Eric Blake0545f6b2015-05-04 09:05:15 -0600707 raise QAPIExprError(info,
708 "Unknown key '%s' in %s '%s'"
709 % (key, meta, name))
Eric Blake437db252015-09-29 16:21:02 -0600710 if (key == 'gen' or key == 'success-response') and value is not False:
Eric Blake2cbf0992015-05-04 09:05:24 -0600711 raise QAPIExprError(info,
712 "'%s' of %s '%s' should only use false value"
713 % (key, meta, name))
Eric Blake0545f6b2015-05-04 09:05:15 -0600714 for key in required:
Eric Blake437db252015-09-29 16:21:02 -0600715 if key not in expr:
Eric Blake0545f6b2015-05-04 09:05:15 -0600716 raise QAPIExprError(info,
717 "Key '%s' is missing from %s '%s'"
718 % (key, meta, name))
719
Eric Blake437db252015-09-29 16:21:02 -0600720
Markus Armbruster4d076d62015-06-10 08:55:21 +0200721def check_exprs(exprs):
722 global all_names
723
724 # Learn the types and check for valid expression keys
725 for builtin in builtin_types.keys():
726 all_names[builtin] = 'built-in'
727 for expr_elem in exprs:
728 expr = expr_elem['expr']
729 info = expr_elem['info']
Eric Blake437db252015-09-29 16:21:02 -0600730 if 'enum' in expr:
Daniel P. Berrange351d36e2015-08-26 14:21:20 +0100731 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
Markus Armbruster4d076d62015-06-10 08:55:21 +0200732 add_enum(expr['enum'], info, expr['data'])
Eric Blake437db252015-09-29 16:21:02 -0600733 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200734 check_keys(expr_elem, 'union', ['data'],
735 ['base', 'discriminator'])
736 add_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600737 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200738 check_keys(expr_elem, 'alternate', ['data'])
739 add_name(expr['alternate'], info, 'alternate')
Eric Blake437db252015-09-29 16:21:02 -0600740 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200741 check_keys(expr_elem, 'struct', ['data'], ['base'])
742 add_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600743 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200744 check_keys(expr_elem, 'command', [],
745 ['data', 'returns', 'gen', 'success-response'])
746 add_name(expr['command'], info, 'command')
Eric Blake437db252015-09-29 16:21:02 -0600747 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200748 check_keys(expr_elem, 'event', [], ['data'])
749 add_name(expr['event'], info, 'event')
750 else:
751 raise QAPIExprError(expr_elem['info'],
752 "Expression is missing metatype")
753
754 # Try again for hidden UnionKind enum
755 for expr_elem in exprs:
756 expr = expr_elem['expr']
Eric Blake437db252015-09-29 16:21:02 -0600757 if 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200758 if not discriminator_find_enum_define(expr):
759 add_enum('%sKind' % expr['union'], expr_elem['info'],
760 implicit=True)
Eric Blake437db252015-09-29 16:21:02 -0600761 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200762 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
763 implicit=True)
764
765 # Validate that exprs make sense
766 for expr_elem in exprs:
767 expr = expr_elem['expr']
768 info = expr_elem['info']
769
Eric Blake437db252015-09-29 16:21:02 -0600770 if 'enum' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200771 check_enum(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600772 elif 'union' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200773 check_union(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600774 elif 'alternate' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200775 check_alternate(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600776 elif 'struct' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200777 check_struct(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600778 elif 'command' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200779 check_command(expr, info)
Eric Blake437db252015-09-29 16:21:02 -0600780 elif 'event' in expr:
Markus Armbruster4d076d62015-06-10 08:55:21 +0200781 check_event(expr, info)
782 else:
783 assert False, 'unexpected meta type'
784
Markus Armbrusterac882192015-09-16 13:06:05 +0200785 return exprs
Eric Blake0545f6b2015-05-04 09:05:15 -0600786
Markus Armbrusterac882192015-09-16 13:06:05 +0200787
788#
789# Schema compiler frontend
790#
791
792class QAPISchemaEntity(object):
793 def __init__(self, name, info):
794 assert isinstance(name, str)
795 self.name = name
796 self.info = info
797
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200798 def c_name(self):
799 return c_name(self.name)
800
Markus Armbrusterac882192015-09-16 13:06:05 +0200801 def check(self, schema):
802 pass
803
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200804 def visit(self, visitor):
805 pass
806
807
808class QAPISchemaVisitor(object):
809 def visit_begin(self, schema):
810 pass
811
812 def visit_end(self):
813 pass
814
815 def visit_builtin_type(self, name, info, json_type):
816 pass
817
818 def visit_enum_type(self, name, info, values, prefix):
819 pass
820
821 def visit_array_type(self, name, info, element_type):
822 pass
823
824 def visit_object_type(self, name, info, base, members, variants):
825 pass
826
Markus Armbruster39a18152015-09-16 13:06:28 +0200827 def visit_object_type_flat(self, name, info, members, variants):
828 pass
829
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200830 def visit_alternate_type(self, name, info, variants):
831 pass
832
833 def visit_command(self, name, info, arg_type, ret_type,
834 gen, success_response):
835 pass
836
837 def visit_event(self, name, info, arg_type):
838 pass
839
Markus Armbrusterac882192015-09-16 13:06:05 +0200840
841class QAPISchemaType(QAPISchemaEntity):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200842 def c_type(self, is_param=False):
843 return c_name(self.name) + pointer_suffix
844
845 def c_null(self):
846 return 'NULL'
847
848 def json_type(self):
849 pass
850
851 def alternate_qtype(self):
852 json2qtype = {
853 'string': 'QTYPE_QSTRING',
854 'number': 'QTYPE_QFLOAT',
855 'int': 'QTYPE_QINT',
856 'boolean': 'QTYPE_QBOOL',
857 'object': 'QTYPE_QDICT'
858 }
859 return json2qtype.get(self.json_type())
Markus Armbrusterac882192015-09-16 13:06:05 +0200860
861
862class QAPISchemaBuiltinType(QAPISchemaType):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200863 def __init__(self, name, json_type, c_type, c_null):
Markus Armbrusterac882192015-09-16 13:06:05 +0200864 QAPISchemaType.__init__(self, name, None)
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200865 assert not c_type or isinstance(c_type, str)
866 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
867 'value')
868 self._json_type_name = json_type
869 self._c_type_name = c_type
870 self._c_null_val = c_null
871
872 def c_name(self):
873 return self.name
874
875 def c_type(self, is_param=False):
876 if is_param and self.name == 'str':
877 return 'const ' + self._c_type_name
878 return self._c_type_name
879
880 def c_null(self):
881 return self._c_null_val
882
883 def json_type(self):
884 return self._json_type_name
Markus Armbrusterac882192015-09-16 13:06:05 +0200885
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200886 def visit(self, visitor):
887 visitor.visit_builtin_type(self.name, self.info, self.json_type())
888
Markus Armbrusterac882192015-09-16 13:06:05 +0200889
890class QAPISchemaEnumType(QAPISchemaType):
891 def __init__(self, name, info, values, prefix):
892 QAPISchemaType.__init__(self, name, info)
893 for v in values:
894 assert isinstance(v, str)
895 assert prefix is None or isinstance(prefix, str)
896 self.values = values
897 self.prefix = prefix
898
899 def check(self, schema):
900 assert len(set(self.values)) == len(self.values)
901
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200902 def c_type(self, is_param=False):
903 return c_name(self.name)
904
905 def c_null(self):
906 return c_enum_const(self.name, (self.values + ['MAX'])[0],
907 self.prefix)
908
909 def json_type(self):
910 return 'string'
911
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200912 def visit(self, visitor):
913 visitor.visit_enum_type(self.name, self.info,
914 self.values, self.prefix)
915
Markus Armbrusterac882192015-09-16 13:06:05 +0200916
917class QAPISchemaArrayType(QAPISchemaType):
918 def __init__(self, name, info, element_type):
919 QAPISchemaType.__init__(self, name, info)
920 assert isinstance(element_type, str)
921 self._element_type_name = element_type
922 self.element_type = None
923
924 def check(self, schema):
925 self.element_type = schema.lookup_type(self._element_type_name)
926 assert self.element_type
927
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200928 def json_type(self):
929 return 'array'
930
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200931 def visit(self, visitor):
932 visitor.visit_array_type(self.name, self.info, self.element_type)
933
Markus Armbrusterac882192015-09-16 13:06:05 +0200934
935class QAPISchemaObjectType(QAPISchemaType):
936 def __init__(self, name, info, base, local_members, variants):
937 QAPISchemaType.__init__(self, name, info)
938 assert base is None or isinstance(base, str)
939 for m in local_members:
940 assert isinstance(m, QAPISchemaObjectTypeMember)
941 assert (variants is None or
942 isinstance(variants, QAPISchemaObjectTypeVariants))
943 self._base_name = base
944 self.base = None
945 self.local_members = local_members
946 self.variants = variants
947 self.members = None
948
949 def check(self, schema):
950 assert self.members is not False # not running in cycles
951 if self.members:
952 return
953 self.members = False # mark as being checked
954 if self._base_name:
955 self.base = schema.lookup_type(self._base_name)
956 assert isinstance(self.base, QAPISchemaObjectType)
957 assert not self.base.variants # not implemented
958 self.base.check(schema)
959 members = list(self.base.members)
960 else:
961 members = []
962 seen = {}
963 for m in members:
964 seen[m.name] = m
965 for m in self.local_members:
966 m.check(schema, members, seen)
967 if self.variants:
968 self.variants.check(schema, members, seen)
969 self.members = members
970
Markus Armbrusterf51d8c32015-09-16 13:06:06 +0200971 def c_name(self):
972 assert self.info
973 return QAPISchemaType.c_name(self)
974
975 def c_type(self, is_param=False):
976 assert self.info
977 return QAPISchemaType.c_type(self)
978
979 def json_type(self):
980 return 'object'
981
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200982 def visit(self, visitor):
983 visitor.visit_object_type(self.name, self.info,
984 self.base, self.local_members, self.variants)
Markus Armbruster39a18152015-09-16 13:06:28 +0200985 visitor.visit_object_type_flat(self.name, self.info,
986 self.members, self.variants)
Markus Armbruster3f7dc212015-09-16 13:06:07 +0200987
Markus Armbrusterac882192015-09-16 13:06:05 +0200988
989class QAPISchemaObjectTypeMember(object):
990 def __init__(self, name, typ, optional):
991 assert isinstance(name, str)
992 assert isinstance(typ, str)
993 assert isinstance(optional, bool)
994 self.name = name
995 self._type_name = typ
996 self.type = None
997 self.optional = optional
998
999 def check(self, schema, all_members, seen):
1000 assert self.name not in seen
1001 self.type = schema.lookup_type(self._type_name)
1002 assert self.type
1003 all_members.append(self)
1004 seen[self.name] = self
1005
1006
1007class QAPISchemaObjectTypeVariants(object):
1008 def __init__(self, tag_name, tag_enum, variants):
1009 assert tag_name is None or isinstance(tag_name, str)
1010 assert tag_enum is None or isinstance(tag_enum, str)
1011 for v in variants:
1012 assert isinstance(v, QAPISchemaObjectTypeVariant)
1013 self.tag_name = tag_name
1014 if tag_name:
1015 assert not tag_enum
1016 self.tag_member = None
1017 else:
1018 self.tag_member = QAPISchemaObjectTypeMember('type', tag_enum,
1019 False)
1020 self.variants = variants
1021
1022 def check(self, schema, members, seen):
1023 if self.tag_name:
1024 self.tag_member = seen[self.tag_name]
1025 else:
1026 self.tag_member.check(schema, members, seen)
1027 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1028 for v in self.variants:
1029 vseen = dict(seen)
1030 v.check(schema, self.tag_member.type, vseen)
1031
Eric Blake437db252015-09-29 16:21:02 -06001032
Markus Armbrusterac882192015-09-16 13:06:05 +02001033class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1034 def __init__(self, name, typ):
1035 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1036
1037 def check(self, schema, tag_type, seen):
1038 QAPISchemaObjectTypeMember.check(self, schema, [], seen)
1039 assert self.name in tag_type.values
1040
Markus Armbruster2b162cc2015-09-16 13:06:09 +02001041 # This function exists to support ugly simple union special cases
1042 # TODO get rid of them, and drop the function
1043 def simple_union_type(self):
1044 if isinstance(self.type, QAPISchemaObjectType) and not self.type.info:
1045 assert len(self.type.members) == 1
1046 assert not self.type.variants
1047 return self.type.members[0].type
1048 return None
1049
Markus Armbrusterac882192015-09-16 13:06:05 +02001050
1051class QAPISchemaAlternateType(QAPISchemaType):
1052 def __init__(self, name, info, variants):
1053 QAPISchemaType.__init__(self, name, info)
1054 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1055 assert not variants.tag_name
1056 self.variants = variants
1057
1058 def check(self, schema):
1059 self.variants.check(schema, [], {})
1060
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001061 def json_type(self):
1062 return 'value'
1063
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001064 def visit(self, visitor):
1065 visitor.visit_alternate_type(self.name, self.info, self.variants)
1066
Markus Armbrusterac882192015-09-16 13:06:05 +02001067
1068class QAPISchemaCommand(QAPISchemaEntity):
1069 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1070 QAPISchemaEntity.__init__(self, name, info)
1071 assert not arg_type or isinstance(arg_type, str)
1072 assert not ret_type or isinstance(ret_type, str)
1073 self._arg_type_name = arg_type
1074 self.arg_type = None
1075 self._ret_type_name = ret_type
1076 self.ret_type = None
1077 self.gen = gen
1078 self.success_response = success_response
1079
1080 def check(self, schema):
1081 if self._arg_type_name:
1082 self.arg_type = schema.lookup_type(self._arg_type_name)
1083 assert isinstance(self.arg_type, QAPISchemaObjectType)
1084 assert not self.arg_type.variants # not implemented
1085 if self._ret_type_name:
1086 self.ret_type = schema.lookup_type(self._ret_type_name)
1087 assert isinstance(self.ret_type, QAPISchemaType)
1088
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001089 def visit(self, visitor):
1090 visitor.visit_command(self.name, self.info,
1091 self.arg_type, self.ret_type,
1092 self.gen, self.success_response)
1093
Markus Armbrusterac882192015-09-16 13:06:05 +02001094
1095class QAPISchemaEvent(QAPISchemaEntity):
1096 def __init__(self, name, info, arg_type):
1097 QAPISchemaEntity.__init__(self, name, info)
1098 assert not arg_type or isinstance(arg_type, str)
1099 self._arg_type_name = arg_type
1100 self.arg_type = None
1101
1102 def check(self, schema):
1103 if self._arg_type_name:
1104 self.arg_type = schema.lookup_type(self._arg_type_name)
1105 assert isinstance(self.arg_type, QAPISchemaObjectType)
1106 assert not self.arg_type.variants # not implemented
1107
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001108 def visit(self, visitor):
1109 visitor.visit_event(self.name, self.info, self.arg_type)
1110
Markus Armbrusterac882192015-09-16 13:06:05 +02001111
1112class QAPISchema(object):
1113 def __init__(self, fname):
1114 try:
1115 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1116 except (QAPISchemaError, QAPIExprError), err:
1117 print >>sys.stderr, err
1118 exit(1)
1119 self._entity_dict = {}
1120 self._def_predefineds()
1121 self._def_exprs()
1122 self.check()
1123
Markus Armbrusterac882192015-09-16 13:06:05 +02001124 def _def_entity(self, ent):
1125 assert ent.name not in self._entity_dict
1126 self._entity_dict[ent.name] = ent
1127
1128 def lookup_entity(self, name, typ=None):
1129 ent = self._entity_dict.get(name)
1130 if typ and not isinstance(ent, typ):
1131 return None
1132 return ent
1133
1134 def lookup_type(self, name):
1135 return self.lookup_entity(name, QAPISchemaType)
1136
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001137 def _def_builtin_type(self, name, json_type, c_type, c_null):
1138 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1139 c_type, c_null))
Markus Armbruster28770e02015-09-16 13:06:24 +02001140 self._make_array_type(name) # TODO really needed?
Markus Armbrusterac882192015-09-16 13:06:05 +02001141
1142 def _def_predefineds(self):
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001143 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1144 ('number', 'number', 'double', '0'),
1145 ('int', 'int', 'int64_t', '0'),
1146 ('int8', 'int', 'int8_t', '0'),
1147 ('int16', 'int', 'int16_t', '0'),
1148 ('int32', 'int', 'int32_t', '0'),
1149 ('int64', 'int', 'int64_t', '0'),
1150 ('uint8', 'int', 'uint8_t', '0'),
1151 ('uint16', 'int', 'uint16_t', '0'),
1152 ('uint32', 'int', 'uint32_t', '0'),
1153 ('uint64', 'int', 'uint64_t', '0'),
1154 ('size', 'int', 'uint64_t', '0'),
1155 ('bool', 'boolean', 'bool', 'false'),
Markus Armbruster28770e02015-09-16 13:06:24 +02001156 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
Markus Armbrusterf51d8c32015-09-16 13:06:06 +02001157 self._def_builtin_type(*t)
Markus Armbruster39a18152015-09-16 13:06:28 +02001158 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1159 [], None)
1160 self._def_entity(self.the_empty_object_type)
Markus Armbrusterac882192015-09-16 13:06:05 +02001161
1162 def _make_implicit_enum_type(self, name, values):
1163 name = name + 'Kind'
1164 self._def_entity(QAPISchemaEnumType(name, None, values, None))
1165 return name
1166
1167 def _make_array_type(self, element_type):
1168 name = element_type + 'List'
1169 if not self.lookup_type(name):
1170 self._def_entity(QAPISchemaArrayType(name, None, element_type))
1171 return name
1172
1173 def _make_implicit_object_type(self, name, role, members):
1174 if not members:
1175 return None
1176 name = ':obj-%s-%s' % (name, role)
1177 if not self.lookup_entity(name, QAPISchemaObjectType):
1178 self._def_entity(QAPISchemaObjectType(name, None, None,
1179 members, None))
1180 return name
1181
1182 def _def_enum_type(self, expr, info):
1183 name = expr['enum']
1184 data = expr['data']
1185 prefix = expr.get('prefix')
1186 self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
1187 self._make_array_type(name) # TODO really needed?
1188
1189 def _make_member(self, name, typ):
1190 optional = False
1191 if name.startswith('*'):
1192 name = name[1:]
1193 optional = True
1194 if isinstance(typ, list):
1195 assert len(typ) == 1
1196 typ = self._make_array_type(typ[0])
1197 return QAPISchemaObjectTypeMember(name, typ, optional)
1198
1199 def _make_members(self, data):
1200 return [self._make_member(key, value)
1201 for (key, value) in data.iteritems()]
1202
1203 def _def_struct_type(self, expr, info):
1204 name = expr['struct']
1205 base = expr.get('base')
1206 data = expr['data']
1207 self._def_entity(QAPISchemaObjectType(name, info, base,
1208 self._make_members(data),
1209 None))
1210 self._make_array_type(name) # TODO really needed?
1211
1212 def _make_variant(self, case, typ):
1213 return QAPISchemaObjectTypeVariant(case, typ)
1214
1215 def _make_simple_variant(self, case, typ):
1216 if isinstance(typ, list):
1217 assert len(typ) == 1
1218 typ = self._make_array_type(typ[0])
1219 typ = self._make_implicit_object_type(typ, 'wrapper',
1220 [self._make_member('data', typ)])
1221 return QAPISchemaObjectTypeVariant(case, typ)
1222
1223 def _make_tag_enum(self, type_name, variants):
1224 return self._make_implicit_enum_type(type_name,
1225 [v.name for v in variants])
1226
1227 def _def_union_type(self, expr, info):
1228 name = expr['union']
1229 data = expr['data']
1230 base = expr.get('base')
1231 tag_name = expr.get('discriminator')
1232 tag_enum = None
1233 if tag_name:
1234 variants = [self._make_variant(key, value)
1235 for (key, value) in data.iteritems()]
1236 else:
1237 variants = [self._make_simple_variant(key, value)
1238 for (key, value) in data.iteritems()]
1239 tag_enum = self._make_tag_enum(name, variants)
1240 self._def_entity(
1241 QAPISchemaObjectType(name, info, base,
1242 self._make_members(OrderedDict()),
1243 QAPISchemaObjectTypeVariants(tag_name,
1244 tag_enum,
1245 variants)))
1246 self._make_array_type(name) # TODO really needed?
1247
1248 def _def_alternate_type(self, expr, info):
1249 name = expr['alternate']
1250 data = expr['data']
1251 variants = [self._make_variant(key, value)
1252 for (key, value) in data.iteritems()]
1253 tag_enum = self._make_tag_enum(name, variants)
1254 self._def_entity(
1255 QAPISchemaAlternateType(name, info,
1256 QAPISchemaObjectTypeVariants(None,
1257 tag_enum,
1258 variants)))
1259 self._make_array_type(name) # TODO really needed?
1260
1261 def _def_command(self, expr, info):
1262 name = expr['command']
1263 data = expr.get('data')
1264 rets = expr.get('returns')
1265 gen = expr.get('gen', True)
1266 success_response = expr.get('success-response', True)
1267 if isinstance(data, OrderedDict):
1268 data = self._make_implicit_object_type(name, 'arg',
1269 self._make_members(data))
1270 if isinstance(rets, list):
1271 assert len(rets) == 1
1272 rets = self._make_array_type(rets[0])
1273 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1274 success_response))
1275
1276 def _def_event(self, expr, info):
1277 name = expr['event']
1278 data = expr.get('data')
1279 if isinstance(data, OrderedDict):
1280 data = self._make_implicit_object_type(name, 'arg',
1281 self._make_members(data))
1282 self._def_entity(QAPISchemaEvent(name, info, data))
1283
1284 def _def_exprs(self):
1285 for expr_elem in self.exprs:
1286 expr = expr_elem['expr']
1287 info = expr_elem['info']
1288 if 'enum' in expr:
1289 self._def_enum_type(expr, info)
1290 elif 'struct' in expr:
1291 self._def_struct_type(expr, info)
1292 elif 'union' in expr:
1293 self._def_union_type(expr, info)
1294 elif 'alternate' in expr:
1295 self._def_alternate_type(expr, info)
1296 elif 'command' in expr:
1297 self._def_command(expr, info)
1298 elif 'event' in expr:
1299 self._def_event(expr, info)
1300 else:
1301 assert False
1302
1303 def check(self):
1304 for ent in self._entity_dict.values():
1305 ent.check(self)
1306
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001307 def visit(self, visitor):
Markus Armbruster39a18152015-09-16 13:06:28 +02001308 ignore = visitor.visit_begin(self)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001309 for name in sorted(self._entity_dict.keys()):
Markus Armbruster39a18152015-09-16 13:06:28 +02001310 if not ignore or not isinstance(self._entity_dict[name], ignore):
1311 self._entity_dict[name].visit(visitor)
Markus Armbruster3f7dc212015-09-16 13:06:07 +02001312 visitor.visit_end()
1313
Markus Armbruster2caba362013-07-27 17:41:56 +02001314
Markus Armbruster00e4b282015-06-10 10:04:36 +02001315#
1316# Code generation helpers
1317#
1318
Michael Roth0f923be2011-07-19 14:50:39 -05001319def camel_case(name):
1320 new_name = ''
1321 first = True
1322 for ch in name:
1323 if ch in ['_', '-']:
1324 first = True
1325 elif first:
1326 new_name += ch.upper()
1327 first = False
1328 else:
1329 new_name += ch.lower()
1330 return new_name
1331
Eric Blake437db252015-09-29 16:21:02 -06001332
Markus Armbruster849bc532015-05-14 06:50:53 -06001333# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1334# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1335# ENUM24_Name -> ENUM24_NAME
1336def camel_to_upper(value):
1337 c_fun_str = c_name(value, False)
1338 if value.isupper():
1339 return c_fun_str
1340
1341 new_name = ''
1342 l = len(c_fun_str)
1343 for i in range(l):
1344 c = c_fun_str[i]
1345 # When c is upper and no "_" appears before, do more checks
1346 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
Eric Blake437db252015-09-29 16:21:02 -06001347 if i < l - 1 and c_fun_str[i + 1].islower():
1348 new_name += '_'
1349 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -06001350 new_name += '_'
1351 new_name += c
1352 return new_name.lstrip('_').upper()
1353
Eric Blake437db252015-09-29 16:21:02 -06001354
Daniel P. Berrange351d36e2015-08-26 14:21:20 +01001355def c_enum_const(type_name, const_name, prefix=None):
1356 if prefix is not None:
1357 type_name = prefix
Markus Armbruster849bc532015-05-14 06:50:53 -06001358 return camel_to_upper(type_name + '_' + const_name)
1359
Eric Blake18df5152015-05-14 06:50:48 -06001360c_name_trans = string.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -06001361
Eric Blake437db252015-09-29 16:21:02 -06001362
Eric Blakec6405b52015-05-14 06:50:55 -06001363# Map @name to a valid C identifier.
1364# If @protect, avoid returning certain ticklish identifiers (like
1365# C keywords) by prepending "q_".
1366#
1367# Used for converting 'name' from a 'name':'type' qapi definition
1368# into a generated struct member, as well as converting type names
1369# into substrings of a generated C function name.
1370# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1371# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
Eric Blake18df5152015-05-14 06:50:48 -06001372def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +00001373 # ANSI X3J11/88-090, 3.1.1
1374 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -06001375 'default', 'do', 'double', 'else', 'enum', 'extern',
1376 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1377 'return', 'short', 'signed', 'sizeof', 'static',
1378 'struct', 'switch', 'typedef', 'union', 'unsigned',
1379 'void', 'volatile', 'while'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001380 # ISO/IEC 9899:1999, 6.4.1
1381 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1382 # ISO/IEC 9899:2011, 6.4.1
Eric Blake437db252015-09-29 16:21:02 -06001383 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1384 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +00001385 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1386 # excluding _.*
1387 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -04001388 # C++ ISO/IEC 14882:2003 2.11
1389 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1390 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1391 'namespace', 'new', 'operator', 'private', 'protected',
1392 'public', 'reinterpret_cast', 'static_cast', 'template',
1393 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1394 'using', 'virtual', 'wchar_t',
1395 # alternative representations
1396 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1397 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
Paolo Bonzini10577252012-09-19 16:31:07 +02001398 # namespace pollution:
Max Reitz8592a542013-12-20 19:28:18 +01001399 polluted_words = set(['unix', 'errno'])
Eric Blake437db252015-09-29 16:21:02 -06001400 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1401 | cpp_words | polluted_words):
Blue Swirl427a1a22012-07-30 15:46:55 +00001402 return "q_" + name
Eric Blake18df5152015-05-14 06:50:48 -06001403 return name.translate(c_name_trans)
Michael Roth0f923be2011-07-19 14:50:39 -05001404
Amos Kong05dfb262014-06-10 19:25:53 +08001405eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -06001406pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +08001407
Eric Blake437db252015-09-29 16:21:02 -06001408
Michael Roth0f923be2011-07-19 14:50:39 -05001409def genindent(count):
1410 ret = ""
Eric Blake437db252015-09-29 16:21:02 -06001411 for _ in range(count):
Michael Roth0f923be2011-07-19 14:50:39 -05001412 ret += " "
1413 return ret
1414
1415indent_level = 0
1416
Eric Blake437db252015-09-29 16:21:02 -06001417
Michael Roth0f923be2011-07-19 14:50:39 -05001418def push_indent(indent_amount=4):
1419 global indent_level
1420 indent_level += indent_amount
1421
Eric Blake437db252015-09-29 16:21:02 -06001422
Michael Roth0f923be2011-07-19 14:50:39 -05001423def pop_indent(indent_amount=4):
1424 global indent_level
1425 indent_level -= indent_amount
1426
Eric Blake437db252015-09-29 16:21:02 -06001427
Markus Armbruster77e703b2015-06-24 19:27:32 +02001428# Generate @code with @kwds interpolated.
1429# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -05001430def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001431 raw = code % kwds
1432 if indent_level:
1433 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +02001434 # re.subn() lacks flags support before Python 2.7, use re.compile()
1435 raw = re.subn(re.compile("^.", re.MULTILINE),
1436 indent + r'\g<0>', raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +02001437 raw = raw[0]
1438 return re.sub(re.escape(eatspace) + ' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -05001439
Eric Blake437db252015-09-29 16:21:02 -06001440
Michael Roth0f923be2011-07-19 14:50:39 -05001441def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +02001442 if code[0] == '\n':
1443 code = code[1:]
1444 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -05001445
Michael Roth0f923be2011-07-19 14:50:39 -05001446
1447def guardname(filename):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001448 return c_name(filename, protect=False).upper()
Michael Rothc0afa9c2013-05-10 17:46:00 -05001449
Eric Blake437db252015-09-29 16:21:02 -06001450
Michael Rothc0afa9c2013-05-10 17:46:00 -05001451def guardstart(name):
1452 return mcgen('''
1453
1454#ifndef %(name)s
1455#define %(name)s
1456
1457''',
1458 name=guardname(name))
1459
Eric Blake437db252015-09-29 16:21:02 -06001460
Michael Rothc0afa9c2013-05-10 17:46:00 -05001461def guardend(name):
1462 return mcgen('''
1463
1464#endif /* %(name)s */
1465
1466''',
1467 name=guardname(name))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001468
Eric Blake437db252015-09-29 16:21:02 -06001469
Markus Armbrustere98859a2015-09-16 13:06:16 +02001470def gen_enum_lookup(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001471 ret = mcgen('''
1472
Markus Armbrustere98859a2015-09-16 13:06:16 +02001473const char *const %(c_name)s_lookup[] = {
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001474''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001475 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001476 for value in values:
1477 index = c_enum_const(name, value, prefix)
1478 ret += mcgen('''
1479 [%(index)s] = "%(value)s",
1480''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001481 index=index, value=value)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001482
1483 max_index = c_enum_const(name, 'MAX', prefix)
1484 ret += mcgen('''
1485 [%(max_index)s] = NULL,
1486};
1487''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001488 max_index=max_index)
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001489 return ret
1490
Eric Blake437db252015-09-29 16:21:02 -06001491
Markus Armbrustere98859a2015-09-16 13:06:16 +02001492def gen_enum(name, values, prefix=None):
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001493 # append automatically generated _MAX value
Markus Armbrustere98859a2015-09-16 13:06:16 +02001494 enum_values = values + ['MAX']
1495
1496 ret = mcgen('''
1497
1498typedef enum %(c_name)s {
1499''',
1500 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001501
1502 i = 0
1503 for value in enum_values:
Markus Armbrustere98859a2015-09-16 13:06:16 +02001504 ret += mcgen('''
1505 %(c_enum)s = %(i)d,
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001506''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001507 c_enum=c_enum_const(name, value, prefix),
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001508 i=i)
1509 i += 1
1510
Markus Armbrustere98859a2015-09-16 13:06:16 +02001511 ret += mcgen('''
1512} %(c_name)s;
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001513''',
Markus Armbrustere98859a2015-09-16 13:06:16 +02001514 c_name=c_name(name))
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001515
Markus Armbrustere98859a2015-09-16 13:06:16 +02001516 ret += mcgen('''
1517
1518extern const char *const %(c_name)s_lookup[];
1519''',
1520 c_name=c_name(name))
1521 return ret
Markus Armbrusterefd2eaa2015-09-16 13:06:12 +02001522
Eric Blake437db252015-09-29 16:21:02 -06001523
Markus Armbruster03b43672015-09-16 13:06:20 +02001524def gen_params(arg_type, extra):
1525 if not arg_type:
1526 return extra
1527 assert not arg_type.variants
1528 ret = ''
1529 sep = ''
1530 for memb in arg_type.members:
1531 ret += sep
1532 sep = ', '
1533 if memb.optional:
1534 ret += 'bool has_%s, ' % c_name(memb.name)
1535 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1536 if extra:
1537 ret += sep + extra
1538 return ret
1539
Markus Armbruster00e4b282015-06-10 10:04:36 +02001540#
1541# Common command line parsing
1542#
1543
Eric Blake437db252015-09-29 16:21:02 -06001544
1545def parse_command_line(extra_options="", extra_long_options=[]):
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001546
1547 try:
1548 opts, args = getopt.gnu_getopt(sys.argv[1:],
Markus Armbruster16d80f62015-04-02 13:32:16 +02001549 "chp:o:" + extra_options,
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001550 ["source", "header", "prefix=",
Markus Armbruster16d80f62015-04-02 13:32:16 +02001551 "output-dir="] + extra_long_options)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001552 except getopt.GetoptError, err:
Markus Armbrusterb4540962015-04-02 13:17:34 +02001553 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001554 sys.exit(1)
1555
1556 output_dir = ""
1557 prefix = ""
1558 do_c = False
1559 do_h = False
1560 extra_opts = []
1561
1562 for oa in opts:
1563 o, a = oa
1564 if o in ("-p", "--prefix"):
Markus Armbruster1cf47a12015-07-01 13:13:54 +02001565 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1566 if match.end() != len(a):
1567 print >>sys.stderr, \
1568 "%s: 'funny character '%s' in argument of --prefix" \
1569 % (sys.argv[0], a[match.end()])
1570 sys.exit(1)
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001571 prefix = a
Markus Armbruster2114f5a2015-04-02 13:12:21 +02001572 elif o in ("-o", "--output-dir"):
1573 output_dir = a + "/"
1574 elif o in ("-c", "--source"):
1575 do_c = True
1576 elif o in ("-h", "--header"):
1577 do_h = True
1578 else:
1579 extra_opts.append(oa)
1580
1581 if not do_c and not do_h:
1582 do_c = True
1583 do_h = True
1584
Markus Armbruster16d80f62015-04-02 13:32:16 +02001585 if len(args) != 1:
1586 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001587 sys.exit(1)
Markus Armbruster54414042015-06-09 16:22:45 +02001588 fname = args[0]
Markus Armbrusterb4540962015-04-02 13:17:34 +02001589
Markus Armbruster54414042015-06-09 16:22:45 +02001590 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001591
Markus Armbruster00e4b282015-06-10 10:04:36 +02001592#
1593# Generate output files with boilerplate
1594#
1595
Eric Blake437db252015-09-29 16:21:02 -06001596
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001597def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1598 c_comment, h_comment):
Markus Armbruster00dfc3b2015-06-27 07:27:21 +02001599 guard = guardname(prefix + h_file)
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001600 c_file = output_dir + prefix + c_file
1601 h_file = output_dir + prefix + h_file
1602
Markus Armbrusterc4f498f2015-09-03 10:24:25 +02001603 if output_dir:
1604 try:
1605 os.makedirs(output_dir)
1606 except os.error, e:
1607 if e.errno != errno.EEXIST:
1608 raise
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001609
1610 def maybe_open(really, name, opt):
1611 if really:
1612 return open(name, opt)
1613 else:
1614 import StringIO
1615 return StringIO.StringIO()
1616
1617 fdef = maybe_open(do_c, c_file, 'w')
1618 fdecl = maybe_open(do_h, h_file, 'w')
1619
1620 fdef.write(mcgen('''
1621/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1622%(comment)s
1623''',
Eric Blake437db252015-09-29 16:21:02 -06001624 comment=c_comment))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001625
1626 fdecl.write(mcgen('''
1627/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1628%(comment)s
1629#ifndef %(guard)s
1630#define %(guard)s
1631
1632''',
Eric Blake437db252015-09-29 16:21:02 -06001633 comment=h_comment, guard=guard))
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001634
1635 return (fdef, fdecl)
1636
Eric Blake437db252015-09-29 16:21:02 -06001637
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001638def close_output(fdef, fdecl):
1639 fdecl.write('''
1640#endif
1641''')
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001642 fdecl.close()
Markus Armbruster12f8e1b2015-04-02 14:46:39 +02001643 fdef.close()