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