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