]> git.proxmox.com Git - mirror_qemu.git/blame - scripts/qapi.py
qapi: Add alias for ErrorClass
[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
59a92fee
EB
356# Names must be letters, numbers, -, and _. They must start with letter,
357# except for downstream extensions which must start with __RFQDN_.
358# Dots are only valid in the downstream extension prefix.
359valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
360 '[a-zA-Z][a-zA-Z0-9_-]*$')
437db254
EB
361
362
363def check_name(expr_info, source, name, allow_optional=False,
364 enum_member=False):
c9e0a798
EB
365 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
59a92fee
EB
379 if enum_member and membername[0].isdigit():
380 membername = 'D' + membername
9fb081e0
EB
381 # Reserve the entire 'q_' namespace for c_name()
382 if not valid_name.match(membername) or \
383 c_name(membername, False).startswith('q_'):
c9e0a798
EB
384 raise QAPIExprError(expr_info,
385 "%s uses invalid name '%s'" % (source, name))
386
437db254
EB
387
388def add_name(name, info, meta, implicit=False):
00e4b285
MA
389 global all_names
390 check_name(info, "'%s'" % meta, name)
d90675fa
MA
391 # FIXME should reject names that differ only in '_' vs. '.'
392 # vs. '-', because they're liable to clash in generated C.
00e4b285
MA
393 if name in all_names:
394 raise QAPIExprError(info,
395 "%s '%s' is already defined"
396 % (all_names[name], name))
255960dd 397 if not implicit and (name.endswith('Kind') or name.endswith('List')):
00e4b285 398 raise QAPIExprError(info,
255960dd
EB
399 "%s '%s' should not end in '%s'"
400 % (meta, name, name[-4:]))
00e4b285
MA
401 all_names[name] = meta
402
437db254 403
00e4b285
MA
404def add_struct(definition, info):
405 global struct_types
406 name = definition['struct']
407 add_name(name, info, 'struct')
408 struct_types.append(definition)
409
437db254 410
00e4b285
MA
411def find_struct(name):
412 global struct_types
413 for struct in struct_types:
414 if struct['struct'] == name:
415 return struct
416 return None
417
437db254 418
00e4b285
MA
419def add_union(definition, info):
420 global union_types
421 name = definition['union']
422 add_name(name, info, 'union')
423 union_types.append(definition)
424
437db254 425
00e4b285
MA
426def find_union(name):
427 global union_types
428 for union in union_types:
429 if union['union'] == name:
430 return union
431 return None
432
437db254
EB
433
434def add_enum(name, info, enum_values=None, implicit=False):
00e4b285
MA
435 global enum_types
436 add_name(name, info, 'enum', implicit)
437 enum_types.append({"enum_name": name, "enum_values": enum_values})
438
437db254 439
00e4b285
MA
440def find_enum(name):
441 global enum_types
442 for enum in enum_types:
443 if enum['enum_name'] == name:
444 return enum
445 return None
446
437db254 447
00e4b285 448def is_enum(name):
437db254
EB
449 return find_enum(name) is not None
450
00e4b285 451
437db254
EB
452def check_type(expr_info, source, value, allow_array=False,
453 allow_dict=False, allow_optional=False,
454 allow_metas=[]):
dd883c6f 455 global all_names
dd883c6f
EB
456
457 if value is None:
458 return
459
dd883c6f
EB
460 # Check if array type for value is okay
461 if isinstance(value, list):
462 if not allow_array:
463 raise QAPIExprError(expr_info,
464 "%s cannot be an array" % source)
465 if len(value) != 1 or not isinstance(value[0], str):
466 raise QAPIExprError(expr_info,
467 "%s: array type must contain single type name"
468 % source)
469 value = value[0]
dd883c6f
EB
470
471 # Check if type name for value is okay
472 if isinstance(value, str):
437db254 473 if value not in all_names:
dd883c6f
EB
474 raise QAPIExprError(expr_info,
475 "%s uses unknown type '%s'"
eddf817b 476 % (source, value))
dd883c6f
EB
477 if not all_names[value] in allow_metas:
478 raise QAPIExprError(expr_info,
479 "%s cannot use %s type '%s'"
eddf817b 480 % (source, all_names[value], value))
dd883c6f
EB
481 return
482
dd883c6f
EB
483 if not allow_dict:
484 raise QAPIExprError(expr_info,
485 "%s should be a type name" % source)
c6b71e5a
MA
486
487 if not isinstance(value, OrderedDict):
488 raise QAPIExprError(expr_info,
489 "%s should be a dictionary or type name" % source)
490
491 # value is a dictionary, check that each member is okay
dd883c6f 492 for (key, arg) in value.items():
c9e0a798
EB
493 check_name(expr_info, "Member of %s" % source, key,
494 allow_optional=allow_optional)
5e59baf9 495 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
9fb081e0
EB
496 raise QAPIExprError(expr_info,
497 "Member of %s uses reserved name '%s'"
498 % (source, key))
6b5abc7d
EB
499 # Todo: allow dictionaries to represent default values of
500 # an optional argument.
dd883c6f 501 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
2d21291a 502 allow_array=True,
dd883c6f 503 allow_metas=['built-in', 'union', 'alternate', 'struct',
6b5abc7d 504 'enum'])
dd883c6f 505
437db254
EB
506
507def check_member_clash(expr_info, base_name, data, source=""):
ff55d72e
EB
508 base = find_struct(base_name)
509 assert base
510 base_members = base['data']
511 for key in data.keys():
512 if key.startswith('*'):
513 key = key[1:]
514 if key in base_members or "*" + key in base_members:
515 raise QAPIExprError(expr_info,
516 "Member name '%s'%s clashes with base '%s'"
517 % (key, source, base_name))
518 if base.get('base'):
519 check_member_clash(expr_info, base['base'], data, source)
520
437db254 521
dd883c6f
EB
522def check_command(expr, expr_info):
523 name = expr['command']
2cbf0992 524
dd883c6f 525 check_type(expr_info, "'data' for command '%s'" % name,
c9e0a798 526 expr.get('data'), allow_dict=True, allow_optional=True,
2d21291a 527 allow_metas=['struct'])
10d4d997
EB
528 returns_meta = ['union', 'struct']
529 if name in returns_whitelist:
530 returns_meta += ['built-in', 'alternate', 'enum']
dd883c6f 531 check_type(expr_info, "'returns' for command '%s'" % name,
9b090d42 532 expr.get('returns'), allow_array=True,
2d21291a 533 allow_optional=True, allow_metas=returns_meta)
dd883c6f 534
437db254 535
21cd70df 536def check_event(expr, expr_info):
4dc2e690
EB
537 global events
538 name = expr['event']
4dc2e690 539
4dc2e690 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']
04e0639d 551 values = {}
b86b05ed 552
811d04fd 553 # Two types of unions, determined by discriminator.
811d04fd
EB
554
555 # With no discriminator it is a simple union.
556 if discriminator is None:
b86b05ed 557 enum_define = None
437db254 558 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
44bd1276
EB
559 if base is not None:
560 raise QAPIExprError(expr_info,
811d04fd 561 "Simple union '%s' must not have a base"
44bd1276 562 % name)
b86b05ed
WX
563
564 # Else, it's a flat union.
565 else:
44bd1276 566 # The object must have a string member 'base'.
376863ef
EB
567 check_type(expr_info, "'base' for union '%s'" % name,
568 base, allow_metas=['struct'])
569 if not base:
b86b05ed 570 raise QAPIExprError(expr_info,
376863ef 571 "Flat union '%s' must have a base"
b86b05ed 572 % name)
44bd1276 573 base_fields = find_base_fields(base)
376863ef 574 assert base_fields
44bd1276 575
c9e0a798 576 # The value of member 'discriminator' must name a non-optional
fd41dd4e 577 # member of the base struct.
c9e0a798
EB
578 check_name(expr_info, "Discriminator of flat union '%s'" % name,
579 discriminator)
b86b05ed
WX
580 discriminator_type = base_fields.get(discriminator)
581 if not discriminator_type:
582 raise QAPIExprError(expr_info,
583 "Discriminator '%s' is not a member of base "
fd41dd4e 584 "struct '%s'"
b86b05ed
WX
585 % (discriminator, base))
586 enum_define = find_enum(discriminator_type)
437db254 587 allow_metas = ['struct']
5223070c
WX
588 # Do not allow string discriminator
589 if not enum_define:
590 raise QAPIExprError(expr_info,
591 "Discriminator '%s' must be of enumeration "
592 "type" % discriminator)
b86b05ed
WX
593
594 # Check every branch
595 for (key, value) in members.items():
c9e0a798
EB
596 check_name(expr_info, "Member of union '%s'" % name, key)
597
dd883c6f 598 # Each value must name a known type; furthermore, in flat unions,
ff55d72e 599 # branches must be a struct with no overlapping member names
dd883c6f 600 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
f9a14273 601 value, allow_array=not base, allow_metas=allow_metas)
ff55d72e
EB
602 if base:
603 branch_struct = find_struct(value)
604 assert branch_struct
605 check_member_clash(expr_info, base, branch_struct['data'],
606 " of branch '%s'" % key)
dd883c6f 607
44bd1276 608 # If the discriminator names an enum type, then all members
61a94661 609 # of 'data' must also be members of the enum type.
44bd1276 610 if enum_define:
437db254 611 if key not in enum_define['enum_values']:
44bd1276
EB
612 raise QAPIExprError(expr_info,
613 "Discriminator value '%s' is not found in "
614 "enum '%s'" %
615 (key, enum_define["enum_name"]))
616
617 # Otherwise, check for conflicts in the generated enum
618 else:
fa6068a1 619 c_key = camel_to_upper(key)
44bd1276
EB
620 if c_key in values:
621 raise QAPIExprError(expr_info,
622 "Union '%s' member '%s' clashes with '%s'"
623 % (name, key, values[c_key]))
624 values[c_key] = key
625
437db254 626
811d04fd 627def check_alternate(expr, expr_info):
ab916fad 628 name = expr['alternate']
811d04fd 629 members = expr['data']
04e0639d 630 values = {}
811d04fd
EB
631 types_seen = {}
632
811d04fd
EB
633 # Check every branch
634 for (key, value) in members.items():
c9e0a798
EB
635 check_name(expr_info, "Member of alternate '%s'" % name, key)
636
811d04fd 637 # Check for conflicts in the generated enum
fa6068a1 638 c_key = camel_to_upper(key)
811d04fd
EB
639 if c_key in values:
640 raise QAPIExprError(expr_info,
ab916fad
EB
641 "Alternate '%s' member '%s' clashes with '%s'"
642 % (name, key, values[c_key]))
811d04fd 643 values[c_key] = key
44bd1276 644
811d04fd 645 # Ensure alternates have no type conflicts.
dd883c6f
EB
646 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
647 value,
648 allow_metas=['built-in', 'union', 'struct', 'enum'])
811d04fd 649 qtype = find_alternate_member_qtype(value)
dd883c6f 650 assert qtype
811d04fd
EB
651 if qtype in types_seen:
652 raise QAPIExprError(expr_info,
ab916fad 653 "Alternate '%s' member '%s' can't "
811d04fd
EB
654 "be distinguished from member '%s'"
655 % (name, key, types_seen[qtype]))
656 types_seen[qtype] = key
b86b05ed 657
437db254 658
cf393590
EB
659def check_enum(expr, expr_info):
660 name = expr['enum']
661 members = expr.get('data')
351d36e4 662 prefix = expr.get('prefix')
04e0639d 663 values = {}
cf393590
EB
664
665 if not isinstance(members, list):
666 raise QAPIExprError(expr_info,
667 "Enum '%s' requires an array for 'data'" % name)
351d36e4
DB
668 if prefix is not None and not isinstance(prefix, str):
669 raise QAPIExprError(expr_info,
670 "Enum '%s' requires a string for 'prefix'" % name)
cf393590 671 for member in members:
437db254 672 check_name(expr_info, "Member of enum '%s'" % name, member,
c9e0a798 673 enum_member=True)
fa6068a1 674 key = camel_to_upper(member)
cf393590
EB
675 if key in values:
676 raise QAPIExprError(expr_info,
677 "Enum '%s' member '%s' clashes with '%s'"
678 % (name, member, values[key]))
679 values[key] = member
680
437db254 681
dd883c6f 682def check_struct(expr, expr_info):
fd41dd4e 683 name = expr['struct']
dd883c6f
EB
684 members = expr['data']
685
fd41dd4e 686 check_type(expr_info, "'data' for struct '%s'" % name, members,
c9e0a798 687 allow_dict=True, allow_optional=True)
fd41dd4e 688 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
dd883c6f 689 allow_metas=['struct'])
ff55d72e
EB
690 if expr.get('base'):
691 check_member_clash(expr_info, expr['base'], expr['data'])
dd883c6f 692
437db254 693
0545f6b8
EB
694def check_keys(expr_elem, meta, required, optional=[]):
695 expr = expr_elem['expr']
696 info = expr_elem['info']
697 name = expr[meta]
698 if not isinstance(name, str):
699 raise QAPIExprError(info,
700 "'%s' key must have a string value" % meta)
437db254 701 required = required + [meta]
0545f6b8 702 for (key, value) in expr.items():
437db254 703 if key not in required and key not in optional:
0545f6b8
EB
704 raise QAPIExprError(info,
705 "Unknown key '%s' in %s '%s'"
706 % (key, meta, name))
437db254 707 if (key == 'gen' or key == 'success-response') and value is not False:
2cbf0992
EB
708 raise QAPIExprError(info,
709 "'%s' of %s '%s' should only use false value"
710 % (key, meta, name))
0545f6b8 711 for key in required:
437db254 712 if key not in expr:
0545f6b8
EB
713 raise QAPIExprError(info,
714 "Key '%s' is missing from %s '%s'"
715 % (key, meta, name))
716
437db254 717
4d076d67 718def check_exprs(exprs):
4dc2e690 719 global all_names
4dc2e690 720
4d076d67
MA
721 # Learn the types and check for valid expression keys
722 for builtin in builtin_types.keys():
723 all_names[builtin] = 'built-in'
724 for expr_elem in exprs:
725 expr = expr_elem['expr']
726 info = expr_elem['info']
437db254 727 if 'enum' in expr:
351d36e4 728 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
4d076d67 729 add_enum(expr['enum'], info, expr['data'])
437db254 730 elif 'union' in expr:
4d076d67
MA
731 check_keys(expr_elem, 'union', ['data'],
732 ['base', 'discriminator'])
733 add_union(expr, info)
437db254 734 elif 'alternate' in expr:
4d076d67
MA
735 check_keys(expr_elem, 'alternate', ['data'])
736 add_name(expr['alternate'], info, 'alternate')
437db254 737 elif 'struct' in expr:
4d076d67
MA
738 check_keys(expr_elem, 'struct', ['data'], ['base'])
739 add_struct(expr, info)
437db254 740 elif 'command' in expr:
4d076d67
MA
741 check_keys(expr_elem, 'command', [],
742 ['data', 'returns', 'gen', 'success-response'])
743 add_name(expr['command'], info, 'command')
437db254 744 elif 'event' in expr:
4d076d67
MA
745 check_keys(expr_elem, 'event', [], ['data'])
746 add_name(expr['event'], info, 'event')
747 else:
748 raise QAPIExprError(expr_elem['info'],
749 "Expression is missing metatype")
2caba36c 750
4d076d67
MA
751 # Try again for hidden UnionKind enum
752 for expr_elem in exprs:
753 expr = expr_elem['expr']
437db254 754 if 'union' in expr:
4d076d67
MA
755 if not discriminator_find_enum_define(expr):
756 add_enum('%sKind' % expr['union'], expr_elem['info'],
4dc2e690 757 implicit=True)
437db254 758 elif 'alternate' in expr:
4d076d67
MA
759 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
760 implicit=True)
761
762 # Validate that exprs make sense
763 for expr_elem in exprs:
764 expr = expr_elem['expr']
765 info = expr_elem['info']
268a1c5e 766
437db254 767 if 'enum' in expr:
4d076d67 768 check_enum(expr, info)
437db254 769 elif 'union' in expr:
4d076d67 770 check_union(expr, info)
437db254 771 elif 'alternate' in expr:
4d076d67 772 check_alternate(expr, info)
437db254 773 elif 'struct' in expr:
4d076d67 774 check_struct(expr, info)
437db254 775 elif 'command' in expr:
4d076d67 776 check_command(expr, info)
437db254 777 elif 'event' in expr:
4d076d67
MA
778 check_event(expr, info)
779 else:
780 assert False, 'unexpected meta type'
781
ac88219a
MA
782 return exprs
783
784
785#
786# Schema compiler frontend
787#
788
789class QAPISchemaEntity(object):
790 def __init__(self, name, info):
791 assert isinstance(name, str)
792 self.name = name
99df5289
EB
793 # For explicitly defined entities, info points to the (explicit)
794 # definition. For builtins (and their arrays), info is None.
795 # For implicitly defined entities, info points to a place that
796 # triggered the implicit definition (there may be more than one
797 # such place).
ac88219a
MA
798 self.info = info
799
f51d8c3d
MA
800 def c_name(self):
801 return c_name(self.name)
802
ac88219a
MA
803 def check(self, schema):
804 pass
805
49823c4b
EB
806 def is_implicit(self):
807 return not self.info
808
3f7dc21b
MA
809 def visit(self, visitor):
810 pass
811
812
813class QAPISchemaVisitor(object):
814 def visit_begin(self, schema):
815 pass
816
817 def visit_end(self):
818 pass
819
25a0d9c9
EB
820 def visit_needed(self, entity):
821 # Default to visiting everything
822 return True
823
3f7dc21b
MA
824 def visit_builtin_type(self, name, info, json_type):
825 pass
826
827 def visit_enum_type(self, name, info, values, prefix):
828 pass
829
830 def visit_array_type(self, name, info, element_type):
831 pass
832
833 def visit_object_type(self, name, info, base, members, variants):
834 pass
835
39a18158
MA
836 def visit_object_type_flat(self, name, info, members, variants):
837 pass
838
3f7dc21b
MA
839 def visit_alternate_type(self, name, info, variants):
840 pass
841
842 def visit_command(self, name, info, arg_type, ret_type,
843 gen, success_response):
844 pass
845
846 def visit_event(self, name, info, arg_type):
847 pass
848
ac88219a
MA
849
850class QAPISchemaType(QAPISchemaEntity):
f51d8c3d
MA
851 def c_type(self, is_param=False):
852 return c_name(self.name) + pointer_suffix
853
854 def c_null(self):
855 return 'NULL'
856
857 def json_type(self):
858 pass
859
860 def alternate_qtype(self):
861 json2qtype = {
862 'string': 'QTYPE_QSTRING',
863 'number': 'QTYPE_QFLOAT',
864 'int': 'QTYPE_QINT',
865 'boolean': 'QTYPE_QBOOL',
866 'object': 'QTYPE_QDICT'
867 }
868 return json2qtype.get(self.json_type())
ac88219a
MA
869
870
871class QAPISchemaBuiltinType(QAPISchemaType):
f51d8c3d 872 def __init__(self, name, json_type, c_type, c_null):
ac88219a 873 QAPISchemaType.__init__(self, name, None)
f51d8c3d
MA
874 assert not c_type or isinstance(c_type, str)
875 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
876 'value')
877 self._json_type_name = json_type
878 self._c_type_name = c_type
879 self._c_null_val = c_null
880
881 def c_name(self):
882 return self.name
883
884 def c_type(self, is_param=False):
885 if is_param and self.name == 'str':
886 return 'const ' + self._c_type_name
887 return self._c_type_name
888
889 def c_null(self):
890 return self._c_null_val
891
892 def json_type(self):
893 return self._json_type_name
ac88219a 894
3f7dc21b
MA
895 def visit(self, visitor):
896 visitor.visit_builtin_type(self.name, self.info, self.json_type())
897
ac88219a
MA
898
899class QAPISchemaEnumType(QAPISchemaType):
900 def __init__(self, name, info, values, prefix):
901 QAPISchemaType.__init__(self, name, info)
902 for v in values:
903 assert isinstance(v, str)
904 assert prefix is None or isinstance(prefix, str)
905 self.values = values
906 self.prefix = prefix
907
908 def check(self, schema):
909 assert len(set(self.values)) == len(self.values)
910
99df5289
EB
911 def is_implicit(self):
912 # See QAPISchema._make_implicit_enum_type()
8712fa53 913 return self.name.endswith('Kind')
99df5289 914
f51d8c3d
MA
915 def c_type(self, is_param=False):
916 return c_name(self.name)
917
918 def c_null(self):
7fb1cf16 919 return c_enum_const(self.name, (self.values + ['_MAX'])[0],
f51d8c3d
MA
920 self.prefix)
921
922 def json_type(self):
923 return 'string'
924
3f7dc21b
MA
925 def visit(self, visitor):
926 visitor.visit_enum_type(self.name, self.info,
927 self.values, self.prefix)
928
ac88219a
MA
929
930class QAPISchemaArrayType(QAPISchemaType):
931 def __init__(self, name, info, element_type):
932 QAPISchemaType.__init__(self, name, info)
933 assert isinstance(element_type, str)
934 self._element_type_name = element_type
935 self.element_type = None
936
937 def check(self, schema):
938 self.element_type = schema.lookup_type(self._element_type_name)
939 assert self.element_type
940
99df5289
EB
941 def is_implicit(self):
942 return True
943
f51d8c3d
MA
944 def json_type(self):
945 return 'array'
946
3f7dc21b
MA
947 def visit(self, visitor):
948 visitor.visit_array_type(self.name, self.info, self.element_type)
949
ac88219a
MA
950
951class QAPISchemaObjectType(QAPISchemaType):
952 def __init__(self, name, info, base, local_members, variants):
da34a9bd
EB
953 # struct has local_members, optional base, and no variants
954 # flat union has base, variants, and no local_members
955 # simple union has local_members, variants, and no base
ac88219a
MA
956 QAPISchemaType.__init__(self, name, info)
957 assert base is None or isinstance(base, str)
958 for m in local_members:
959 assert isinstance(m, QAPISchemaObjectTypeMember)
88d4ef8b
EB
960 m.set_owner(name)
961 if variants is not None:
962 assert isinstance(variants, QAPISchemaObjectTypeVariants)
963 variants.set_owner(name)
ac88219a
MA
964 self._base_name = base
965 self.base = None
966 self.local_members = local_members
967 self.variants = variants
968 self.members = None
969
970 def check(self, schema):
971 assert self.members is not False # not running in cycles
972 if self.members:
973 return
974 self.members = False # mark as being checked
23a4b2c6 975 seen = OrderedDict()
ac88219a
MA
976 if self._base_name:
977 self.base = schema.lookup_type(self._base_name)
978 assert isinstance(self.base, QAPISchemaObjectType)
ac88219a 979 self.base.check(schema)
27b60ab9 980 self.base.check_clash(schema, self.info, seen)
ac88219a 981 for m in self.local_members:
e564e2dd 982 m.check(schema)
27b60ab9 983 m.check_clash(self.info, seen)
14ff8461 984 self.members = seen.values()
ac88219a 985 if self.variants:
cdc5fa37 986 self.variants.check(schema, seen)
14ff8461 987 assert self.variants.tag_member in self.members
27b60ab9 988 self.variants.check_clash(schema, self.info, seen)
ac88219a 989
27b60ab9
EB
990 # Check that the members of this type do not cause duplicate JSON fields,
991 # and update seen to track the members seen so far. Report any errors
992 # on behalf of info, which is not necessarily self.info
993 def check_clash(self, schema, info, seen):
c2183d2e
EB
994 assert not self.variants # not implemented
995 for m in self.members:
27b60ab9 996 m.check_clash(info, seen)
c2183d2e 997
99df5289
EB
998 def is_implicit(self):
999 # See QAPISchema._make_implicit_object_type()
1000 return self.name[0] == ':'
1001
f51d8c3d 1002 def c_name(self):
49823c4b 1003 assert not self.is_implicit()
f51d8c3d
MA
1004 return QAPISchemaType.c_name(self)
1005
1006 def c_type(self, is_param=False):
49823c4b 1007 assert not self.is_implicit()
f51d8c3d
MA
1008 return QAPISchemaType.c_type(self)
1009
1010 def json_type(self):
1011 return 'object'
1012
3f7dc21b
MA
1013 def visit(self, visitor):
1014 visitor.visit_object_type(self.name, self.info,
1015 self.base, self.local_members, self.variants)
39a18158
MA
1016 visitor.visit_object_type_flat(self.name, self.info,
1017 self.members, self.variants)
3f7dc21b 1018
ac88219a
MA
1019
1020class QAPISchemaObjectTypeMember(object):
88d4ef8b
EB
1021 role = 'member'
1022
ac88219a
MA
1023 def __init__(self, name, typ, optional):
1024 assert isinstance(name, str)
1025 assert isinstance(typ, str)
1026 assert isinstance(optional, bool)
1027 self.name = name
1028 self._type_name = typ
1029 self.type = None
1030 self.optional = optional
88d4ef8b
EB
1031 self.owner = None
1032
1033 def set_owner(self, name):
1034 assert not self.owner
1035 self.owner = name
ac88219a 1036
e564e2dd 1037 def check(self, schema):
88d4ef8b 1038 assert self.owner
ac88219a
MA
1039 self.type = schema.lookup_type(self._type_name)
1040 assert self.type
ac88219a 1041
27b60ab9
EB
1042 def check_clash(self, info, seen):
1043 cname = c_name(self.name)
1044 if cname in seen:
1045 raise QAPIExprError(info,
1046 "%s collides with %s"
1047 % (self.describe(), seen[cname].describe()))
1048 seen[cname] = self
577de12d 1049
88d4ef8b
EB
1050 def _pretty_owner(self):
1051 owner = self.owner
1052 if owner.startswith(':obj-'):
1053 # See QAPISchema._make_implicit_object_type() - reverse the
1054 # mapping there to create a nice human-readable description
1055 owner = owner[5:]
1056 if owner.endswith('-arg'):
1057 return '(parameter of %s)' % owner[:-4]
1058 else:
1059 assert owner.endswith('-wrapper')
1060 # Unreachable and not implemented
1061 assert False
1062 return '(%s of %s)' % (self.role, owner)
1063
1064 def describe(self):
1065 return "'%s' %s" % (self.name, self._pretty_owner())
1066
ac88219a
MA
1067
1068class QAPISchemaObjectTypeVariants(object):
46292ba7
EB
1069 def __init__(self, tag_name, tag_member, variants):
1070 # Flat unions pass tag_name but not tag_member.
1071 # Simple unions and alternates pass tag_member but not tag_name.
1072 # After check(), tag_member is always set, and tag_name remains
1073 # a reliable witness of being used by a flat union.
1074 assert bool(tag_member) != bool(tag_name)
1075 assert (isinstance(tag_name, str) or
1076 isinstance(tag_member, QAPISchemaObjectTypeMember))
ac88219a
MA
1077 for v in variants:
1078 assert isinstance(v, QAPISchemaObjectTypeVariant)
1079 self.tag_name = tag_name
46292ba7 1080 self.tag_member = tag_member
ac88219a
MA
1081 self.variants = variants
1082
88d4ef8b
EB
1083 def set_owner(self, name):
1084 for v in self.variants:
1085 v.set_owner(name)
1086
cdc5fa37 1087 def check(self, schema, seen):
14ff8461 1088 if not self.tag_member: # flat union
27b60ab9
EB
1089 self.tag_member = seen[c_name(self.tag_name)]
1090 assert self.tag_name == self.tag_member.name
ac88219a
MA
1091 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1092 for v in self.variants:
10565ca9
EB
1093 v.check(schema)
1094 assert v.name in self.tag_member.type.values
b807a1e1
EB
1095 if isinstance(v.type, QAPISchemaObjectType):
1096 v.type.check(schema)
1097
27b60ab9 1098 def check_clash(self, schema, info, seen):
b807a1e1
EB
1099 for v in self.variants:
1100 # Reset seen map for each variant, since qapi names from one
1101 # branch do not affect another branch
b807a1e1 1102 assert isinstance(v.type, QAPISchemaObjectType)
27b60ab9 1103 v.type.check_clash(schema, info, dict(seen))
ac88219a 1104
437db254 1105
ac88219a 1106class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
88d4ef8b
EB
1107 role = 'branch'
1108
ac88219a
MA
1109 def __init__(self, name, typ):
1110 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1111
2b162ccb
MA
1112 # This function exists to support ugly simple union special cases
1113 # TODO get rid of them, and drop the function
1114 def simple_union_type(self):
49823c4b
EB
1115 if (self.type.is_implicit() and
1116 isinstance(self.type, QAPISchemaObjectType)):
2b162ccb
MA
1117 assert len(self.type.members) == 1
1118 assert not self.type.variants
1119 return self.type.members[0].type
1120 return None
1121
ac88219a
MA
1122
1123class QAPISchemaAlternateType(QAPISchemaType):
1124 def __init__(self, name, info, variants):
1125 QAPISchemaType.__init__(self, name, info)
1126 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1127 assert not variants.tag_name
88d4ef8b
EB
1128 variants.set_owner(name)
1129 variants.tag_member.set_owner(self.name)
ac88219a
MA
1130 self.variants = variants
1131
1132 def check(self, schema):
e564e2dd 1133 self.variants.tag_member.check(schema)
b807a1e1
EB
1134 # Not calling self.variants.check_clash(), because there's nothing
1135 # to clash with
cdc5fa37 1136 self.variants.check(schema, {})
ac88219a 1137
f51d8c3d
MA
1138 def json_type(self):
1139 return 'value'
1140
3f7dc21b
MA
1141 def visit(self, visitor):
1142 visitor.visit_alternate_type(self.name, self.info, self.variants)
1143
ac88219a
MA
1144
1145class QAPISchemaCommand(QAPISchemaEntity):
1146 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1147 QAPISchemaEntity.__init__(self, name, info)
1148 assert not arg_type or isinstance(arg_type, str)
1149 assert not ret_type or isinstance(ret_type, str)
1150 self._arg_type_name = arg_type
1151 self.arg_type = None
1152 self._ret_type_name = ret_type
1153 self.ret_type = None
1154 self.gen = gen
1155 self.success_response = success_response
1156
1157 def check(self, schema):
1158 if self._arg_type_name:
1159 self.arg_type = schema.lookup_type(self._arg_type_name)
1160 assert isinstance(self.arg_type, QAPISchemaObjectType)
1161 assert not self.arg_type.variants # not implemented
1162 if self._ret_type_name:
1163 self.ret_type = schema.lookup_type(self._ret_type_name)
1164 assert isinstance(self.ret_type, QAPISchemaType)
1165
3f7dc21b
MA
1166 def visit(self, visitor):
1167 visitor.visit_command(self.name, self.info,
1168 self.arg_type, self.ret_type,
1169 self.gen, self.success_response)
1170
ac88219a
MA
1171
1172class QAPISchemaEvent(QAPISchemaEntity):
1173 def __init__(self, name, info, arg_type):
1174 QAPISchemaEntity.__init__(self, name, info)
1175 assert not arg_type or isinstance(arg_type, str)
1176 self._arg_type_name = arg_type
1177 self.arg_type = None
1178
1179 def check(self, schema):
1180 if self._arg_type_name:
1181 self.arg_type = schema.lookup_type(self._arg_type_name)
1182 assert isinstance(self.arg_type, QAPISchemaObjectType)
1183 assert not self.arg_type.variants # not implemented
1184
3f7dc21b
MA
1185 def visit(self, visitor):
1186 visitor.visit_event(self.name, self.info, self.arg_type)
1187
ac88219a
MA
1188
1189class QAPISchema(object):
1190 def __init__(self, fname):
1191 try:
1192 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
7618b91f 1193 self._entity_dict = {}
99df5289 1194 self._predefining = True
7618b91f 1195 self._def_predefineds()
99df5289 1196 self._predefining = False
7618b91f
EB
1197 self._def_exprs()
1198 self.check()
ac88219a
MA
1199 except (QAPISchemaError, QAPIExprError), err:
1200 print >>sys.stderr, err
1201 exit(1)
ac88219a 1202
ac88219a 1203 def _def_entity(self, ent):
99df5289
EB
1204 # Only the predefined types are allowed to not have info
1205 assert ent.info or self._predefining
ac88219a
MA
1206 assert ent.name not in self._entity_dict
1207 self._entity_dict[ent.name] = ent
1208
1209 def lookup_entity(self, name, typ=None):
1210 ent = self._entity_dict.get(name)
1211 if typ and not isinstance(ent, typ):
1212 return None
1213 return ent
1214
1215 def lookup_type(self, name):
1216 return self.lookup_entity(name, QAPISchemaType)
1217
f51d8c3d
MA
1218 def _def_builtin_type(self, name, json_type, c_type, c_null):
1219 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1220 c_type, c_null))
9f08c8ec
EB
1221 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1222 # qapi-types.h from a single .c, all arrays of builtins must be
1223 # declared in the first file whether or not they are used. Nicer
1224 # would be to use lazy instantiation, while figuring out how to
1225 # avoid compilation issues with multiple qapi-types.h.
99df5289 1226 self._make_array_type(name, None)
ac88219a
MA
1227
1228 def _def_predefineds(self):
f51d8c3d
MA
1229 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1230 ('number', 'number', 'double', '0'),
1231 ('int', 'int', 'int64_t', '0'),
1232 ('int8', 'int', 'int8_t', '0'),
1233 ('int16', 'int', 'int16_t', '0'),
1234 ('int32', 'int', 'int32_t', '0'),
1235 ('int64', 'int', 'int64_t', '0'),
1236 ('uint8', 'int', 'uint8_t', '0'),
1237 ('uint16', 'int', 'uint16_t', '0'),
1238 ('uint32', 'int', 'uint32_t', '0'),
1239 ('uint64', 'int', 'uint64_t', '0'),
1240 ('size', 'int', 'uint64_t', '0'),
1241 ('bool', 'boolean', 'bool', 'false'),
28770e05 1242 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
f51d8c3d 1243 self._def_builtin_type(*t)
39a18158
MA
1244 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1245 [], None)
1246 self._def_entity(self.the_empty_object_type)
ac88219a 1247
99df5289 1248 def _make_implicit_enum_type(self, name, info, values):
49823c4b 1249 name = name + 'Kind' # Use namespace reserved by add_name()
99df5289 1250 self._def_entity(QAPISchemaEnumType(name, info, values, None))
ac88219a
MA
1251 return name
1252
99df5289 1253 def _make_array_type(self, element_type, info):
255960dd 1254 name = element_type + 'List' # Use namespace reserved by add_name()
ac88219a 1255 if not self.lookup_type(name):
99df5289 1256 self._def_entity(QAPISchemaArrayType(name, info, element_type))
ac88219a
MA
1257 return name
1258
99df5289 1259 def _make_implicit_object_type(self, name, info, role, members):
ac88219a
MA
1260 if not members:
1261 return None
88d4ef8b 1262 # See also QAPISchemaObjectTypeMember._pretty_owner()
ac88219a
MA
1263 name = ':obj-%s-%s' % (name, role)
1264 if not self.lookup_entity(name, QAPISchemaObjectType):
99df5289 1265 self._def_entity(QAPISchemaObjectType(name, info, None,
ac88219a
MA
1266 members, None))
1267 return name
1268
1269 def _def_enum_type(self, expr, info):
1270 name = expr['enum']
1271 data = expr['data']
1272 prefix = expr.get('prefix')
1273 self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
ac88219a 1274
99df5289 1275 def _make_member(self, name, typ, info):
ac88219a
MA
1276 optional = False
1277 if name.startswith('*'):
1278 name = name[1:]
1279 optional = True
1280 if isinstance(typ, list):
1281 assert len(typ) == 1
99df5289 1282 typ = self._make_array_type(typ[0], info)
ac88219a
MA
1283 return QAPISchemaObjectTypeMember(name, typ, optional)
1284
99df5289
EB
1285 def _make_members(self, data, info):
1286 return [self._make_member(key, value, info)
ac88219a
MA
1287 for (key, value) in data.iteritems()]
1288
1289 def _def_struct_type(self, expr, info):
1290 name = expr['struct']
1291 base = expr.get('base')
1292 data = expr['data']
1293 self._def_entity(QAPISchemaObjectType(name, info, base,
99df5289 1294 self._make_members(data, info),
ac88219a 1295 None))
ac88219a
MA
1296
1297 def _make_variant(self, case, typ):
1298 return QAPISchemaObjectTypeVariant(case, typ)
1299
99df5289 1300 def _make_simple_variant(self, case, typ, info):
ac88219a
MA
1301 if isinstance(typ, list):
1302 assert len(typ) == 1
99df5289
EB
1303 typ = self._make_array_type(typ[0], info)
1304 typ = self._make_implicit_object_type(
1305 typ, info, 'wrapper', [self._make_member('data', typ, info)])
ac88219a
MA
1306 return QAPISchemaObjectTypeVariant(case, typ)
1307
99df5289
EB
1308 def _make_implicit_tag(self, type_name, info, variants):
1309 typ = self._make_implicit_enum_type(type_name, info,
46292ba7
EB
1310 [v.name for v in variants])
1311 return QAPISchemaObjectTypeMember('type', typ, False)
ac88219a
MA
1312
1313 def _def_union_type(self, expr, info):
1314 name = expr['union']
1315 data = expr['data']
1316 base = expr.get('base')
1317 tag_name = expr.get('discriminator')
46292ba7 1318 tag_member = None
ac88219a
MA
1319 if tag_name:
1320 variants = [self._make_variant(key, value)
1321 for (key, value) in data.iteritems()]
da34a9bd 1322 members = []
ac88219a 1323 else:
99df5289 1324 variants = [self._make_simple_variant(key, value, info)
ac88219a 1325 for (key, value) in data.iteritems()]
99df5289 1326 tag_member = self._make_implicit_tag(name, info, variants)
da34a9bd 1327 members = [tag_member]
ac88219a 1328 self._def_entity(
da34a9bd 1329 QAPISchemaObjectType(name, info, base, members,
ac88219a 1330 QAPISchemaObjectTypeVariants(tag_name,
46292ba7 1331 tag_member,
ac88219a 1332 variants)))
ac88219a
MA
1333
1334 def _def_alternate_type(self, expr, info):
1335 name = expr['alternate']
1336 data = expr['data']
1337 variants = [self._make_variant(key, value)
1338 for (key, value) in data.iteritems()]
99df5289 1339 tag_member = self._make_implicit_tag(name, info, variants)
ac88219a
MA
1340 self._def_entity(
1341 QAPISchemaAlternateType(name, info,
1342 QAPISchemaObjectTypeVariants(None,
46292ba7 1343 tag_member,
ac88219a 1344 variants)))
ac88219a
MA
1345
1346 def _def_command(self, expr, info):
1347 name = expr['command']
1348 data = expr.get('data')
1349 rets = expr.get('returns')
1350 gen = expr.get('gen', True)
1351 success_response = expr.get('success-response', True)
1352 if isinstance(data, OrderedDict):
99df5289
EB
1353 data = self._make_implicit_object_type(
1354 name, info, 'arg', self._make_members(data, info))
ac88219a
MA
1355 if isinstance(rets, list):
1356 assert len(rets) == 1
99df5289 1357 rets = self._make_array_type(rets[0], info)
ac88219a
MA
1358 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1359 success_response))
1360
1361 def _def_event(self, expr, info):
1362 name = expr['event']
1363 data = expr.get('data')
1364 if isinstance(data, OrderedDict):
99df5289
EB
1365 data = self._make_implicit_object_type(
1366 name, info, 'arg', self._make_members(data, info))
ac88219a
MA
1367 self._def_entity(QAPISchemaEvent(name, info, data))
1368
1369 def _def_exprs(self):
1370 for expr_elem in self.exprs:
1371 expr = expr_elem['expr']
1372 info = expr_elem['info']
1373 if 'enum' in expr:
1374 self._def_enum_type(expr, info)
1375 elif 'struct' in expr:
1376 self._def_struct_type(expr, info)
1377 elif 'union' in expr:
1378 self._def_union_type(expr, info)
1379 elif 'alternate' in expr:
1380 self._def_alternate_type(expr, info)
1381 elif 'command' in expr:
1382 self._def_command(expr, info)
1383 elif 'event' in expr:
1384 self._def_event(expr, info)
1385 else:
1386 assert False
1387
1388 def check(self):
1389 for ent in self._entity_dict.values():
1390 ent.check(self)
4d076d67 1391
3f7dc21b 1392 def visit(self, visitor):
25a0d9c9
EB
1393 visitor.visit_begin(self)
1394 for (name, entity) in sorted(self._entity_dict.items()):
1395 if visitor.visit_needed(entity):
1396 entity.visit(visitor)
3f7dc21b
MA
1397 visitor.visit_end()
1398
b86b05ed 1399
00e4b285
MA
1400#
1401# Code generation helpers
1402#
1403
0f923be2
MR
1404def camel_case(name):
1405 new_name = ''
1406 first = True
1407 for ch in name:
1408 if ch in ['_', '-']:
1409 first = True
1410 elif first:
1411 new_name += ch.upper()
1412 first = False
1413 else:
1414 new_name += ch.lower()
1415 return new_name
1416
437db254 1417
849bc538
MA
1418# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1419# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1420# ENUM24_Name -> ENUM24_NAME
1421def camel_to_upper(value):
1422 c_fun_str = c_name(value, False)
1423 if value.isupper():
1424 return c_fun_str
1425
1426 new_name = ''
1427 l = len(c_fun_str)
1428 for i in range(l):
1429 c = c_fun_str[i]
1430 # When c is upper and no "_" appears before, do more checks
1431 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
437db254
EB
1432 if i < l - 1 and c_fun_str[i + 1].islower():
1433 new_name += '_'
1434 elif c_fun_str[i - 1].isdigit():
849bc538
MA
1435 new_name += '_'
1436 new_name += c
1437 return new_name.lstrip('_').upper()
1438
437db254 1439
351d36e4
DB
1440def c_enum_const(type_name, const_name, prefix=None):
1441 if prefix is not None:
1442 type_name = prefix
849bc538
MA
1443 return camel_to_upper(type_name + '_' + const_name)
1444
18df515e 1445c_name_trans = string.maketrans('.-', '__')
47299262 1446
437db254 1447
c6405b54
EB
1448# Map @name to a valid C identifier.
1449# If @protect, avoid returning certain ticklish identifiers (like
1450# C keywords) by prepending "q_".
1451#
1452# Used for converting 'name' from a 'name':'type' qapi definition
1453# into a generated struct member, as well as converting type names
1454# into substrings of a generated C function name.
1455# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1456# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
18df515e 1457def c_name(name, protect=True):
427a1a2c
BS
1458 # ANSI X3J11/88-090, 3.1.1
1459 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
437db254
EB
1460 'default', 'do', 'double', 'else', 'enum', 'extern',
1461 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1462 'return', 'short', 'signed', 'sizeof', 'static',
1463 'struct', 'switch', 'typedef', 'union', 'unsigned',
1464 'void', 'volatile', 'while'])
427a1a2c
BS
1465 # ISO/IEC 9899:1999, 6.4.1
1466 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1467 # ISO/IEC 9899:2011, 6.4.1
437db254
EB
1468 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1469 '_Noreturn', '_Static_assert', '_Thread_local'])
427a1a2c
BS
1470 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1471 # excluding _.*
1472 gcc_words = set(['asm', 'typeof'])
6f88009e
TS
1473 # C++ ISO/IEC 14882:2003 2.11
1474 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1475 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1476 'namespace', 'new', 'operator', 'private', 'protected',
1477 'public', 'reinterpret_cast', 'static_cast', 'template',
1478 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1479 'using', 'virtual', 'wchar_t',
1480 # alternative representations
1481 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1482 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1057725f 1483 # namespace pollution:
8592a545 1484 polluted_words = set(['unix', 'errno'])
c43567c1 1485 name = name.translate(c_name_trans)
437db254
EB
1486 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1487 | cpp_words | polluted_words):
427a1a2c 1488 return "q_" + name
c43567c1 1489 return name
0f923be2 1490
05dfb26c 1491eatspace = '\033EATSPACE.'
d5573446 1492pointer_suffix = ' *' + eatspace
05dfb26c 1493
437db254 1494
0f923be2
MR
1495def genindent(count):
1496 ret = ""
437db254 1497 for _ in range(count):
0f923be2
MR
1498 ret += " "
1499 return ret
1500
1501indent_level = 0
1502
437db254 1503
0f923be2
MR
1504def push_indent(indent_amount=4):
1505 global indent_level
1506 indent_level += indent_amount
1507
437db254 1508
0f923be2
MR
1509def pop_indent(indent_amount=4):
1510 global indent_level
1511 indent_level -= indent_amount
1512
437db254 1513
77e703b8
MA
1514# Generate @code with @kwds interpolated.
1515# Obey indent_level, and strip eatspace.
0f923be2 1516def cgen(code, **kwds):
77e703b8
MA
1517 raw = code % kwds
1518 if indent_level:
1519 indent = genindent(indent_level)
2752e5be
MA
1520 # re.subn() lacks flags support before Python 2.7, use re.compile()
1521 raw = re.subn(re.compile("^.", re.MULTILINE),
1522 indent + r'\g<0>', raw)
77e703b8
MA
1523 raw = raw[0]
1524 return re.sub(re.escape(eatspace) + ' *', '', raw)
0f923be2 1525
437db254 1526
0f923be2 1527def mcgen(code, **kwds):
77e703b8
MA
1528 if code[0] == '\n':
1529 code = code[1:]
1530 return cgen(code, **kwds)
0f923be2 1531
0f923be2
MR
1532
1533def guardname(filename):
00dfc3b2 1534 return c_name(filename, protect=False).upper()
c0afa9c5 1535
437db254 1536
c0afa9c5
MR
1537def guardstart(name):
1538 return mcgen('''
1539
1540#ifndef %(name)s
1541#define %(name)s
1542
1543''',
1544 name=guardname(name))
1545
437db254 1546
c0afa9c5
MR
1547def guardend(name):
1548 return mcgen('''
1549
1550#endif /* %(name)s */
1551
1552''',
1553 name=guardname(name))
2114f5a9 1554
437db254 1555
e98859a9 1556def gen_enum_lookup(name, values, prefix=None):
efd2eaa6
MA
1557 ret = mcgen('''
1558
e98859a9 1559const char *const %(c_name)s_lookup[] = {
efd2eaa6 1560''',
e98859a9 1561 c_name=c_name(name))
efd2eaa6
MA
1562 for value in values:
1563 index = c_enum_const(name, value, prefix)
1564 ret += mcgen('''
1565 [%(index)s] = "%(value)s",
1566''',
e98859a9 1567 index=index, value=value)
efd2eaa6 1568
7fb1cf16 1569 max_index = c_enum_const(name, '_MAX', prefix)
efd2eaa6
MA
1570 ret += mcgen('''
1571 [%(max_index)s] = NULL,
1572};
1573''',
e98859a9 1574 max_index=max_index)
efd2eaa6
MA
1575 return ret
1576
437db254 1577
e98859a9
MA
1578def gen_enum(name, values, prefix=None):
1579 # append automatically generated _MAX value
7fb1cf16 1580 enum_values = values + ['_MAX']
efd2eaa6 1581
e98859a9 1582 ret = mcgen('''
efd2eaa6 1583
e98859a9 1584typedef enum %(c_name)s {
efd2eaa6 1585''',
e98859a9 1586 c_name=c_name(name))
efd2eaa6
MA
1587
1588 i = 0
1589 for value in enum_values:
e98859a9
MA
1590 ret += mcgen('''
1591 %(c_enum)s = %(i)d,
efd2eaa6 1592''',
e98859a9 1593 c_enum=c_enum_const(name, value, prefix),
efd2eaa6
MA
1594 i=i)
1595 i += 1
1596
e98859a9
MA
1597 ret += mcgen('''
1598} %(c_name)s;
efd2eaa6 1599''',
e98859a9
MA
1600 c_name=c_name(name))
1601
1602 ret += mcgen('''
efd2eaa6 1603
e98859a9
MA
1604extern const char *const %(c_name)s_lookup[];
1605''',
1606 c_name=c_name(name))
1607 return ret
efd2eaa6 1608
437db254 1609
03b4367a
MA
1610def gen_params(arg_type, extra):
1611 if not arg_type:
1612 return extra
1613 assert not arg_type.variants
1614 ret = ''
1615 sep = ''
1616 for memb in arg_type.members:
1617 ret += sep
1618 sep = ', '
1619 if memb.optional:
1620 ret += 'bool has_%s, ' % c_name(memb.name)
1621 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1622 if extra:
1623 ret += sep + extra
1624 return ret
1625
1f353344 1626
18bdbc3a
EB
1627def gen_err_check(label='out', skiperr=False):
1628 if skiperr:
1f353344
EB
1629 return ''
1630 return mcgen('''
18bdbc3a 1631 if (err) {
1f353344
EB
1632 goto %(label)s;
1633 }
1634''',
18bdbc3a 1635 label=label)
1f353344
EB
1636
1637
18bdbc3a 1638def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
82ca8e46 1639 ret = ''
18bdbc3a 1640 if skiperr:
82ca8e46 1641 errparg = 'NULL'
18bdbc3a
EB
1642 else:
1643 errparg = '&err'
82ca8e46
EB
1644
1645 for memb in members:
1646 if memb.optional:
1647 ret += mcgen('''
1648 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1649''',
1650 prefix=prefix, c_name=c_name(memb.name),
1651 name=memb.name, errp=errparg)
18bdbc3a 1652 ret += gen_err_check(skiperr=skiperr)
82ca8e46
EB
1653 ret += mcgen('''
1654 if (%(prefix)shas_%(c_name)s) {
1655''',
1656 prefix=prefix, c_name=c_name(memb.name))
1657 push_indent()
1658
1659 # Ugly: sometimes we need to cast away const
1660 if need_cast and memb.type.name == 'str':
1661 cast = '(char **)'
1662 else:
1663 cast = ''
1664
1665 ret += mcgen('''
1666 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1667''',
1668 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1669 c_name=c_name(memb.name), name=memb.name,
1670 errp=errparg)
18bdbc3a 1671 ret += gen_err_check(skiperr=skiperr)
82ca8e46
EB
1672
1673 if memb.optional:
1674 pop_indent()
1675 ret += mcgen('''
1676 }
1677''')
1678 return ret
1679
1680
00e4b285
MA
1681#
1682# Common command line parsing
1683#
1684
437db254
EB
1685
1686def parse_command_line(extra_options="", extra_long_options=[]):
2114f5a9
MA
1687
1688 try:
1689 opts, args = getopt.gnu_getopt(sys.argv[1:],
16d80f61 1690 "chp:o:" + extra_options,
2114f5a9 1691 ["source", "header", "prefix=",
16d80f61 1692 "output-dir="] + extra_long_options)
2114f5a9 1693 except getopt.GetoptError, err:
b4540968 1694 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
2114f5a9
MA
1695 sys.exit(1)
1696
1697 output_dir = ""
1698 prefix = ""
1699 do_c = False
1700 do_h = False
1701 extra_opts = []
1702
1703 for oa in opts:
1704 o, a = oa
1705 if o in ("-p", "--prefix"):
1cf47a15
MA
1706 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1707 if match.end() != len(a):
1708 print >>sys.stderr, \
1709 "%s: 'funny character '%s' in argument of --prefix" \
1710 % (sys.argv[0], a[match.end()])
1711 sys.exit(1)
2114f5a9 1712 prefix = a
2114f5a9
MA
1713 elif o in ("-o", "--output-dir"):
1714 output_dir = a + "/"
1715 elif o in ("-c", "--source"):
1716 do_c = True
1717 elif o in ("-h", "--header"):
1718 do_h = True
1719 else:
1720 extra_opts.append(oa)
1721
1722 if not do_c and not do_h:
1723 do_c = True
1724 do_h = True
1725
16d80f61
MA
1726 if len(args) != 1:
1727 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
b4540968 1728 sys.exit(1)
54414047 1729 fname = args[0]
b4540968 1730
54414047 1731 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
12f8e1b9 1732
00e4b285
MA
1733#
1734# Generate output files with boilerplate
1735#
1736
437db254 1737
12f8e1b9
MA
1738def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1739 c_comment, h_comment):
00dfc3b2 1740 guard = guardname(prefix + h_file)
12f8e1b9
MA
1741 c_file = output_dir + prefix + c_file
1742 h_file = output_dir + prefix + h_file
1743
c4f498fe
MA
1744 if output_dir:
1745 try:
1746 os.makedirs(output_dir)
1747 except os.error, e:
1748 if e.errno != errno.EEXIST:
1749 raise
12f8e1b9
MA
1750
1751 def maybe_open(really, name, opt):
1752 if really:
1753 return open(name, opt)
1754 else:
1755 import StringIO
1756 return StringIO.StringIO()
1757
1758 fdef = maybe_open(do_c, c_file, 'w')
1759 fdecl = maybe_open(do_h, h_file, 'w')
1760
1761 fdef.write(mcgen('''
1762/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1763%(comment)s
1764''',
437db254 1765 comment=c_comment))
12f8e1b9
MA
1766
1767 fdecl.write(mcgen('''
1768/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1769%(comment)s
1770#ifndef %(guard)s
1771#define %(guard)s
1772
1773''',
437db254 1774 comment=h_comment, guard=guard))
12f8e1b9
MA
1775
1776 return (fdef, fdecl)
1777
437db254 1778
12f8e1b9
MA
1779def close_output(fdef, fdecl):
1780 fdecl.write('''
1781#endif
1782''')
12f8e1b9 1783 fdecl.close()
12f8e1b9 1784 fdef.close()