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