]> git.proxmox.com Git - mirror_qemu.git/blame - scripts/qapi.py
qapi: Factor out QAPISchemaObjectTypeMember.check_clash()
[mirror_qemu.git] / scripts / qapi.py
CommitLineData
0f923be2
MR
1#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
fe2a9303 5# Copyright (c) 2013-2015 Red Hat Inc.
0f923be2
MR
6#
7# Authors:
8# Anthony Liguori <aliguori@us.ibm.com>
c7a3f252 9# Markus Armbruster <armbru@redhat.com>
0f923be2 10#
678e48a2
MA
11# This work is licensed under the terms of the GNU GPL, version 2.
12# See the COPYING file in the top-level directory.
0f923be2 13
a719a27c 14import re
0f923be2 15from ordereddict import OrderedDict
12f8e1b9 16import errno
2114f5a9 17import getopt
33aaad52 18import os
2caba36c 19import sys
47299262 20import string
0f923be2 21
b52c4b9c 22builtin_types = {
69dd62df
KW
23 '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',
cb17f79e 35 'size': 'QTYPE_QINT',
28770e05 36 'any': None, # any qtype_code possible, actually
69dd62df
KW
37}
38
10d4d997
EB
39# Whitelist of commands allowed to return a non-dictionary
40returns_whitelist = [
41 # From QMP:
42 'human-monitor-command',
6eb3937e 43 'qom-get',
10d4d997
EB
44 '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',
10d4d997
EB
59]
60
4dc2e690
EB
61enum_types = []
62struct_types = []
63union_types = []
64events = []
65all_names = {}
66
00e4b285
MA
67#
68# Parsing the schema into expressions
69#
70
437db254 71
a719a27c
LV
72def error_path(parent):
73 res = ""
74 while parent:
75 res = ("In file included from %s:%d:\n" % (parent['file'],
76 parent['line'])) + res
77 parent = parent['parent']
78 return res
79
437db254 80
2caba36c
MA
81class QAPISchemaError(Exception):
82 def __init__(self, schema, msg):
59b00542 83 Exception.__init__(self)
54414047 84 self.fname = schema.fname
2caba36c 85 self.msg = msg
515b943a
WX
86 self.col = 1
87 self.line = schema.line
88 for ch in schema.src[schema.line_pos:schema.pos]:
89 if ch == '\t':
2caba36c
MA
90 self.col = (self.col + 7) % 8 + 1
91 else:
92 self.col += 1
54414047 93 self.info = schema.incl_info
2caba36c
MA
94
95 def __str__(self):
a719a27c 96 return error_path(self.info) + \
54414047 97 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
2caba36c 98
437db254 99
b86b05ed
WX
100class QAPIExprError(Exception):
101 def __init__(self, expr_info, msg):
59b00542 102 Exception.__init__(self)
7618b91f 103 assert expr_info
a719a27c 104 self.info = expr_info
b86b05ed
WX
105 self.msg = msg
106
107 def __str__(self):
a719a27c
LV
108 return error_path(self.info['parent']) + \
109 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
b86b05ed 110
437db254 111
a4bcb208 112class QAPISchemaParser(object):
c7a3f252 113
437db254 114 def __init__(self, fp, previously_included=[], incl_info=None):
54414047 115 abs_fname = os.path.abspath(fp.name)
8608d252 116 fname = fp.name
54414047 117 self.fname = fname
54414047
MA
118 previously_included.append(abs_fname)
119 self.incl_info = incl_info
c7a3f252
MA
120 self.src = fp.read()
121 if self.src == '' or self.src[-1] != '\n':
122 self.src += '\n'
123 self.cursor = 0
515b943a
WX
124 self.line = 1
125 self.line_pos = 0
c7a3f252
MA
126 self.exprs = []
127 self.accept()
128
437db254 129 while self.tok is not None:
54414047
MA
130 expr_info = {'file': fname, 'line': self.line,
131 'parent': self.incl_info}
a719a27c
LV
132 expr = self.get_expr(False)
133 if isinstance(expr, dict) and "include" in expr:
134 if len(expr) != 1:
437db254
EB
135 raise QAPIExprError(expr_info,
136 "Invalid 'include' directive")
a719a27c
LV
137 include = expr["include"]
138 if not isinstance(include, str):
139 raise QAPIExprError(expr_info,
7408fb67 140 "Value of 'include' must be a string")
54414047
MA
141 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
142 include)
a1366087
MA
143 # catch inclusion cycle
144 inf = expr_info
145 while inf:
146 if incl_abs_fname == os.path.abspath(inf['file']):
7ac9a9d6
SH
147 raise QAPIExprError(expr_info, "Inclusion loop for %s"
148 % include)
a1366087 149 inf = inf['parent']
24fd8489 150 # skip multiple include of the same file
54414047 151 if incl_abs_fname in previously_included:
24fd8489 152 continue
a719a27c 153 try:
54414047 154 fobj = open(incl_abs_fname, 'r')
34788811 155 except IOError, e:
a719a27c
LV
156 raise QAPIExprError(expr_info,
157 '%s: %s' % (e.strerror, include))
a4bcb208
MA
158 exprs_include = QAPISchemaParser(fobj, previously_included,
159 expr_info)
a719a27c
LV
160 self.exprs.extend(exprs_include.exprs)
161 else:
162 expr_elem = {'expr': expr,
163 'info': expr_info}
164 self.exprs.append(expr_elem)
c7a3f252
MA
165
166 def accept(self):
167 while True:
c7a3f252 168 self.tok = self.src[self.cursor]
2caba36c 169 self.pos = self.cursor
c7a3f252
MA
170 self.cursor += 1
171 self.val = None
172
f1a145e1 173 if self.tok == '#':
c7a3f252 174 self.cursor = self.src.find('\n', self.cursor)
8712fa53 175 elif self.tok in "{}:,[]":
c7a3f252
MA
176 return
177 elif self.tok == "'":
178 string = ''
179 esc = False
180 while True:
181 ch = self.src[self.cursor]
182 self.cursor += 1
183 if ch == '\n':
2caba36c
MA
184 raise QAPISchemaError(self,
185 'Missing terminating "\'"')
c7a3f252 186 if esc:
a7f5966b
EB
187 if ch == 'b':
188 string += '\b'
189 elif ch == 'f':
190 string += '\f'
191 elif ch == 'n':
192 string += '\n'
193 elif ch == 'r':
194 string += '\r'
195 elif ch == 't':
196 string += '\t'
197 elif ch == 'u':
198 value = 0
437db254 199 for _ in range(0, 4):
a7f5966b
EB
200 ch = self.src[self.cursor]
201 self.cursor += 1
202 if ch not in "0123456789abcdefABCDEF":
203 raise QAPISchemaError(self,
204 '\\u escape needs 4 '
205 'hex digits')
206 value = (value << 4) + int(ch, 16)
207 # If Python 2 and 3 didn't disagree so much on
208 # how to handle Unicode, then we could allow
209 # Unicode string defaults. But most of QAPI is
210 # ASCII-only, so we aren't losing much for now.
211 if not value or value > 0x7f:
212 raise QAPISchemaError(self,
213 'For now, \\u escape '
214 'only supports non-zero '
215 'values up to \\u007f')
216 string += chr(value)
217 elif ch in "\\/'\"":
218 string += ch
219 else:
220 raise QAPISchemaError(self,
437db254 221 "Unknown escape \\%s" % ch)
c7a3f252
MA
222 esc = False
223 elif ch == "\\":
224 esc = True
225 elif ch == "'":
226 self.val = string
227 return
228 else:
229 string += ch
e565d934
MA
230 elif self.src.startswith("true", self.pos):
231 self.val = True
232 self.cursor += 3
233 return
234 elif self.src.startswith("false", self.pos):
235 self.val = False
236 self.cursor += 4
237 return
238 elif self.src.startswith("null", self.pos):
239 self.val = None
240 self.cursor += 3
241 return
c7a3f252
MA
242 elif self.tok == '\n':
243 if self.cursor == len(self.src):
244 self.tok = None
245 return
515b943a
WX
246 self.line += 1
247 self.line_pos = self.cursor
9213aa53
MA
248 elif not self.tok.isspace():
249 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
c7a3f252
MA
250
251 def get_members(self):
252 expr = OrderedDict()
6974ccd5
MA
253 if self.tok == '}':
254 self.accept()
255 return expr
256 if self.tok != "'":
257 raise QAPISchemaError(self, 'Expected string or "}"')
258 while True:
c7a3f252
MA
259 key = self.val
260 self.accept()
6974ccd5
MA
261 if self.tok != ':':
262 raise QAPISchemaError(self, 'Expected ":"')
263 self.accept()
4b35991a
WX
264 if key in expr:
265 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
5f3cd2b7 266 expr[key] = self.get_expr(True)
6974ccd5 267 if self.tok == '}':
c7a3f252 268 self.accept()
6974ccd5
MA
269 return expr
270 if self.tok != ',':
271 raise QAPISchemaError(self, 'Expected "," or "}"')
272 self.accept()
273 if self.tok != "'":
274 raise QAPISchemaError(self, 'Expected string')
c7a3f252
MA
275
276 def get_values(self):
277 expr = []
6974ccd5
MA
278 if self.tok == ']':
279 self.accept()
280 return expr
437db254 281 if self.tok not in "{['tfn":
e53188ad
FZ
282 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
283 'boolean or "null"')
6974ccd5 284 while True:
5f3cd2b7 285 expr.append(self.get_expr(True))
6974ccd5 286 if self.tok == ']':
c7a3f252 287 self.accept()
6974ccd5
MA
288 return expr
289 if self.tok != ',':
290 raise QAPISchemaError(self, 'Expected "," or "]"')
291 self.accept()
c7a3f252 292
5f3cd2b7
MA
293 def get_expr(self, nested):
294 if self.tok != '{' and not nested:
295 raise QAPISchemaError(self, 'Expected "{"')
c7a3f252
MA
296 if self.tok == '{':
297 self.accept()
298 expr = self.get_members()
299 elif self.tok == '[':
300 self.accept()
301 expr = self.get_values()
e53188ad 302 elif self.tok in "'tfn":
c7a3f252
MA
303 expr = self.val
304 self.accept()
6974ccd5
MA
305 else:
306 raise QAPISchemaError(self, 'Expected "{", "[" or string')
c7a3f252 307 return expr
bd9927fe 308
00e4b285
MA
309#
310# Semantic analysis of schema expressions
ac88219a
MA
311# TODO fold into QAPISchema
312# TODO catching name collisions in generated code would be nice
00e4b285
MA
313#
314
437db254 315
b86b05ed
WX
316def find_base_fields(base):
317 base_struct_define = find_struct(base)
318 if not base_struct_define:
319 return None
320 return base_struct_define['data']
321
437db254 322
811d04fd
EB
323# Return the qtype of an alternate branch, or None on error.
324def find_alternate_member_qtype(qapi_type):
437db254 325 if qapi_type in builtin_types:
44bd1276
EB
326 return builtin_types[qapi_type]
327 elif find_struct(qapi_type):
328 return "QTYPE_QDICT"
329 elif find_enum(qapi_type):
330 return "QTYPE_QSTRING"
811d04fd
EB
331 elif find_union(qapi_type):
332 return "QTYPE_QDICT"
44bd1276
EB
333 return None
334
437db254 335
bceae769
WX
336# Return the discriminator enum define if discriminator is specified as an
337# enum type, otherwise return None.
338def discriminator_find_enum_define(expr):
339 base = expr.get('base')
340 discriminator = expr.get('discriminator')
341
342 if not (discriminator and base):
343 return None
344
345 base_fields = find_base_fields(base)
346 if not base_fields:
347 return None
348
349 discriminator_type = base_fields.get(discriminator)
350 if not discriminator_type:
351 return None
352
353 return find_enum(discriminator_type)
354
437db254 355
d90675fa
MA
356# FIXME should enforce "other than downstream extensions [...], all
357# names should begin with a letter".
c9e0a798 358valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
437db254
EB
359
360
361def check_name(expr_info, source, name, allow_optional=False,
362 enum_member=False):
c9e0a798
EB
363 global valid_name
364 membername = name
365
366 if not isinstance(name, str):
367 raise QAPIExprError(expr_info,
368 "%s requires a string name" % source)
369 if name.startswith('*'):
370 membername = name[1:]
371 if not allow_optional:
372 raise QAPIExprError(expr_info,
373 "%s does not allow optional name '%s'"
374 % (source, name))
375 # Enum members can start with a digit, because the generated C
376 # code always prefixes it with the enum name
377 if enum_member:
378 membername = '_' + membername
9fb081e0
EB
379 # Reserve the entire 'q_' namespace for c_name()
380 if not valid_name.match(membername) or \
381 c_name(membername, False).startswith('q_'):
c9e0a798
EB
382 raise QAPIExprError(expr_info,
383 "%s uses invalid name '%s'" % (source, name))
384
437db254
EB
385
386def add_name(name, info, meta, implicit=False):
00e4b285
MA
387 global all_names
388 check_name(info, "'%s'" % meta, name)
d90675fa
MA
389 # FIXME should reject names that differ only in '_' vs. '.'
390 # vs. '-', because they're liable to clash in generated C.
00e4b285
MA
391 if name in all_names:
392 raise QAPIExprError(info,
393 "%s '%s' is already defined"
394 % (all_names[name], name))
255960dd 395 if not implicit and (name.endswith('Kind') or name.endswith('List')):
00e4b285 396 raise QAPIExprError(info,
255960dd
EB
397 "%s '%s' should not end in '%s'"
398 % (meta, name, name[-4:]))
00e4b285
MA
399 all_names[name] = meta
400
437db254 401
00e4b285
MA
402def add_struct(definition, info):
403 global struct_types
404 name = definition['struct']
405 add_name(name, info, 'struct')
406 struct_types.append(definition)
407
437db254 408
00e4b285
MA
409def 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
437db254 416
00e4b285
MA
417def add_union(definition, info):
418 global union_types
419 name = definition['union']
420 add_name(name, info, 'union')
421 union_types.append(definition)
422
437db254 423
00e4b285
MA
424def 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
437db254
EB
431
432def add_enum(name, info, enum_values=None, implicit=False):
00e4b285
MA
433 global enum_types
434 add_name(name, info, 'enum', implicit)
435 enum_types.append({"enum_name": name, "enum_values": enum_values})
436
437db254 437
00e4b285
MA
438def 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
437db254 445
00e4b285 446def is_enum(name):
437db254
EB
447 return find_enum(name) is not None
448
00e4b285 449
437db254
EB
450def check_type(expr_info, source, value, allow_array=False,
451 allow_dict=False, allow_optional=False,
452 allow_metas=[]):
dd883c6f 453 global all_names
dd883c6f
EB
454
455 if value is None:
456 return
457
dd883c6f
EB
458 # 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]
dd883c6f
EB
468
469 # Check if type name for value is okay
470 if isinstance(value, str):
437db254 471 if value not in all_names:
dd883c6f
EB
472 raise QAPIExprError(expr_info,
473 "%s uses unknown type '%s'"
eddf817b 474 % (source, value))
dd883c6f
EB
475 if not all_names[value] in allow_metas:
476 raise QAPIExprError(expr_info,
477 "%s cannot use %s type '%s'"
eddf817b 478 % (source, all_names[value], value))
dd883c6f
EB
479 return
480
dd883c6f
EB
481 if not allow_dict:
482 raise QAPIExprError(expr_info,
483 "%s should be a type name" % source)
c6b71e5a
MA
484
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
dd883c6f 490 for (key, arg) in value.items():
c9e0a798
EB
491 check_name(expr_info, "Member of %s" % source, key,
492 allow_optional=allow_optional)
5e59baf9 493 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
9fb081e0
EB
494 raise QAPIExprError(expr_info,
495 "Member of %s uses reserved name '%s'"
496 % (source, key))
6b5abc7d
EB
497 # Todo: allow dictionaries to represent default values of
498 # an optional argument.
dd883c6f 499 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
2d21291a 500 allow_array=True,
dd883c6f 501 allow_metas=['built-in', 'union', 'alternate', 'struct',
6b5abc7d 502 'enum'])
dd883c6f 503
437db254
EB
504
505def check_member_clash(expr_info, base_name, data, source=""):
ff55d72e
EB
506 base = find_struct(base_name)
507 assert base
508 base_members = base['data']
509 for key in data.keys():
510 if key.startswith('*'):
511 key = key[1:]
512 if key in base_members or "*" + key in base_members:
513 raise QAPIExprError(expr_info,
514 "Member name '%s'%s clashes with base '%s'"
515 % (key, source, base_name))
516 if base.get('base'):
517 check_member_clash(expr_info, base['base'], data, source)
518
437db254 519
dd883c6f
EB
520def check_command(expr, expr_info):
521 name = expr['command']
2cbf0992 522
dd883c6f 523 check_type(expr_info, "'data' for command '%s'" % name,
c9e0a798 524 expr.get('data'), allow_dict=True, allow_optional=True,
2d21291a 525 allow_metas=['struct'])
10d4d997
EB
526 returns_meta = ['union', 'struct']
527 if name in returns_whitelist:
528 returns_meta += ['built-in', 'alternate', 'enum']
dd883c6f 529 check_type(expr_info, "'returns' for command '%s'" % name,
9b090d42 530 expr.get('returns'), allow_array=True,
2d21291a 531 allow_optional=True, allow_metas=returns_meta)
dd883c6f 532
437db254 533
21cd70df 534def check_event(expr, expr_info):
4dc2e690
EB
535 global events
536 name = expr['event']
4dc2e690
EB
537
538 if name.upper() == 'MAX':
539 raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
540 events.append(name)
dd883c6f 541 check_type(expr_info, "'data' for event '%s'" % name,
c9e0a798 542 expr.get('data'), allow_dict=True, allow_optional=True,
315932b5 543 allow_metas=['struct'])
21cd70df 544
437db254 545
b86b05ed
WX
546def check_union(expr, expr_info):
547 name = expr['union']
548 base = expr.get('base')
549 discriminator = expr.get('discriminator')
550 members = expr['data']
f51d8fab
EB
551 values = {'MAX': '(automatic)', 'KIND': '(automatic)',
552 'TYPE': '(automatic)'}
b86b05ed 553
811d04fd 554 # Two types of unions, determined by discriminator.
811d04fd
EB
555
556 # With no discriminator it is a simple union.
557 if discriminator is None:
b86b05ed 558 enum_define = None
437db254 559 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
44bd1276
EB
560 if base is not None:
561 raise QAPIExprError(expr_info,
811d04fd 562 "Simple union '%s' must not have a base"
44bd1276 563 % name)
b86b05ed
WX
564
565 # Else, it's a flat union.
566 else:
44bd1276 567 # The object must have a string member 'base'.
376863ef
EB
568 check_type(expr_info, "'base' for union '%s'" % name,
569 base, allow_metas=['struct'])
570 if not base:
b86b05ed 571 raise QAPIExprError(expr_info,
376863ef 572 "Flat union '%s' must have a base"
b86b05ed 573 % name)
44bd1276 574 base_fields = find_base_fields(base)
376863ef 575 assert base_fields
44bd1276 576
c9e0a798 577 # The value of member 'discriminator' must name a non-optional
fd41dd4e 578 # member of the base struct.
c9e0a798
EB
579 check_name(expr_info, "Discriminator of flat union '%s'" % name,
580 discriminator)
b86b05ed
WX
581 discriminator_type = base_fields.get(discriminator)
582 if not discriminator_type:
583 raise QAPIExprError(expr_info,
584 "Discriminator '%s' is not a member of base "
fd41dd4e 585 "struct '%s'"
b86b05ed
WX
586 % (discriminator, base))
587 enum_define = find_enum(discriminator_type)
437db254 588 allow_metas = ['struct']
5223070c
WX
589 # Do not allow string discriminator
590 if not enum_define:
591 raise QAPIExprError(expr_info,
592 "Discriminator '%s' must be of enumeration "
593 "type" % discriminator)
b86b05ed
WX
594
595 # Check every branch
596 for (key, value) in members.items():
c9e0a798
EB
597 check_name(expr_info, "Member of union '%s'" % name, key)
598
dd883c6f 599 # Each value must name a known type; furthermore, in flat unions,
ff55d72e 600 # branches must be a struct with no overlapping member names
dd883c6f 601 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
f9a14273 602 value, allow_array=not base, allow_metas=allow_metas)
ff55d72e
EB
603 if base:
604 branch_struct = find_struct(value)
605 assert branch_struct
606 check_member_clash(expr_info, base, branch_struct['data'],
607 " of branch '%s'" % key)
dd883c6f 608
44bd1276 609 # If the discriminator names an enum type, then all members
7b2a5c2f
EB
610 # of 'data' must also be members of the enum type, which in turn
611 # must not collide with the discriminator name.
44bd1276 612 if enum_define:
437db254 613 if key not in enum_define['enum_values']:
44bd1276
EB
614 raise QAPIExprError(expr_info,
615 "Discriminator value '%s' is not found in "
616 "enum '%s'" %
617 (key, enum_define["enum_name"]))
7b2a5c2f
EB
618 if discriminator in enum_define['enum_values']:
619 raise QAPIExprError(expr_info,
620 "Discriminator name '%s' collides with "
621 "enum value in '%s'" %
622 (discriminator, enum_define["enum_name"]))
44bd1276
EB
623
624 # Otherwise, check for conflicts in the generated enum
625 else:
fa6068a1 626 c_key = camel_to_upper(key)
44bd1276
EB
627 if c_key in values:
628 raise QAPIExprError(expr_info,
629 "Union '%s' member '%s' clashes with '%s'"
630 % (name, key, values[c_key]))
631 values[c_key] = key
632
437db254 633
811d04fd 634def check_alternate(expr, expr_info):
ab916fad 635 name = expr['alternate']
811d04fd 636 members = expr['data']
437db254 637 values = {'MAX': '(automatic)'}
811d04fd
EB
638 types_seen = {}
639
811d04fd
EB
640 # Check every branch
641 for (key, value) in members.items():
c9e0a798
EB
642 check_name(expr_info, "Member of alternate '%s'" % name, key)
643
811d04fd 644 # Check for conflicts in the generated enum
fa6068a1 645 c_key = camel_to_upper(key)
811d04fd
EB
646 if c_key in values:
647 raise QAPIExprError(expr_info,
ab916fad
EB
648 "Alternate '%s' member '%s' clashes with '%s'"
649 % (name, key, values[c_key]))
811d04fd 650 values[c_key] = key
44bd1276 651
811d04fd 652 # Ensure alternates have no type conflicts.
dd883c6f
EB
653 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
654 value,
655 allow_metas=['built-in', 'union', 'struct', 'enum'])
811d04fd 656 qtype = find_alternate_member_qtype(value)
dd883c6f 657 assert qtype
811d04fd
EB
658 if qtype in types_seen:
659 raise QAPIExprError(expr_info,
ab916fad 660 "Alternate '%s' member '%s' can't "
811d04fd
EB
661 "be distinguished from member '%s'"
662 % (name, key, types_seen[qtype]))
663 types_seen[qtype] = key
b86b05ed 664
437db254 665
cf393590
EB
666def check_enum(expr, expr_info):
667 name = expr['enum']
668 members = expr.get('data')
351d36e4 669 prefix = expr.get('prefix')
437db254 670 values = {'MAX': '(automatic)'}
cf393590
EB
671
672 if not isinstance(members, list):
673 raise QAPIExprError(expr_info,
674 "Enum '%s' requires an array for 'data'" % name)
351d36e4
DB
675 if prefix is not None and not isinstance(prefix, str):
676 raise QAPIExprError(expr_info,
677 "Enum '%s' requires a string for 'prefix'" % name)
cf393590 678 for member in members:
437db254 679 check_name(expr_info, "Member of enum '%s'" % name, member,
c9e0a798 680 enum_member=True)
fa6068a1 681 key = camel_to_upper(member)
cf393590
EB
682 if key in values:
683 raise QAPIExprError(expr_info,
684 "Enum '%s' member '%s' clashes with '%s'"
685 % (name, member, values[key]))
686 values[key] = member
687
437db254 688
dd883c6f 689def check_struct(expr, expr_info):
fd41dd4e 690 name = expr['struct']
dd883c6f
EB
691 members = expr['data']
692
fd41dd4e 693 check_type(expr_info, "'data' for struct '%s'" % name, members,
c9e0a798 694 allow_dict=True, allow_optional=True)
fd41dd4e 695 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
dd883c6f 696 allow_metas=['struct'])
ff55d72e
EB
697 if expr.get('base'):
698 check_member_clash(expr_info, expr['base'], expr['data'])
dd883c6f 699
437db254 700
0545f6b8
EB
701def check_keys(expr_elem, meta, required, optional=[]):
702 expr = expr_elem['expr']
703 info = expr_elem['info']
704 name = expr[meta]
705 if not isinstance(name, str):
706 raise QAPIExprError(info,
707 "'%s' key must have a string value" % meta)
437db254 708 required = required + [meta]
0545f6b8 709 for (key, value) in expr.items():
437db254 710 if key not in required and key not in optional:
0545f6b8
EB
711 raise QAPIExprError(info,
712 "Unknown key '%s' in %s '%s'"
713 % (key, meta, name))
437db254 714 if (key == 'gen' or key == 'success-response') and value is not False:
2cbf0992
EB
715 raise QAPIExprError(info,
716 "'%s' of %s '%s' should only use false value"
717 % (key, meta, name))
0545f6b8 718 for key in required:
437db254 719 if key not in expr:
0545f6b8
EB
720 raise QAPIExprError(info,
721 "Key '%s' is missing from %s '%s'"
722 % (key, meta, name))
723
437db254 724
4d076d67 725def check_exprs(exprs):
4dc2e690 726 global all_names
4dc2e690 727
4d076d67
MA
728 # Learn the types and check for valid expression keys
729 for builtin in builtin_types.keys():
730 all_names[builtin] = 'built-in'
731 for expr_elem in exprs:
732 expr = expr_elem['expr']
733 info = expr_elem['info']
437db254 734 if 'enum' in expr:
351d36e4 735 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
4d076d67 736 add_enum(expr['enum'], info, expr['data'])
437db254 737 elif 'union' in expr:
4d076d67
MA
738 check_keys(expr_elem, 'union', ['data'],
739 ['base', 'discriminator'])
740 add_union(expr, info)
437db254 741 elif 'alternate' in expr:
4d076d67
MA
742 check_keys(expr_elem, 'alternate', ['data'])
743 add_name(expr['alternate'], info, 'alternate')
437db254 744 elif 'struct' in expr:
4d076d67
MA
745 check_keys(expr_elem, 'struct', ['data'], ['base'])
746 add_struct(expr, info)
437db254 747 elif 'command' in expr:
4d076d67
MA
748 check_keys(expr_elem, 'command', [],
749 ['data', 'returns', 'gen', 'success-response'])
750 add_name(expr['command'], info, 'command')
437db254 751 elif 'event' in expr:
4d076d67
MA
752 check_keys(expr_elem, 'event', [], ['data'])
753 add_name(expr['event'], info, 'event')
754 else:
755 raise QAPIExprError(expr_elem['info'],
756 "Expression is missing metatype")
2caba36c 757
4d076d67
MA
758 # Try again for hidden UnionKind enum
759 for expr_elem in exprs:
760 expr = expr_elem['expr']
437db254 761 if 'union' in expr:
4d076d67
MA
762 if not discriminator_find_enum_define(expr):
763 add_enum('%sKind' % expr['union'], expr_elem['info'],
4dc2e690 764 implicit=True)
437db254 765 elif 'alternate' in expr:
4d076d67
MA
766 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
767 implicit=True)
768
769 # Validate that exprs make sense
770 for expr_elem in exprs:
771 expr = expr_elem['expr']
772 info = expr_elem['info']
268a1c5e 773
437db254 774 if 'enum' in expr:
4d076d67 775 check_enum(expr, info)
437db254 776 elif 'union' in expr:
4d076d67 777 check_union(expr, info)
437db254 778 elif 'alternate' in expr:
4d076d67 779 check_alternate(expr, info)
437db254 780 elif 'struct' in expr:
4d076d67 781 check_struct(expr, info)
437db254 782 elif 'command' in expr:
4d076d67 783 check_command(expr, info)
437db254 784 elif 'event' in expr:
4d076d67
MA
785 check_event(expr, info)
786 else:
787 assert False, 'unexpected meta type'
788
ac88219a
MA
789 return exprs
790
791
792#
793# Schema compiler frontend
794#
795
796class QAPISchemaEntity(object):
797 def __init__(self, name, info):
798 assert isinstance(name, str)
799 self.name = name
99df5289
EB
800 # For explicitly defined entities, info points to the (explicit)
801 # definition. For builtins (and their arrays), info is None.
802 # For implicitly defined entities, info points to a place that
803 # triggered the implicit definition (there may be more than one
804 # such place).
ac88219a
MA
805 self.info = info
806
f51d8c3d
MA
807 def c_name(self):
808 return c_name(self.name)
809
ac88219a
MA
810 def check(self, schema):
811 pass
812
49823c4b
EB
813 def is_implicit(self):
814 return not self.info
815
3f7dc21b
MA
816 def visit(self, visitor):
817 pass
818
819
820class QAPISchemaVisitor(object):
821 def visit_begin(self, schema):
822 pass
823
824 def visit_end(self):
825 pass
826
25a0d9c9
EB
827 def visit_needed(self, entity):
828 # Default to visiting everything
829 return True
830
3f7dc21b
MA
831 def visit_builtin_type(self, name, info, json_type):
832 pass
833
834 def visit_enum_type(self, name, info, values, prefix):
835 pass
836
837 def visit_array_type(self, name, info, element_type):
838 pass
839
840 def visit_object_type(self, name, info, base, members, variants):
841 pass
842
39a18158
MA
843 def visit_object_type_flat(self, name, info, members, variants):
844 pass
845
3f7dc21b
MA
846 def visit_alternate_type(self, name, info, variants):
847 pass
848
849 def visit_command(self, name, info, arg_type, ret_type,
850 gen, success_response):
851 pass
852
853 def visit_event(self, name, info, arg_type):
854 pass
855
ac88219a
MA
856
857class QAPISchemaType(QAPISchemaEntity):
f51d8c3d
MA
858 def c_type(self, is_param=False):
859 return c_name(self.name) + pointer_suffix
860
861 def c_null(self):
862 return 'NULL'
863
864 def json_type(self):
865 pass
866
867 def alternate_qtype(self):
868 json2qtype = {
869 'string': 'QTYPE_QSTRING',
870 'number': 'QTYPE_QFLOAT',
871 'int': 'QTYPE_QINT',
872 'boolean': 'QTYPE_QBOOL',
873 'object': 'QTYPE_QDICT'
874 }
875 return json2qtype.get(self.json_type())
ac88219a
MA
876
877
878class QAPISchemaBuiltinType(QAPISchemaType):
f51d8c3d 879 def __init__(self, name, json_type, c_type, c_null):
ac88219a 880 QAPISchemaType.__init__(self, name, None)
f51d8c3d
MA
881 assert not c_type or isinstance(c_type, str)
882 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
883 'value')
884 self._json_type_name = json_type
885 self._c_type_name = c_type
886 self._c_null_val = c_null
887
888 def c_name(self):
889 return self.name
890
891 def c_type(self, is_param=False):
892 if is_param and self.name == 'str':
893 return 'const ' + self._c_type_name
894 return self._c_type_name
895
896 def c_null(self):
897 return self._c_null_val
898
899 def json_type(self):
900 return self._json_type_name
ac88219a 901
3f7dc21b
MA
902 def visit(self, visitor):
903 visitor.visit_builtin_type(self.name, self.info, self.json_type())
904
ac88219a
MA
905
906class QAPISchemaEnumType(QAPISchemaType):
907 def __init__(self, name, info, values, prefix):
908 QAPISchemaType.__init__(self, name, info)
909 for v in values:
910 assert isinstance(v, str)
911 assert prefix is None or isinstance(prefix, str)
912 self.values = values
913 self.prefix = prefix
914
915 def check(self, schema):
916 assert len(set(self.values)) == len(self.values)
917
99df5289
EB
918 def is_implicit(self):
919 # See QAPISchema._make_implicit_enum_type()
8712fa53 920 return self.name.endswith('Kind')
99df5289 921
f51d8c3d
MA
922 def c_type(self, is_param=False):
923 return c_name(self.name)
924
925 def c_null(self):
926 return c_enum_const(self.name, (self.values + ['MAX'])[0],
927 self.prefix)
928
929 def json_type(self):
930 return 'string'
931
3f7dc21b
MA
932 def visit(self, visitor):
933 visitor.visit_enum_type(self.name, self.info,
934 self.values, self.prefix)
935
ac88219a
MA
936
937class QAPISchemaArrayType(QAPISchemaType):
938 def __init__(self, name, info, element_type):
939 QAPISchemaType.__init__(self, name, info)
940 assert isinstance(element_type, str)
941 self._element_type_name = element_type
942 self.element_type = None
943
944 def check(self, schema):
945 self.element_type = schema.lookup_type(self._element_type_name)
946 assert self.element_type
947
99df5289
EB
948 def is_implicit(self):
949 return True
950
f51d8c3d
MA
951 def json_type(self):
952 return 'array'
953
3f7dc21b
MA
954 def visit(self, visitor):
955 visitor.visit_array_type(self.name, self.info, self.element_type)
956
ac88219a
MA
957
958class QAPISchemaObjectType(QAPISchemaType):
959 def __init__(self, name, info, base, local_members, variants):
da34a9bd
EB
960 # struct has local_members, optional base, and no variants
961 # flat union has base, variants, and no local_members
962 # simple union has local_members, variants, and no base
ac88219a
MA
963 QAPISchemaType.__init__(self, name, info)
964 assert base is None or isinstance(base, str)
965 for m in local_members:
966 assert isinstance(m, QAPISchemaObjectTypeMember)
967 assert (variants is None or
968 isinstance(variants, QAPISchemaObjectTypeVariants))
969 self._base_name = base
970 self.base = None
971 self.local_members = local_members
972 self.variants = variants
973 self.members = None
974
975 def check(self, schema):
976 assert self.members is not False # not running in cycles
977 if self.members:
978 return
979 self.members = False # mark as being checked
23a4b2c6 980 seen = OrderedDict()
ac88219a
MA
981 if self._base_name:
982 self.base = schema.lookup_type(self._base_name)
983 assert isinstance(self.base, QAPISchemaObjectType)
984 assert not self.base.variants # not implemented
985 self.base.check(schema)
23a4b2c6 986 for m in self.base.members:
577de12d 987 m.check_clash(seen)
ac88219a 988 for m in self.local_members:
e564e2dd 989 m.check(schema)
577de12d 990 m.check_clash(seen)
ac88219a 991 if self.variants:
cdc5fa37 992 self.variants.check(schema, seen)
23a4b2c6 993 self.members = seen.values()
ac88219a 994
99df5289
EB
995 def is_implicit(self):
996 # See QAPISchema._make_implicit_object_type()
997 return self.name[0] == ':'
998
f51d8c3d 999 def c_name(self):
49823c4b 1000 assert not self.is_implicit()
f51d8c3d
MA
1001 return QAPISchemaType.c_name(self)
1002
1003 def c_type(self, is_param=False):
49823c4b 1004 assert not self.is_implicit()
f51d8c3d
MA
1005 return QAPISchemaType.c_type(self)
1006
1007 def json_type(self):
1008 return 'object'
1009
3f7dc21b
MA
1010 def visit(self, visitor):
1011 visitor.visit_object_type(self.name, self.info,
1012 self.base, self.local_members, self.variants)
39a18158
MA
1013 visitor.visit_object_type_flat(self.name, self.info,
1014 self.members, self.variants)
3f7dc21b 1015
ac88219a
MA
1016
1017class QAPISchemaObjectTypeMember(object):
1018 def __init__(self, name, typ, optional):
1019 assert isinstance(name, str)
1020 assert isinstance(typ, str)
1021 assert isinstance(optional, bool)
1022 self.name = name
1023 self._type_name = typ
1024 self.type = None
1025 self.optional = optional
1026
e564e2dd 1027 def check(self, schema):
ac88219a
MA
1028 self.type = schema.lookup_type(self._type_name)
1029 assert self.type
ac88219a 1030
577de12d
MA
1031 def check_clash(self, seen):
1032 # TODO change key of seen from QAPI name to C name
1033 assert self.name not in seen
1034 seen[self.name] = self
1035
ac88219a
MA
1036
1037class QAPISchemaObjectTypeVariants(object):
46292ba7
EB
1038 def __init__(self, tag_name, tag_member, variants):
1039 # Flat unions pass tag_name but not tag_member.
1040 # Simple unions and alternates pass tag_member but not tag_name.
1041 # After check(), tag_member is always set, and tag_name remains
1042 # a reliable witness of being used by a flat union.
1043 assert bool(tag_member) != bool(tag_name)
1044 assert (isinstance(tag_name, str) or
1045 isinstance(tag_member, QAPISchemaObjectTypeMember))
ac88219a
MA
1046 for v in variants:
1047 assert isinstance(v, QAPISchemaObjectTypeVariant)
1048 self.tag_name = tag_name
46292ba7 1049 self.tag_member = tag_member
ac88219a
MA
1050 self.variants = variants
1051
cdc5fa37 1052 def check(self, schema, seen):
da34a9bd 1053 if self.tag_name: # flat union
ac88219a 1054 self.tag_member = seen[self.tag_name]
da34a9bd
EB
1055 if seen:
1056 assert self.tag_member in seen.itervalues()
ac88219a
MA
1057 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1058 for v in self.variants:
cdc5fa37 1059 v.check(schema, self.tag_member.type)
ac88219a 1060
437db254 1061
ac88219a
MA
1062class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1063 def __init__(self, name, typ):
1064 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1065
cdc5fa37 1066 def check(self, schema, tag_type):
e564e2dd 1067 QAPISchemaObjectTypeMember.check(self, schema)
ac88219a
MA
1068 assert self.name in tag_type.values
1069
2b162ccb
MA
1070 # This function exists to support ugly simple union special cases
1071 # TODO get rid of them, and drop the function
1072 def simple_union_type(self):
49823c4b
EB
1073 if (self.type.is_implicit() and
1074 isinstance(self.type, QAPISchemaObjectType)):
2b162ccb
MA
1075 assert len(self.type.members) == 1
1076 assert not self.type.variants
1077 return self.type.members[0].type
1078 return None
1079
ac88219a
MA
1080
1081class QAPISchemaAlternateType(QAPISchemaType):
1082 def __init__(self, name, info, variants):
1083 QAPISchemaType.__init__(self, name, info)
1084 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1085 assert not variants.tag_name
1086 self.variants = variants
1087
1088 def check(self, schema):
e564e2dd 1089 self.variants.tag_member.check(schema)
cdc5fa37 1090 self.variants.check(schema, {})
ac88219a 1091
f51d8c3d
MA
1092 def json_type(self):
1093 return 'value'
1094
3f7dc21b
MA
1095 def visit(self, visitor):
1096 visitor.visit_alternate_type(self.name, self.info, self.variants)
1097
ac88219a
MA
1098
1099class QAPISchemaCommand(QAPISchemaEntity):
1100 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1101 QAPISchemaEntity.__init__(self, name, info)
1102 assert not arg_type or isinstance(arg_type, str)
1103 assert not ret_type or isinstance(ret_type, str)
1104 self._arg_type_name = arg_type
1105 self.arg_type = None
1106 self._ret_type_name = ret_type
1107 self.ret_type = None
1108 self.gen = gen
1109 self.success_response = success_response
1110
1111 def check(self, schema):
1112 if self._arg_type_name:
1113 self.arg_type = schema.lookup_type(self._arg_type_name)
1114 assert isinstance(self.arg_type, QAPISchemaObjectType)
1115 assert not self.arg_type.variants # not implemented
1116 if self._ret_type_name:
1117 self.ret_type = schema.lookup_type(self._ret_type_name)
1118 assert isinstance(self.ret_type, QAPISchemaType)
1119
3f7dc21b
MA
1120 def visit(self, visitor):
1121 visitor.visit_command(self.name, self.info,
1122 self.arg_type, self.ret_type,
1123 self.gen, self.success_response)
1124
ac88219a
MA
1125
1126class QAPISchemaEvent(QAPISchemaEntity):
1127 def __init__(self, name, info, arg_type):
1128 QAPISchemaEntity.__init__(self, name, info)
1129 assert not arg_type or isinstance(arg_type, str)
1130 self._arg_type_name = arg_type
1131 self.arg_type = None
1132
1133 def check(self, schema):
1134 if self._arg_type_name:
1135 self.arg_type = schema.lookup_type(self._arg_type_name)
1136 assert isinstance(self.arg_type, QAPISchemaObjectType)
1137 assert not self.arg_type.variants # not implemented
1138
3f7dc21b
MA
1139 def visit(self, visitor):
1140 visitor.visit_event(self.name, self.info, self.arg_type)
1141
ac88219a
MA
1142
1143class QAPISchema(object):
1144 def __init__(self, fname):
1145 try:
1146 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
7618b91f 1147 self._entity_dict = {}
99df5289 1148 self._predefining = True
7618b91f 1149 self._def_predefineds()
99df5289 1150 self._predefining = False
7618b91f
EB
1151 self._def_exprs()
1152 self.check()
ac88219a
MA
1153 except (QAPISchemaError, QAPIExprError), err:
1154 print >>sys.stderr, err
1155 exit(1)
ac88219a 1156
ac88219a 1157 def _def_entity(self, ent):
99df5289
EB
1158 # Only the predefined types are allowed to not have info
1159 assert ent.info or self._predefining
ac88219a
MA
1160 assert ent.name not in self._entity_dict
1161 self._entity_dict[ent.name] = ent
1162
1163 def lookup_entity(self, name, typ=None):
1164 ent = self._entity_dict.get(name)
1165 if typ and not isinstance(ent, typ):
1166 return None
1167 return ent
1168
1169 def lookup_type(self, name):
1170 return self.lookup_entity(name, QAPISchemaType)
1171
f51d8c3d
MA
1172 def _def_builtin_type(self, name, json_type, c_type, c_null):
1173 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1174 c_type, c_null))
9f08c8ec
EB
1175 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1176 # qapi-types.h from a single .c, all arrays of builtins must be
1177 # declared in the first file whether or not they are used. Nicer
1178 # would be to use lazy instantiation, while figuring out how to
1179 # avoid compilation issues with multiple qapi-types.h.
99df5289 1180 self._make_array_type(name, None)
ac88219a
MA
1181
1182 def _def_predefineds(self):
f51d8c3d
MA
1183 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1184 ('number', 'number', 'double', '0'),
1185 ('int', 'int', 'int64_t', '0'),
1186 ('int8', 'int', 'int8_t', '0'),
1187 ('int16', 'int', 'int16_t', '0'),
1188 ('int32', 'int', 'int32_t', '0'),
1189 ('int64', 'int', 'int64_t', '0'),
1190 ('uint8', 'int', 'uint8_t', '0'),
1191 ('uint16', 'int', 'uint16_t', '0'),
1192 ('uint32', 'int', 'uint32_t', '0'),
1193 ('uint64', 'int', 'uint64_t', '0'),
1194 ('size', 'int', 'uint64_t', '0'),
1195 ('bool', 'boolean', 'bool', 'false'),
28770e05 1196 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
f51d8c3d 1197 self._def_builtin_type(*t)
39a18158
MA
1198 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1199 [], None)
1200 self._def_entity(self.the_empty_object_type)
ac88219a 1201
99df5289 1202 def _make_implicit_enum_type(self, name, info, values):
49823c4b 1203 name = name + 'Kind' # Use namespace reserved by add_name()
99df5289 1204 self._def_entity(QAPISchemaEnumType(name, info, values, None))
ac88219a
MA
1205 return name
1206
99df5289 1207 def _make_array_type(self, element_type, info):
255960dd 1208 name = element_type + 'List' # Use namespace reserved by add_name()
ac88219a 1209 if not self.lookup_type(name):
99df5289 1210 self._def_entity(QAPISchemaArrayType(name, info, element_type))
ac88219a
MA
1211 return name
1212
99df5289 1213 def _make_implicit_object_type(self, name, info, role, members):
ac88219a
MA
1214 if not members:
1215 return None
1216 name = ':obj-%s-%s' % (name, role)
1217 if not self.lookup_entity(name, QAPISchemaObjectType):
99df5289 1218 self._def_entity(QAPISchemaObjectType(name, info, None,
ac88219a
MA
1219 members, None))
1220 return name
1221
1222 def _def_enum_type(self, expr, info):
1223 name = expr['enum']
1224 data = expr['data']
1225 prefix = expr.get('prefix')
1226 self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
ac88219a 1227
99df5289 1228 def _make_member(self, name, typ, info):
ac88219a
MA
1229 optional = False
1230 if name.startswith('*'):
1231 name = name[1:]
1232 optional = True
1233 if isinstance(typ, list):
1234 assert len(typ) == 1
99df5289 1235 typ = self._make_array_type(typ[0], info)
ac88219a
MA
1236 return QAPISchemaObjectTypeMember(name, typ, optional)
1237
99df5289
EB
1238 def _make_members(self, data, info):
1239 return [self._make_member(key, value, info)
ac88219a
MA
1240 for (key, value) in data.iteritems()]
1241
1242 def _def_struct_type(self, expr, info):
1243 name = expr['struct']
1244 base = expr.get('base')
1245 data = expr['data']
1246 self._def_entity(QAPISchemaObjectType(name, info, base,
99df5289 1247 self._make_members(data, info),
ac88219a 1248 None))
ac88219a
MA
1249
1250 def _make_variant(self, case, typ):
1251 return QAPISchemaObjectTypeVariant(case, typ)
1252
99df5289 1253 def _make_simple_variant(self, case, typ, info):
ac88219a
MA
1254 if isinstance(typ, list):
1255 assert len(typ) == 1
99df5289
EB
1256 typ = self._make_array_type(typ[0], info)
1257 typ = self._make_implicit_object_type(
1258 typ, info, 'wrapper', [self._make_member('data', typ, info)])
ac88219a
MA
1259 return QAPISchemaObjectTypeVariant(case, typ)
1260
99df5289
EB
1261 def _make_implicit_tag(self, type_name, info, variants):
1262 typ = self._make_implicit_enum_type(type_name, info,
46292ba7
EB
1263 [v.name for v in variants])
1264 return QAPISchemaObjectTypeMember('type', typ, False)
ac88219a
MA
1265
1266 def _def_union_type(self, expr, info):
1267 name = expr['union']
1268 data = expr['data']
1269 base = expr.get('base')
1270 tag_name = expr.get('discriminator')
46292ba7 1271 tag_member = None
ac88219a
MA
1272 if tag_name:
1273 variants = [self._make_variant(key, value)
1274 for (key, value) in data.iteritems()]
da34a9bd 1275 members = []
ac88219a 1276 else:
99df5289 1277 variants = [self._make_simple_variant(key, value, info)
ac88219a 1278 for (key, value) in data.iteritems()]
99df5289 1279 tag_member = self._make_implicit_tag(name, info, variants)
da34a9bd 1280 members = [tag_member]
ac88219a 1281 self._def_entity(
da34a9bd 1282 QAPISchemaObjectType(name, info, base, members,
ac88219a 1283 QAPISchemaObjectTypeVariants(tag_name,
46292ba7 1284 tag_member,
ac88219a 1285 variants)))
ac88219a
MA
1286
1287 def _def_alternate_type(self, expr, info):
1288 name = expr['alternate']
1289 data = expr['data']
1290 variants = [self._make_variant(key, value)
1291 for (key, value) in data.iteritems()]
99df5289 1292 tag_member = self._make_implicit_tag(name, info, variants)
ac88219a
MA
1293 self._def_entity(
1294 QAPISchemaAlternateType(name, info,
1295 QAPISchemaObjectTypeVariants(None,
46292ba7 1296 tag_member,
ac88219a 1297 variants)))
ac88219a
MA
1298
1299 def _def_command(self, expr, info):
1300 name = expr['command']
1301 data = expr.get('data')
1302 rets = expr.get('returns')
1303 gen = expr.get('gen', True)
1304 success_response = expr.get('success-response', True)
1305 if isinstance(data, OrderedDict):
99df5289
EB
1306 data = self._make_implicit_object_type(
1307 name, info, 'arg', self._make_members(data, info))
ac88219a
MA
1308 if isinstance(rets, list):
1309 assert len(rets) == 1
99df5289 1310 rets = self._make_array_type(rets[0], info)
ac88219a
MA
1311 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1312 success_response))
1313
1314 def _def_event(self, expr, info):
1315 name = expr['event']
1316 data = expr.get('data')
1317 if isinstance(data, OrderedDict):
99df5289
EB
1318 data = self._make_implicit_object_type(
1319 name, info, 'arg', self._make_members(data, info))
ac88219a
MA
1320 self._def_entity(QAPISchemaEvent(name, info, data))
1321
1322 def _def_exprs(self):
1323 for expr_elem in self.exprs:
1324 expr = expr_elem['expr']
1325 info = expr_elem['info']
1326 if 'enum' in expr:
1327 self._def_enum_type(expr, info)
1328 elif 'struct' in expr:
1329 self._def_struct_type(expr, info)
1330 elif 'union' in expr:
1331 self._def_union_type(expr, info)
1332 elif 'alternate' in expr:
1333 self._def_alternate_type(expr, info)
1334 elif 'command' in expr:
1335 self._def_command(expr, info)
1336 elif 'event' in expr:
1337 self._def_event(expr, info)
1338 else:
1339 assert False
1340
1341 def check(self):
1342 for ent in self._entity_dict.values():
1343 ent.check(self)
4d076d67 1344
3f7dc21b 1345 def visit(self, visitor):
25a0d9c9
EB
1346 visitor.visit_begin(self)
1347 for (name, entity) in sorted(self._entity_dict.items()):
1348 if visitor.visit_needed(entity):
1349 entity.visit(visitor)
3f7dc21b
MA
1350 visitor.visit_end()
1351
b86b05ed 1352
00e4b285
MA
1353#
1354# Code generation helpers
1355#
1356
0f923be2
MR
1357def camel_case(name):
1358 new_name = ''
1359 first = True
1360 for ch in name:
1361 if ch in ['_', '-']:
1362 first = True
1363 elif first:
1364 new_name += ch.upper()
1365 first = False
1366 else:
1367 new_name += ch.lower()
1368 return new_name
1369
437db254 1370
849bc538
MA
1371# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1372# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1373# ENUM24_Name -> ENUM24_NAME
1374def camel_to_upper(value):
1375 c_fun_str = c_name(value, False)
1376 if value.isupper():
1377 return c_fun_str
1378
1379 new_name = ''
1380 l = len(c_fun_str)
1381 for i in range(l):
1382 c = c_fun_str[i]
1383 # When c is upper and no "_" appears before, do more checks
1384 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
437db254
EB
1385 if i < l - 1 and c_fun_str[i + 1].islower():
1386 new_name += '_'
1387 elif c_fun_str[i - 1].isdigit():
849bc538
MA
1388 new_name += '_'
1389 new_name += c
1390 return new_name.lstrip('_').upper()
1391
437db254 1392
351d36e4
DB
1393def c_enum_const(type_name, const_name, prefix=None):
1394 if prefix is not None:
1395 type_name = prefix
849bc538
MA
1396 return camel_to_upper(type_name + '_' + const_name)
1397
18df515e 1398c_name_trans = string.maketrans('.-', '__')
47299262 1399
437db254 1400
c6405b54
EB
1401# Map @name to a valid C identifier.
1402# If @protect, avoid returning certain ticklish identifiers (like
1403# C keywords) by prepending "q_".
1404#
1405# Used for converting 'name' from a 'name':'type' qapi definition
1406# into a generated struct member, as well as converting type names
1407# into substrings of a generated C function name.
1408# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1409# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
18df515e 1410def c_name(name, protect=True):
427a1a2c
BS
1411 # ANSI X3J11/88-090, 3.1.1
1412 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
437db254
EB
1413 'default', 'do', 'double', 'else', 'enum', 'extern',
1414 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1415 'return', 'short', 'signed', 'sizeof', 'static',
1416 'struct', 'switch', 'typedef', 'union', 'unsigned',
1417 'void', 'volatile', 'while'])
427a1a2c
BS
1418 # ISO/IEC 9899:1999, 6.4.1
1419 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1420 # ISO/IEC 9899:2011, 6.4.1
437db254
EB
1421 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1422 '_Noreturn', '_Static_assert', '_Thread_local'])
427a1a2c
BS
1423 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1424 # excluding _.*
1425 gcc_words = set(['asm', 'typeof'])
6f88009e
TS
1426 # C++ ISO/IEC 14882:2003 2.11
1427 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1428 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1429 'namespace', 'new', 'operator', 'private', 'protected',
1430 'public', 'reinterpret_cast', 'static_cast', 'template',
1431 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1432 'using', 'virtual', 'wchar_t',
1433 # alternative representations
1434 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1435 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1057725f 1436 # namespace pollution:
8592a545 1437 polluted_words = set(['unix', 'errno'])
437db254
EB
1438 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1439 | cpp_words | polluted_words):
427a1a2c 1440 return "q_" + name
18df515e 1441 return name.translate(c_name_trans)
0f923be2 1442
05dfb26c 1443eatspace = '\033EATSPACE.'
d5573446 1444pointer_suffix = ' *' + eatspace
05dfb26c 1445
437db254 1446
0f923be2
MR
1447def genindent(count):
1448 ret = ""
437db254 1449 for _ in range(count):
0f923be2
MR
1450 ret += " "
1451 return ret
1452
1453indent_level = 0
1454
437db254 1455
0f923be2
MR
1456def push_indent(indent_amount=4):
1457 global indent_level
1458 indent_level += indent_amount
1459
437db254 1460
0f923be2
MR
1461def pop_indent(indent_amount=4):
1462 global indent_level
1463 indent_level -= indent_amount
1464
437db254 1465
77e703b8
MA
1466# Generate @code with @kwds interpolated.
1467# Obey indent_level, and strip eatspace.
0f923be2 1468def cgen(code, **kwds):
77e703b8
MA
1469 raw = code % kwds
1470 if indent_level:
1471 indent = genindent(indent_level)
2752e5be
MA
1472 # re.subn() lacks flags support before Python 2.7, use re.compile()
1473 raw = re.subn(re.compile("^.", re.MULTILINE),
1474 indent + r'\g<0>', raw)
77e703b8
MA
1475 raw = raw[0]
1476 return re.sub(re.escape(eatspace) + ' *', '', raw)
0f923be2 1477
437db254 1478
0f923be2 1479def mcgen(code, **kwds):
77e703b8
MA
1480 if code[0] == '\n':
1481 code = code[1:]
1482 return cgen(code, **kwds)
0f923be2 1483
0f923be2
MR
1484
1485def guardname(filename):
00dfc3b2 1486 return c_name(filename, protect=False).upper()
c0afa9c5 1487
437db254 1488
c0afa9c5
MR
1489def guardstart(name):
1490 return mcgen('''
1491
1492#ifndef %(name)s
1493#define %(name)s
1494
1495''',
1496 name=guardname(name))
1497
437db254 1498
c0afa9c5
MR
1499def guardend(name):
1500 return mcgen('''
1501
1502#endif /* %(name)s */
1503
1504''',
1505 name=guardname(name))
2114f5a9 1506
437db254 1507
e98859a9 1508def gen_enum_lookup(name, values, prefix=None):
efd2eaa6
MA
1509 ret = mcgen('''
1510
e98859a9 1511const char *const %(c_name)s_lookup[] = {
efd2eaa6 1512''',
e98859a9 1513 c_name=c_name(name))
efd2eaa6
MA
1514 for value in values:
1515 index = c_enum_const(name, value, prefix)
1516 ret += mcgen('''
1517 [%(index)s] = "%(value)s",
1518''',
e98859a9 1519 index=index, value=value)
efd2eaa6
MA
1520
1521 max_index = c_enum_const(name, 'MAX', prefix)
1522 ret += mcgen('''
1523 [%(max_index)s] = NULL,
1524};
1525''',
e98859a9 1526 max_index=max_index)
efd2eaa6
MA
1527 return ret
1528
437db254 1529
e98859a9
MA
1530def gen_enum(name, values, prefix=None):
1531 # append automatically generated _MAX value
1532 enum_values = values + ['MAX']
efd2eaa6 1533
e98859a9 1534 ret = mcgen('''
efd2eaa6 1535
e98859a9 1536typedef enum %(c_name)s {
efd2eaa6 1537''',
e98859a9 1538 c_name=c_name(name))
efd2eaa6
MA
1539
1540 i = 0
1541 for value in enum_values:
e98859a9
MA
1542 ret += mcgen('''
1543 %(c_enum)s = %(i)d,
efd2eaa6 1544''',
e98859a9 1545 c_enum=c_enum_const(name, value, prefix),
efd2eaa6
MA
1546 i=i)
1547 i += 1
1548
e98859a9
MA
1549 ret += mcgen('''
1550} %(c_name)s;
efd2eaa6 1551''',
e98859a9
MA
1552 c_name=c_name(name))
1553
1554 ret += mcgen('''
efd2eaa6 1555
e98859a9
MA
1556extern const char *const %(c_name)s_lookup[];
1557''',
1558 c_name=c_name(name))
1559 return ret
efd2eaa6 1560
437db254 1561
03b4367a
MA
1562def gen_params(arg_type, extra):
1563 if not arg_type:
1564 return extra
1565 assert not arg_type.variants
1566 ret = ''
1567 sep = ''
1568 for memb in arg_type.members:
1569 ret += sep
1570 sep = ', '
1571 if memb.optional:
1572 ret += 'bool has_%s, ' % c_name(memb.name)
1573 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1574 if extra:
1575 ret += sep + extra
1576 return ret
1577
1f353344 1578
18bdbc3a
EB
1579def gen_err_check(label='out', skiperr=False):
1580 if skiperr:
1f353344
EB
1581 return ''
1582 return mcgen('''
18bdbc3a 1583 if (err) {
1f353344
EB
1584 goto %(label)s;
1585 }
1586''',
18bdbc3a 1587 label=label)
1f353344
EB
1588
1589
18bdbc3a 1590def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
82ca8e46 1591 ret = ''
18bdbc3a 1592 if skiperr:
82ca8e46 1593 errparg = 'NULL'
18bdbc3a
EB
1594 else:
1595 errparg = '&err'
82ca8e46
EB
1596
1597 for memb in members:
1598 if memb.optional:
1599 ret += mcgen('''
1600 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1601''',
1602 prefix=prefix, c_name=c_name(memb.name),
1603 name=memb.name, errp=errparg)
18bdbc3a 1604 ret += gen_err_check(skiperr=skiperr)
82ca8e46
EB
1605 ret += mcgen('''
1606 if (%(prefix)shas_%(c_name)s) {
1607''',
1608 prefix=prefix, c_name=c_name(memb.name))
1609 push_indent()
1610
1611 # Ugly: sometimes we need to cast away const
1612 if need_cast and memb.type.name == 'str':
1613 cast = '(char **)'
1614 else:
1615 cast = ''
1616
1617 ret += mcgen('''
1618 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1619''',
1620 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1621 c_name=c_name(memb.name), name=memb.name,
1622 errp=errparg)
18bdbc3a 1623 ret += gen_err_check(skiperr=skiperr)
82ca8e46
EB
1624
1625 if memb.optional:
1626 pop_indent()
1627 ret += mcgen('''
1628 }
1629''')
1630 return ret
1631
1632
00e4b285
MA
1633#
1634# Common command line parsing
1635#
1636
437db254
EB
1637
1638def parse_command_line(extra_options="", extra_long_options=[]):
2114f5a9
MA
1639
1640 try:
1641 opts, args = getopt.gnu_getopt(sys.argv[1:],
16d80f61 1642 "chp:o:" + extra_options,
2114f5a9 1643 ["source", "header", "prefix=",
16d80f61 1644 "output-dir="] + extra_long_options)
2114f5a9 1645 except getopt.GetoptError, err:
b4540968 1646 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
2114f5a9
MA
1647 sys.exit(1)
1648
1649 output_dir = ""
1650 prefix = ""
1651 do_c = False
1652 do_h = False
1653 extra_opts = []
1654
1655 for oa in opts:
1656 o, a = oa
1657 if o in ("-p", "--prefix"):
1cf47a15
MA
1658 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1659 if match.end() != len(a):
1660 print >>sys.stderr, \
1661 "%s: 'funny character '%s' in argument of --prefix" \
1662 % (sys.argv[0], a[match.end()])
1663 sys.exit(1)
2114f5a9 1664 prefix = a
2114f5a9
MA
1665 elif o in ("-o", "--output-dir"):
1666 output_dir = a + "/"
1667 elif o in ("-c", "--source"):
1668 do_c = True
1669 elif o in ("-h", "--header"):
1670 do_h = True
1671 else:
1672 extra_opts.append(oa)
1673
1674 if not do_c and not do_h:
1675 do_c = True
1676 do_h = True
1677
16d80f61
MA
1678 if len(args) != 1:
1679 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
b4540968 1680 sys.exit(1)
54414047 1681 fname = args[0]
b4540968 1682
54414047 1683 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
12f8e1b9 1684
00e4b285
MA
1685#
1686# Generate output files with boilerplate
1687#
1688
437db254 1689
12f8e1b9
MA
1690def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1691 c_comment, h_comment):
00dfc3b2 1692 guard = guardname(prefix + h_file)
12f8e1b9
MA
1693 c_file = output_dir + prefix + c_file
1694 h_file = output_dir + prefix + h_file
1695
c4f498fe
MA
1696 if output_dir:
1697 try:
1698 os.makedirs(output_dir)
1699 except os.error, e:
1700 if e.errno != errno.EEXIST:
1701 raise
12f8e1b9
MA
1702
1703 def maybe_open(really, name, opt):
1704 if really:
1705 return open(name, opt)
1706 else:
1707 import StringIO
1708 return StringIO.StringIO()
1709
1710 fdef = maybe_open(do_c, c_file, 'w')
1711 fdecl = maybe_open(do_h, h_file, 'w')
1712
1713 fdef.write(mcgen('''
1714/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1715%(comment)s
1716''',
437db254 1717 comment=c_comment))
12f8e1b9
MA
1718
1719 fdecl.write(mcgen('''
1720/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1721%(comment)s
1722#ifndef %(guard)s
1723#define %(guard)s
1724
1725''',
437db254 1726 comment=h_comment, guard=guard))
12f8e1b9
MA
1727
1728 return (fdef, fdecl)
1729
437db254 1730
12f8e1b9
MA
1731def close_output(fdef, fdecl):
1732 fdecl.write('''
1733#endif
1734''')
12f8e1b9 1735 fdecl.close()
12f8e1b9 1736 fdef.close()