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