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