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