]> Git Repo - qemu.git/blame - scripts/qapi.py
Merge remote-tracking branch 'remotes/kraxel/tags/pull-ui-20160513-1' into staging
[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
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
437db254 615
811d04fd 616def check_alternate(expr, expr_info):
ab916fad 617 name = expr['alternate']
811d04fd 618 members = expr['data']
811d04fd
EB
619 types_seen = {}
620
02a57ae3
EB
621 # Check every branch; require at least two branches
622 if len(members) < 2:
623 raise QAPIExprError(expr_info,
624 "Alternate '%s' should have at least two branches "
625 "in 'data'" % name)
811d04fd 626 for (key, value) in members.items():
c9e0a798
EB
627 check_name(expr_info, "Member of alternate '%s'" % name, key)
628
811d04fd 629 # Ensure alternates have no type conflicts.
dd883c6f
EB
630 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
631 value,
632 allow_metas=['built-in', 'union', 'struct', 'enum'])
811d04fd 633 qtype = find_alternate_member_qtype(value)
46534309
EB
634 if not qtype:
635 raise QAPIExprError(expr_info,
636 "Alternate '%s' member '%s' cannot use "
637 "type '%s'" % (name, key, value))
811d04fd
EB
638 if qtype in types_seen:
639 raise QAPIExprError(expr_info,
ab916fad 640 "Alternate '%s' member '%s' can't "
811d04fd
EB
641 "be distinguished from member '%s'"
642 % (name, key, types_seen[qtype]))
643 types_seen[qtype] = key
b86b05ed 644
437db254 645
cf393590
EB
646def check_enum(expr, expr_info):
647 name = expr['enum']
648 members = expr.get('data')
351d36e4 649 prefix = expr.get('prefix')
cf393590
EB
650
651 if not isinstance(members, list):
652 raise QAPIExprError(expr_info,
653 "Enum '%s' requires an array for 'data'" % name)
351d36e4
DB
654 if prefix is not None and not isinstance(prefix, str):
655 raise QAPIExprError(expr_info,
656 "Enum '%s' requires a string for 'prefix'" % name)
cf393590 657 for member in members:
437db254 658 check_name(expr_info, "Member of enum '%s'" % name, member,
c9e0a798 659 enum_member=True)
cf393590 660
437db254 661
dd883c6f 662def check_struct(expr, expr_info):
fd41dd4e 663 name = expr['struct']
dd883c6f
EB
664 members = expr['data']
665
fd41dd4e 666 check_type(expr_info, "'data' for struct '%s'" % name, members,
c9e0a798 667 allow_dict=True, allow_optional=True)
fd41dd4e 668 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
dd883c6f
EB
669 allow_metas=['struct'])
670
437db254 671
0545f6b8
EB
672def check_keys(expr_elem, meta, required, optional=[]):
673 expr = expr_elem['expr']
674 info = expr_elem['info']
675 name = expr[meta]
676 if not isinstance(name, str):
677 raise QAPIExprError(info,
678 "'%s' key must have a string value" % meta)
437db254 679 required = required + [meta]
0545f6b8 680 for (key, value) in expr.items():
437db254 681 if key not in required and key not in optional:
0545f6b8
EB
682 raise QAPIExprError(info,
683 "Unknown key '%s' in %s '%s'"
684 % (key, meta, name))
437db254 685 if (key == 'gen' or key == 'success-response') and value is not False:
2cbf0992
EB
686 raise QAPIExprError(info,
687 "'%s' of %s '%s' should only use false value"
688 % (key, meta, name))
0545f6b8 689 for key in required:
437db254 690 if key not in expr:
0545f6b8
EB
691 raise QAPIExprError(info,
692 "Key '%s' is missing from %s '%s'"
693 % (key, meta, name))
694
437db254 695
4d076d67 696def check_exprs(exprs):
4dc2e690 697 global all_names
4dc2e690 698
4d076d67
MA
699 # Learn the types and check for valid expression keys
700 for builtin in builtin_types.keys():
701 all_names[builtin] = 'built-in'
702 for expr_elem in exprs:
703 expr = expr_elem['expr']
704 info = expr_elem['info']
437db254 705 if 'enum' in expr:
351d36e4 706 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
4d076d67 707 add_enum(expr['enum'], info, expr['data'])
437db254 708 elif 'union' in expr:
4d076d67
MA
709 check_keys(expr_elem, 'union', ['data'],
710 ['base', 'discriminator'])
711 add_union(expr, info)
437db254 712 elif 'alternate' in expr:
4d076d67
MA
713 check_keys(expr_elem, 'alternate', ['data'])
714 add_name(expr['alternate'], info, 'alternate')
437db254 715 elif 'struct' in expr:
4d076d67
MA
716 check_keys(expr_elem, 'struct', ['data'], ['base'])
717 add_struct(expr, info)
437db254 718 elif 'command' in expr:
4d076d67
MA
719 check_keys(expr_elem, 'command', [],
720 ['data', 'returns', 'gen', 'success-response'])
721 add_name(expr['command'], info, 'command')
437db254 722 elif 'event' in expr:
4d076d67
MA
723 check_keys(expr_elem, 'event', [], ['data'])
724 add_name(expr['event'], info, 'event')
725 else:
726 raise QAPIExprError(expr_elem['info'],
727 "Expression is missing metatype")
2caba36c 728
4d076d67
MA
729 # Try again for hidden UnionKind enum
730 for expr_elem in exprs:
731 expr = expr_elem['expr']
437db254 732 if 'union' in expr:
4d076d67
MA
733 if not discriminator_find_enum_define(expr):
734 add_enum('%sKind' % expr['union'], expr_elem['info'],
4dc2e690 735 implicit=True)
437db254 736 elif 'alternate' in expr:
4d076d67
MA
737 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
738 implicit=True)
739
740 # Validate that exprs make sense
741 for expr_elem in exprs:
742 expr = expr_elem['expr']
743 info = expr_elem['info']
268a1c5e 744
437db254 745 if 'enum' in expr:
4d076d67 746 check_enum(expr, info)
437db254 747 elif 'union' in expr:
4d076d67 748 check_union(expr, info)
437db254 749 elif 'alternate' in expr:
4d076d67 750 check_alternate(expr, info)
437db254 751 elif 'struct' in expr:
4d076d67 752 check_struct(expr, info)
437db254 753 elif 'command' in expr:
4d076d67 754 check_command(expr, info)
437db254 755 elif 'event' in expr:
4d076d67
MA
756 check_event(expr, info)
757 else:
758 assert False, 'unexpected meta type'
759
ac88219a
MA
760 return exprs
761
762
763#
764# Schema compiler frontend
765#
766
767class QAPISchemaEntity(object):
768 def __init__(self, name, info):
769 assert isinstance(name, str)
770 self.name = name
99df5289
EB
771 # For explicitly defined entities, info points to the (explicit)
772 # definition. For builtins (and their arrays), info is None.
773 # For implicitly defined entities, info points to a place that
774 # triggered the implicit definition (there may be more than one
775 # such place).
ac88219a
MA
776 self.info = info
777
f51d8c3d
MA
778 def c_name(self):
779 return c_name(self.name)
780
ac88219a
MA
781 def check(self, schema):
782 pass
783
49823c4b
EB
784 def is_implicit(self):
785 return not self.info
786
3f7dc21b
MA
787 def visit(self, visitor):
788 pass
789
790
791class QAPISchemaVisitor(object):
792 def visit_begin(self, schema):
793 pass
794
795 def visit_end(self):
796 pass
797
25a0d9c9
EB
798 def visit_needed(self, entity):
799 # Default to visiting everything
800 return True
801
3f7dc21b
MA
802 def visit_builtin_type(self, name, info, json_type):
803 pass
804
805 def visit_enum_type(self, name, info, values, prefix):
806 pass
807
808 def visit_array_type(self, name, info, element_type):
809 pass
810
811 def visit_object_type(self, name, info, base, members, variants):
812 pass
813
39a18158
MA
814 def visit_object_type_flat(self, name, info, members, variants):
815 pass
816
3f7dc21b
MA
817 def visit_alternate_type(self, name, info, variants):
818 pass
819
820 def visit_command(self, name, info, arg_type, ret_type,
821 gen, success_response):
822 pass
823
824 def visit_event(self, name, info, arg_type):
825 pass
826
ac88219a
MA
827
828class QAPISchemaType(QAPISchemaEntity):
4040d995
EB
829 # Return the C type for common use.
830 # For the types we commonly box, this is a pointer type.
831 def c_type(self):
832 pass
833
834 # Return the C type to be used in a parameter list.
835 def c_param_type(self):
836 return self.c_type()
837
838 # Return the C type to be used where we suppress boxing.
839 def c_unboxed_type(self):
840 return self.c_type()
f51d8c3d 841
f51d8c3d
MA
842 def json_type(self):
843 pass
844
845 def alternate_qtype(self):
846 json2qtype = {
847 'string': 'QTYPE_QSTRING',
848 'number': 'QTYPE_QFLOAT',
849 'int': 'QTYPE_QINT',
850 'boolean': 'QTYPE_QBOOL',
851 'object': 'QTYPE_QDICT'
852 }
853 return json2qtype.get(self.json_type())
ac88219a
MA
854
855
856class QAPISchemaBuiltinType(QAPISchemaType):
861877a0 857 def __init__(self, name, json_type, c_type):
ac88219a 858 QAPISchemaType.__init__(self, name, None)
f51d8c3d
MA
859 assert not c_type or isinstance(c_type, str)
860 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
861 'value')
862 self._json_type_name = json_type
863 self._c_type_name = c_type
f51d8c3d
MA
864
865 def c_name(self):
866 return self.name
867
4040d995
EB
868 def c_type(self):
869 return self._c_type_name
870
871 def c_param_type(self):
872 if self.name == 'str':
f51d8c3d
MA
873 return 'const ' + self._c_type_name
874 return self._c_type_name
875
f51d8c3d
MA
876 def json_type(self):
877 return self._json_type_name
ac88219a 878
3f7dc21b
MA
879 def visit(self, visitor):
880 visitor.visit_builtin_type(self.name, self.info, self.json_type())
881
ac88219a
MA
882
883class QAPISchemaEnumType(QAPISchemaType):
884 def __init__(self, name, info, values, prefix):
885 QAPISchemaType.__init__(self, name, info)
886 for v in values:
93bda4dd
EB
887 assert isinstance(v, QAPISchemaMember)
888 v.set_owner(name)
ac88219a
MA
889 assert prefix is None or isinstance(prefix, str)
890 self.values = values
891 self.prefix = prefix
892
893 def check(self, schema):
93bda4dd
EB
894 seen = {}
895 for v in self.values:
896 v.check_clash(self.info, seen)
ac88219a 897
99df5289
EB
898 def is_implicit(self):
899 # See QAPISchema._make_implicit_enum_type()
8712fa53 900 return self.name.endswith('Kind')
99df5289 901
4040d995 902 def c_type(self):
f51d8c3d
MA
903 return c_name(self.name)
904
93bda4dd
EB
905 def member_names(self):
906 return [v.name for v in self.values]
907
f51d8c3d
MA
908 def json_type(self):
909 return 'string'
910
3f7dc21b
MA
911 def visit(self, visitor):
912 visitor.visit_enum_type(self.name, self.info,
93bda4dd 913 self.member_names(), self.prefix)
3f7dc21b 914
ac88219a
MA
915
916class QAPISchemaArrayType(QAPISchemaType):
917 def __init__(self, name, info, element_type):
918 QAPISchemaType.__init__(self, name, info)
919 assert isinstance(element_type, str)
920 self._element_type_name = element_type
921 self.element_type = None
922
923 def check(self, schema):
924 self.element_type = schema.lookup_type(self._element_type_name)
925 assert self.element_type
926
99df5289
EB
927 def is_implicit(self):
928 return True
929
4040d995
EB
930 def c_type(self):
931 return c_name(self.name) + pointer_suffix
932
f51d8c3d
MA
933 def json_type(self):
934 return 'array'
935
3f7dc21b
MA
936 def visit(self, visitor):
937 visitor.visit_array_type(self.name, self.info, self.element_type)
938
ac88219a
MA
939
940class QAPISchemaObjectType(QAPISchemaType):
941 def __init__(self, name, info, base, local_members, variants):
da34a9bd
EB
942 # struct has local_members, optional base, and no variants
943 # flat union has base, variants, and no local_members
944 # simple union has local_members, variants, and no base
ac88219a
MA
945 QAPISchemaType.__init__(self, name, info)
946 assert base is None or isinstance(base, str)
947 for m in local_members:
948 assert isinstance(m, QAPISchemaObjectTypeMember)
88d4ef8b
EB
949 m.set_owner(name)
950 if variants is not None:
951 assert isinstance(variants, QAPISchemaObjectTypeVariants)
952 variants.set_owner(name)
ac88219a
MA
953 self._base_name = base
954 self.base = None
955 self.local_members = local_members
956 self.variants = variants
957 self.members = None
958
959 def check(self, schema):
bac5429c
EB
960 if self.members is False: # check for cycles
961 raise QAPIExprError(self.info,
962 "Object %s contains itself" % self.name)
ac88219a
MA
963 if self.members:
964 return
965 self.members = False # mark as being checked
23a4b2c6 966 seen = OrderedDict()
ac88219a
MA
967 if self._base_name:
968 self.base = schema.lookup_type(self._base_name)
969 assert isinstance(self.base, QAPISchemaObjectType)
ac88219a 970 self.base.check(schema)
27b60ab9 971 self.base.check_clash(schema, self.info, seen)
ac88219a 972 for m in self.local_members:
e564e2dd 973 m.check(schema)
27b60ab9 974 m.check_clash(self.info, seen)
14ff8461 975 self.members = seen.values()
ac88219a 976 if self.variants:
cdc5fa37 977 self.variants.check(schema, seen)
14ff8461 978 assert self.variants.tag_member in self.members
27b60ab9 979 self.variants.check_clash(schema, self.info, seen)
ac88219a 980
14f00c6c 981 # Check that the members of this type do not cause duplicate JSON members,
27b60ab9
EB
982 # and update seen to track the members seen so far. Report any errors
983 # on behalf of info, which is not necessarily self.info
984 def check_clash(self, schema, info, seen):
c2183d2e
EB
985 assert not self.variants # not implemented
986 for m in self.members:
27b60ab9 987 m.check_clash(info, seen)
c2183d2e 988
99df5289 989 def is_implicit(self):
7599697c
EB
990 # See QAPISchema._make_implicit_object_type(), as well as
991 # _def_predefineds()
992 return self.name.startswith('q_')
99df5289 993
f51d8c3d 994 def c_name(self):
f51d8c3d
MA
995 return QAPISchemaType.c_name(self)
996
4040d995 997 def c_type(self):
49823c4b 998 assert not self.is_implicit()
becceedc 999 return c_name(self.name) + pointer_suffix
f51d8c3d 1000
4040d995 1001 def c_unboxed_type(self):
4040d995
EB
1002 return c_name(self.name)
1003
f51d8c3d
MA
1004 def json_type(self):
1005 return 'object'
1006
3f7dc21b
MA
1007 def visit(self, visitor):
1008 visitor.visit_object_type(self.name, self.info,
1009 self.base, self.local_members, self.variants)
39a18158
MA
1010 visitor.visit_object_type_flat(self.name, self.info,
1011 self.members, self.variants)
3f7dc21b 1012
ac88219a 1013
d44f9ac8 1014class QAPISchemaMember(object):
88d4ef8b
EB
1015 role = 'member'
1016
d44f9ac8 1017 def __init__(self, name):
ac88219a 1018 assert isinstance(name, str)
ac88219a 1019 self.name = name
88d4ef8b
EB
1020 self.owner = None
1021
1022 def set_owner(self, name):
1023 assert not self.owner
1024 self.owner = name
ac88219a 1025
27b60ab9
EB
1026 def check_clash(self, info, seen):
1027 cname = c_name(self.name)
893e1f2c
EB
1028 if cname.lower() != cname and self.owner not in case_whitelist:
1029 raise QAPIExprError(info,
1030 "%s should not use uppercase" % self.describe())
27b60ab9
EB
1031 if cname in seen:
1032 raise QAPIExprError(info,
1033 "%s collides with %s"
1034 % (self.describe(), seen[cname].describe()))
1035 seen[cname] = self
577de12d 1036
88d4ef8b
EB
1037 def _pretty_owner(self):
1038 owner = self.owner
7599697c 1039 if owner.startswith('q_obj_'):
88d4ef8b
EB
1040 # See QAPISchema._make_implicit_object_type() - reverse the
1041 # mapping there to create a nice human-readable description
7599697c 1042 owner = owner[6:]
88d4ef8b
EB
1043 if owner.endswith('-arg'):
1044 return '(parameter of %s)' % owner[:-4]
ac4338f8
EB
1045 elif owner.endswith('-base'):
1046 return '(base of %s)' % owner[:-5]
88d4ef8b
EB
1047 else:
1048 assert owner.endswith('-wrapper')
1049 # Unreachable and not implemented
1050 assert False
93bda4dd
EB
1051 if owner.endswith('Kind'):
1052 # See QAPISchema._make_implicit_enum_type()
1053 return '(branch of %s)' % owner[:-4]
88d4ef8b
EB
1054 return '(%s of %s)' % (self.role, owner)
1055
1056 def describe(self):
1057 return "'%s' %s" % (self.name, self._pretty_owner())
1058
ac88219a 1059
d44f9ac8
EB
1060class QAPISchemaObjectTypeMember(QAPISchemaMember):
1061 def __init__(self, name, typ, optional):
1062 QAPISchemaMember.__init__(self, name)
1063 assert isinstance(typ, str)
1064 assert isinstance(optional, bool)
1065 self._type_name = typ
1066 self.type = None
1067 self.optional = optional
1068
1069 def check(self, schema):
1070 assert self.owner
1071 self.type = schema.lookup_type(self._type_name)
1072 assert self.type
1073
1074
ac88219a 1075class QAPISchemaObjectTypeVariants(object):
46292ba7
EB
1076 def __init__(self, tag_name, tag_member, variants):
1077 # Flat unions pass tag_name but not tag_member.
1078 # Simple unions and alternates pass tag_member but not tag_name.
1079 # After check(), tag_member is always set, and tag_name remains
1080 # a reliable witness of being used by a flat union.
1081 assert bool(tag_member) != bool(tag_name)
1082 assert (isinstance(tag_name, str) or
1083 isinstance(tag_member, QAPISchemaObjectTypeMember))
02a57ae3 1084 assert len(variants) > 0
ac88219a
MA
1085 for v in variants:
1086 assert isinstance(v, QAPISchemaObjectTypeVariant)
1087 self.tag_name = tag_name
46292ba7 1088 self.tag_member = tag_member
ac88219a
MA
1089 self.variants = variants
1090
88d4ef8b
EB
1091 def set_owner(self, name):
1092 for v in self.variants:
1093 v.set_owner(name)
1094
cdc5fa37 1095 def check(self, schema, seen):
14ff8461 1096 if not self.tag_member: # flat union
27b60ab9
EB
1097 self.tag_member = seen[c_name(self.tag_name)]
1098 assert self.tag_name == self.tag_member.name
ac88219a
MA
1099 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1100 for v in self.variants:
10565ca9 1101 v.check(schema)
0426d53c
EB
1102 # Union names must match enum values; alternate names are
1103 # checked separately. Use 'seen' to tell the two apart.
1104 if seen:
93bda4dd 1105 assert v.name in self.tag_member.type.member_names()
0426d53c 1106 assert isinstance(v.type, QAPISchemaObjectType)
b807a1e1
EB
1107 v.type.check(schema)
1108
27b60ab9 1109 def check_clash(self, schema, info, seen):
b807a1e1
EB
1110 for v in self.variants:
1111 # Reset seen map for each variant, since qapi names from one
1112 # branch do not affect another branch
b807a1e1 1113 assert isinstance(v.type, QAPISchemaObjectType)
27b60ab9 1114 v.type.check_clash(schema, info, dict(seen))
ac88219a 1115
437db254 1116
ac88219a 1117class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
88d4ef8b
EB
1118 role = 'branch'
1119
ac88219a
MA
1120 def __init__(self, name, typ):
1121 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1122
ac88219a
MA
1123
1124class QAPISchemaAlternateType(QAPISchemaType):
1125 def __init__(self, name, info, variants):
1126 QAPISchemaType.__init__(self, name, info)
1127 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1128 assert not variants.tag_name
88d4ef8b
EB
1129 variants.set_owner(name)
1130 variants.tag_member.set_owner(self.name)
ac88219a
MA
1131 self.variants = variants
1132
1133 def check(self, schema):
e564e2dd 1134 self.variants.tag_member.check(schema)
b807a1e1
EB
1135 # Not calling self.variants.check_clash(), because there's nothing
1136 # to clash with
cdc5fa37 1137 self.variants.check(schema, {})
0426d53c
EB
1138 # Alternate branch names have no relation to the tag enum values;
1139 # so we have to check for potential name collisions ourselves.
1140 seen = {}
1141 for v in self.variants.variants:
1142 v.check_clash(self.info, seen)
ac88219a 1143
4040d995
EB
1144 def c_type(self):
1145 return c_name(self.name) + pointer_suffix
1146
f51d8c3d
MA
1147 def json_type(self):
1148 return 'value'
1149
3f7dc21b
MA
1150 def visit(self, visitor):
1151 visitor.visit_alternate_type(self.name, self.info, self.variants)
1152
ac88219a
MA
1153
1154class QAPISchemaCommand(QAPISchemaEntity):
1155 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1156 QAPISchemaEntity.__init__(self, name, info)
1157 assert not arg_type or isinstance(arg_type, str)
1158 assert not ret_type or isinstance(ret_type, str)
1159 self._arg_type_name = arg_type
1160 self.arg_type = None
1161 self._ret_type_name = ret_type
1162 self.ret_type = None
1163 self.gen = gen
1164 self.success_response = success_response
1165
1166 def check(self, schema):
1167 if self._arg_type_name:
1168 self.arg_type = schema.lookup_type(self._arg_type_name)
1169 assert isinstance(self.arg_type, QAPISchemaObjectType)
1170 assert not self.arg_type.variants # not implemented
1171 if self._ret_type_name:
1172 self.ret_type = schema.lookup_type(self._ret_type_name)
1173 assert isinstance(self.ret_type, QAPISchemaType)
1174
3f7dc21b
MA
1175 def visit(self, visitor):
1176 visitor.visit_command(self.name, self.info,
1177 self.arg_type, self.ret_type,
1178 self.gen, self.success_response)
1179
ac88219a
MA
1180
1181class QAPISchemaEvent(QAPISchemaEntity):
1182 def __init__(self, name, info, arg_type):
1183 QAPISchemaEntity.__init__(self, name, info)
1184 assert not arg_type or isinstance(arg_type, str)
1185 self._arg_type_name = arg_type
1186 self.arg_type = None
1187
1188 def check(self, schema):
1189 if self._arg_type_name:
1190 self.arg_type = schema.lookup_type(self._arg_type_name)
1191 assert isinstance(self.arg_type, QAPISchemaObjectType)
1192 assert not self.arg_type.variants # not implemented
1193
3f7dc21b
MA
1194 def visit(self, visitor):
1195 visitor.visit_event(self.name, self.info, self.arg_type)
1196
ac88219a
MA
1197
1198class QAPISchema(object):
1199 def __init__(self, fname):
1200 try:
1201 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
7618b91f 1202 self._entity_dict = {}
99df5289 1203 self._predefining = True
7618b91f 1204 self._def_predefineds()
99df5289 1205 self._predefining = False
7618b91f
EB
1206 self._def_exprs()
1207 self.check()
291928a8 1208 except (QAPISchemaError, QAPIExprError) as err:
ac88219a
MA
1209 print >>sys.stderr, err
1210 exit(1)
ac88219a 1211
ac88219a 1212 def _def_entity(self, ent):
99df5289
EB
1213 # Only the predefined types are allowed to not have info
1214 assert ent.info or self._predefining
ac88219a
MA
1215 assert ent.name not in self._entity_dict
1216 self._entity_dict[ent.name] = ent
1217
1218 def lookup_entity(self, name, typ=None):
1219 ent = self._entity_dict.get(name)
1220 if typ and not isinstance(ent, typ):
1221 return None
1222 return ent
1223
1224 def lookup_type(self, name):
1225 return self.lookup_entity(name, QAPISchemaType)
1226
861877a0
EB
1227 def _def_builtin_type(self, name, json_type, c_type):
1228 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
9f08c8ec
EB
1229 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1230 # qapi-types.h from a single .c, all arrays of builtins must be
1231 # declared in the first file whether or not they are used. Nicer
1232 # would be to use lazy instantiation, while figuring out how to
1233 # avoid compilation issues with multiple qapi-types.h.
99df5289 1234 self._make_array_type(name, None)
ac88219a
MA
1235
1236 def _def_predefineds(self):
861877a0
EB
1237 for t in [('str', 'string', 'char' + pointer_suffix),
1238 ('number', 'number', 'double'),
1239 ('int', 'int', 'int64_t'),
1240 ('int8', 'int', 'int8_t'),
1241 ('int16', 'int', 'int16_t'),
1242 ('int32', 'int', 'int32_t'),
1243 ('int64', 'int', 'int64_t'),
1244 ('uint8', 'int', 'uint8_t'),
1245 ('uint16', 'int', 'uint16_t'),
1246 ('uint32', 'int', 'uint32_t'),
1247 ('uint64', 'int', 'uint64_t'),
1248 ('size', 'int', 'uint64_t'),
1249 ('bool', 'boolean', 'bool'),
1250 ('any', 'value', 'QObject' + pointer_suffix)]:
f51d8c3d 1251 self._def_builtin_type(*t)
7599697c
EB
1252 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1253 None, [], None)
39a18158 1254 self._def_entity(self.the_empty_object_type)
93bda4dd
EB
1255 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1256 'qstring', 'qdict', 'qlist',
1257 'qfloat', 'qbool'])
1258 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
7264f5c5 1259 'QTYPE'))
ac88219a 1260
93bda4dd
EB
1261 def _make_enum_members(self, values):
1262 return [QAPISchemaMember(v) for v in values]
1263
99df5289 1264 def _make_implicit_enum_type(self, name, info, values):
93bda4dd 1265 # See also QAPISchemaObjectTypeMember._pretty_owner()
49823c4b 1266 name = name + 'Kind' # Use namespace reserved by add_name()
93bda4dd
EB
1267 self._def_entity(QAPISchemaEnumType(
1268 name, info, self._make_enum_members(values), None))
ac88219a
MA
1269 return name
1270
99df5289 1271 def _make_array_type(self, element_type, info):
255960dd 1272 name = element_type + 'List' # Use namespace reserved by add_name()
ac88219a 1273 if not self.lookup_type(name):
99df5289 1274 self._def_entity(QAPISchemaArrayType(name, info, element_type))
ac88219a
MA
1275 return name
1276
99df5289 1277 def _make_implicit_object_type(self, name, info, role, members):
ac88219a
MA
1278 if not members:
1279 return None
88d4ef8b 1280 # See also QAPISchemaObjectTypeMember._pretty_owner()
7599697c 1281 name = 'q_obj_%s-%s' % (name, role)
ac88219a 1282 if not self.lookup_entity(name, QAPISchemaObjectType):
99df5289 1283 self._def_entity(QAPISchemaObjectType(name, info, None,
ac88219a
MA
1284 members, None))
1285 return name
1286
1287 def _def_enum_type(self, expr, info):
1288 name = expr['enum']
1289 data = expr['data']
1290 prefix = expr.get('prefix')
93bda4dd
EB
1291 self._def_entity(QAPISchemaEnumType(
1292 name, info, self._make_enum_members(data), prefix))
ac88219a 1293
99df5289 1294 def _make_member(self, name, typ, info):
ac88219a
MA
1295 optional = False
1296 if name.startswith('*'):
1297 name = name[1:]
1298 optional = True
1299 if isinstance(typ, list):
1300 assert len(typ) == 1
99df5289 1301 typ = self._make_array_type(typ[0], info)
ac88219a
MA
1302 return QAPISchemaObjectTypeMember(name, typ, optional)
1303
99df5289
EB
1304 def _make_members(self, data, info):
1305 return [self._make_member(key, value, info)
ac88219a
MA
1306 for (key, value) in data.iteritems()]
1307
1308 def _def_struct_type(self, expr, info):
1309 name = expr['struct']
1310 base = expr.get('base')
1311 data = expr['data']
1312 self._def_entity(QAPISchemaObjectType(name, info, base,
99df5289 1313 self._make_members(data, info),
ac88219a 1314 None))
ac88219a
MA
1315
1316 def _make_variant(self, case, typ):
1317 return QAPISchemaObjectTypeVariant(case, typ)
1318
99df5289 1319 def _make_simple_variant(self, case, typ, info):
ac88219a
MA
1320 if isinstance(typ, list):
1321 assert len(typ) == 1
99df5289
EB
1322 typ = self._make_array_type(typ[0], info)
1323 typ = self._make_implicit_object_type(
1324 typ, info, 'wrapper', [self._make_member('data', typ, info)])
ac88219a
MA
1325 return QAPISchemaObjectTypeVariant(case, typ)
1326
ac88219a
MA
1327 def _def_union_type(self, expr, info):
1328 name = expr['union']
1329 data = expr['data']
1330 base = expr.get('base')
1331 tag_name = expr.get('discriminator')
46292ba7 1332 tag_member = None
ac4338f8
EB
1333 if isinstance(base, dict):
1334 base = (self._make_implicit_object_type(
1335 name, info, 'base', self._make_members(base, info)))
ac88219a
MA
1336 if tag_name:
1337 variants = [self._make_variant(key, value)
1338 for (key, value) in data.iteritems()]
da34a9bd 1339 members = []
ac88219a 1340 else:
99df5289 1341 variants = [self._make_simple_variant(key, value, info)
ac88219a 1342 for (key, value) in data.iteritems()]
9d3f3494
EB
1343 typ = self._make_implicit_enum_type(name, info,
1344 [v.name for v in variants])
1345 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
da34a9bd 1346 members = [tag_member]
ac88219a 1347 self._def_entity(
da34a9bd 1348 QAPISchemaObjectType(name, info, base, members,
ac88219a 1349 QAPISchemaObjectTypeVariants(tag_name,
46292ba7 1350 tag_member,
ac88219a 1351 variants)))
ac88219a
MA
1352
1353 def _def_alternate_type(self, expr, info):
1354 name = expr['alternate']
1355 data = expr['data']
1356 variants = [self._make_variant(key, value)
1357 for (key, value) in data.iteritems()]
0426d53c 1358 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
ac88219a
MA
1359 self._def_entity(
1360 QAPISchemaAlternateType(name, info,
1361 QAPISchemaObjectTypeVariants(None,
46292ba7 1362 tag_member,
ac88219a 1363 variants)))
ac88219a
MA
1364
1365 def _def_command(self, expr, info):
1366 name = expr['command']
1367 data = expr.get('data')
1368 rets = expr.get('returns')
1369 gen = expr.get('gen', True)
1370 success_response = expr.get('success-response', True)
1371 if isinstance(data, OrderedDict):
99df5289
EB
1372 data = self._make_implicit_object_type(
1373 name, info, 'arg', self._make_members(data, info))
ac88219a
MA
1374 if isinstance(rets, list):
1375 assert len(rets) == 1
99df5289 1376 rets = self._make_array_type(rets[0], info)
ac88219a
MA
1377 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1378 success_response))
1379
1380 def _def_event(self, expr, info):
1381 name = expr['event']
1382 data = expr.get('data')
1383 if isinstance(data, OrderedDict):
99df5289
EB
1384 data = self._make_implicit_object_type(
1385 name, info, 'arg', self._make_members(data, info))
ac88219a
MA
1386 self._def_entity(QAPISchemaEvent(name, info, data))
1387
1388 def _def_exprs(self):
1389 for expr_elem in self.exprs:
1390 expr = expr_elem['expr']
1391 info = expr_elem['info']
1392 if 'enum' in expr:
1393 self._def_enum_type(expr, info)
1394 elif 'struct' in expr:
1395 self._def_struct_type(expr, info)
1396 elif 'union' in expr:
1397 self._def_union_type(expr, info)
1398 elif 'alternate' in expr:
1399 self._def_alternate_type(expr, info)
1400 elif 'command' in expr:
1401 self._def_command(expr, info)
1402 elif 'event' in expr:
1403 self._def_event(expr, info)
1404 else:
1405 assert False
1406
1407 def check(self):
1408 for ent in self._entity_dict.values():
1409 ent.check(self)
4d076d67 1410
3f7dc21b 1411 def visit(self, visitor):
25a0d9c9
EB
1412 visitor.visit_begin(self)
1413 for (name, entity) in sorted(self._entity_dict.items()):
1414 if visitor.visit_needed(entity):
1415 entity.visit(visitor)
3f7dc21b
MA
1416 visitor.visit_end()
1417
b86b05ed 1418
00e4b285
MA
1419#
1420# Code generation helpers
1421#
1422
0f923be2
MR
1423def camel_case(name):
1424 new_name = ''
1425 first = True
1426 for ch in name:
1427 if ch in ['_', '-']:
1428 first = True
1429 elif first:
1430 new_name += ch.upper()
1431 first = False
1432 else:
1433 new_name += ch.lower()
1434 return new_name
1435
437db254 1436
849bc538
MA
1437# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1438# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1439# ENUM24_Name -> ENUM24_NAME
1440def camel_to_upper(value):
1441 c_fun_str = c_name(value, False)
1442 if value.isupper():
1443 return c_fun_str
1444
1445 new_name = ''
1446 l = len(c_fun_str)
1447 for i in range(l):
1448 c = c_fun_str[i]
1449 # When c is upper and no "_" appears before, do more checks
1450 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
437db254
EB
1451 if i < l - 1 and c_fun_str[i + 1].islower():
1452 new_name += '_'
1453 elif c_fun_str[i - 1].isdigit():
849bc538
MA
1454 new_name += '_'
1455 new_name += c
1456 return new_name.lstrip('_').upper()
1457
437db254 1458
351d36e4
DB
1459def c_enum_const(type_name, const_name, prefix=None):
1460 if prefix is not None:
1461 type_name = prefix
d20a580b 1462 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
849bc538 1463
18df515e 1464c_name_trans = string.maketrans('.-', '__')
47299262 1465
437db254 1466
c6405b54
EB
1467# Map @name to a valid C identifier.
1468# If @protect, avoid returning certain ticklish identifiers (like
1469# C keywords) by prepending "q_".
1470#
1471# Used for converting 'name' from a 'name':'type' qapi definition
1472# into a generated struct member, as well as converting type names
1473# into substrings of a generated C function name.
1474# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1475# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
18df515e 1476def c_name(name, protect=True):
427a1a2c
BS
1477 # ANSI X3J11/88-090, 3.1.1
1478 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
437db254
EB
1479 'default', 'do', 'double', 'else', 'enum', 'extern',
1480 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1481 'return', 'short', 'signed', 'sizeof', 'static',
1482 'struct', 'switch', 'typedef', 'union', 'unsigned',
1483 'void', 'volatile', 'while'])
427a1a2c
BS
1484 # ISO/IEC 9899:1999, 6.4.1
1485 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1486 # ISO/IEC 9899:2011, 6.4.1
437db254
EB
1487 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1488 '_Noreturn', '_Static_assert', '_Thread_local'])
427a1a2c
BS
1489 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1490 # excluding _.*
1491 gcc_words = set(['asm', 'typeof'])
6f88009e
TS
1492 # C++ ISO/IEC 14882:2003 2.11
1493 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1494 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1495 'namespace', 'new', 'operator', 'private', 'protected',
1496 'public', 'reinterpret_cast', 'static_cast', 'template',
1497 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1498 'using', 'virtual', 'wchar_t',
1499 # alternative representations
1500 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1501 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1057725f 1502 # namespace pollution:
86ae1911 1503 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
c43567c1 1504 name = name.translate(c_name_trans)
437db254
EB
1505 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1506 | cpp_words | polluted_words):
427a1a2c 1507 return "q_" + name
c43567c1 1508 return name
0f923be2 1509
05dfb26c 1510eatspace = '\033EATSPACE.'
d5573446 1511pointer_suffix = ' *' + eatspace
05dfb26c 1512
437db254 1513
0f923be2
MR
1514def genindent(count):
1515 ret = ""
437db254 1516 for _ in range(count):
0f923be2
MR
1517 ret += " "
1518 return ret
1519
1520indent_level = 0
1521
437db254 1522
0f923be2
MR
1523def push_indent(indent_amount=4):
1524 global indent_level
1525 indent_level += indent_amount
1526
437db254 1527
0f923be2
MR
1528def pop_indent(indent_amount=4):
1529 global indent_level
1530 indent_level -= indent_amount
1531
437db254 1532
77e703b8
MA
1533# Generate @code with @kwds interpolated.
1534# Obey indent_level, and strip eatspace.
0f923be2 1535def cgen(code, **kwds):
77e703b8
MA
1536 raw = code % kwds
1537 if indent_level:
1538 indent = genindent(indent_level)
2752e5be
MA
1539 # re.subn() lacks flags support before Python 2.7, use re.compile()
1540 raw = re.subn(re.compile("^.", re.MULTILINE),
1541 indent + r'\g<0>', raw)
77e703b8
MA
1542 raw = raw[0]
1543 return re.sub(re.escape(eatspace) + ' *', '', raw)
0f923be2 1544
437db254 1545
0f923be2 1546def mcgen(code, **kwds):
77e703b8
MA
1547 if code[0] == '\n':
1548 code = code[1:]
1549 return cgen(code, **kwds)
0f923be2 1550
0f923be2
MR
1551
1552def guardname(filename):
00dfc3b2 1553 return c_name(filename, protect=False).upper()
c0afa9c5 1554
437db254 1555
c0afa9c5
MR
1556def guardstart(name):
1557 return mcgen('''
1558
1559#ifndef %(name)s
1560#define %(name)s
1561
1562''',
1563 name=guardname(name))
1564
437db254 1565
c0afa9c5
MR
1566def guardend(name):
1567 return mcgen('''
1568
1569#endif /* %(name)s */
1570
1571''',
1572 name=guardname(name))
2114f5a9 1573
437db254 1574
e98859a9 1575def gen_enum_lookup(name, values, prefix=None):
efd2eaa6
MA
1576 ret = mcgen('''
1577
e98859a9 1578const char *const %(c_name)s_lookup[] = {
efd2eaa6 1579''',
e98859a9 1580 c_name=c_name(name))
efd2eaa6
MA
1581 for value in values:
1582 index = c_enum_const(name, value, prefix)
1583 ret += mcgen('''
1584 [%(index)s] = "%(value)s",
1585''',
e98859a9 1586 index=index, value=value)
efd2eaa6 1587
7fb1cf16 1588 max_index = c_enum_const(name, '_MAX', prefix)
efd2eaa6
MA
1589 ret += mcgen('''
1590 [%(max_index)s] = NULL,
1591};
1592''',
e98859a9 1593 max_index=max_index)
efd2eaa6
MA
1594 return ret
1595
437db254 1596
e98859a9
MA
1597def gen_enum(name, values, prefix=None):
1598 # append automatically generated _MAX value
7fb1cf16 1599 enum_values = values + ['_MAX']
efd2eaa6 1600
e98859a9 1601 ret = mcgen('''
efd2eaa6 1602
e98859a9 1603typedef enum %(c_name)s {
efd2eaa6 1604''',
e98859a9 1605 c_name=c_name(name))
efd2eaa6
MA
1606
1607 i = 0
1608 for value in enum_values:
e98859a9
MA
1609 ret += mcgen('''
1610 %(c_enum)s = %(i)d,
efd2eaa6 1611''',
e98859a9 1612 c_enum=c_enum_const(name, value, prefix),
efd2eaa6
MA
1613 i=i)
1614 i += 1
1615
e98859a9
MA
1616 ret += mcgen('''
1617} %(c_name)s;
efd2eaa6 1618''',
e98859a9
MA
1619 c_name=c_name(name))
1620
1621 ret += mcgen('''
efd2eaa6 1622
e98859a9
MA
1623extern const char *const %(c_name)s_lookup[];
1624''',
1625 c_name=c_name(name))
1626 return ret
efd2eaa6 1627
437db254 1628
03b4367a
MA
1629def gen_params(arg_type, extra):
1630 if not arg_type:
1631 return extra
1632 assert not arg_type.variants
1633 ret = ''
1634 sep = ''
1635 for memb in arg_type.members:
1636 ret += sep
1637 sep = ', '
1638 if memb.optional:
1639 ret += 'bool has_%s, ' % c_name(memb.name)
4040d995 1640 ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name))
03b4367a
MA
1641 if extra:
1642 ret += sep + extra
1643 return ret
1644
1f353344 1645
12f254fd 1646def gen_err_check():
1f353344 1647 return mcgen('''
18bdbc3a 1648 if (err) {
12f254fd 1649 goto out;
82ca8e46
EB
1650 }
1651''')
82ca8e46
EB
1652
1653
00e4b285
MA
1654#
1655# Common command line parsing
1656#
1657
437db254
EB
1658
1659def parse_command_line(extra_options="", extra_long_options=[]):
2114f5a9
MA
1660
1661 try:
1662 opts, args = getopt.gnu_getopt(sys.argv[1:],
16d80f61 1663 "chp:o:" + extra_options,
2114f5a9 1664 ["source", "header", "prefix=",
16d80f61 1665 "output-dir="] + extra_long_options)
291928a8 1666 except getopt.GetoptError as err:
b4540968 1667 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
2114f5a9
MA
1668 sys.exit(1)
1669
1670 output_dir = ""
1671 prefix = ""
1672 do_c = False
1673 do_h = False
1674 extra_opts = []
1675
1676 for oa in opts:
1677 o, a = oa
1678 if o in ("-p", "--prefix"):
1cf47a15
MA
1679 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1680 if match.end() != len(a):
1681 print >>sys.stderr, \
1682 "%s: 'funny character '%s' in argument of --prefix" \
1683 % (sys.argv[0], a[match.end()])
1684 sys.exit(1)
2114f5a9 1685 prefix = a
2114f5a9
MA
1686 elif o in ("-o", "--output-dir"):
1687 output_dir = a + "/"
1688 elif o in ("-c", "--source"):
1689 do_c = True
1690 elif o in ("-h", "--header"):
1691 do_h = True
1692 else:
1693 extra_opts.append(oa)
1694
1695 if not do_c and not do_h:
1696 do_c = True
1697 do_h = True
1698
16d80f61
MA
1699 if len(args) != 1:
1700 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
b4540968 1701 sys.exit(1)
54414047 1702 fname = args[0]
b4540968 1703
54414047 1704 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
12f8e1b9 1705
00e4b285
MA
1706#
1707# Generate output files with boilerplate
1708#
1709
437db254 1710
12f8e1b9
MA
1711def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1712 c_comment, h_comment):
00dfc3b2 1713 guard = guardname(prefix + h_file)
12f8e1b9
MA
1714 c_file = output_dir + prefix + c_file
1715 h_file = output_dir + prefix + h_file
1716
c4f498fe
MA
1717 if output_dir:
1718 try:
1719 os.makedirs(output_dir)
291928a8 1720 except os.error as e:
c4f498fe
MA
1721 if e.errno != errno.EEXIST:
1722 raise
12f8e1b9
MA
1723
1724 def maybe_open(really, name, opt):
1725 if really:
1726 return open(name, opt)
1727 else:
1728 import StringIO
1729 return StringIO.StringIO()
1730
1731 fdef = maybe_open(do_c, c_file, 'w')
1732 fdecl = maybe_open(do_h, h_file, 'w')
1733
1734 fdef.write(mcgen('''
1735/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1736%(comment)s
1737''',
437db254 1738 comment=c_comment))
12f8e1b9
MA
1739
1740 fdecl.write(mcgen('''
1741/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1742%(comment)s
1743#ifndef %(guard)s
1744#define %(guard)s
1745
1746''',
437db254 1747 comment=h_comment, guard=guard))
12f8e1b9
MA
1748
1749 return (fdef, fdecl)
1750
437db254 1751
12f8e1b9
MA
1752def close_output(fdef, fdecl):
1753 fdecl.write('''
1754#endif
1755''')
12f8e1b9 1756 fdecl.close()
12f8e1b9 1757 fdef.close()
This page took 0.650173 seconds and 4 git commands to generate.