qemu-iotests/118: Test media change with qdev name
[qemu.git] / scripts / qapi.py
blob21bc32fda3d1e1d59f76d7b22c126deea236ea8c
2 # QAPI helper library
4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2016 Red Hat Inc.
7 # Authors:
8 # Anthony Liguori <aliguori@us.ibm.com>
9 # Markus Armbruster <armbru@redhat.com>
11 # This work is licensed under the terms of the GNU GPL, version 2.
12 # See the COPYING file in the top-level directory.
14 import re
15 from ordereddict import OrderedDict
16 import errno
17 import getopt
18 import os
19 import sys
20 import string
22 builtin_types = {
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',
35 'size': 'QTYPE_QINT',
36 'any': None, # any QType possible, actually
37 'QType': 'QTYPE_QSTRING',
40 # Whitelist of commands allowed to return a non-dictionary
41 returns_whitelist = [
42 # From QMP:
43 'human-monitor-command',
44 'qom-get',
45 'query-migrate-cache-size',
46 'query-tpm-models',
47 'query-tpm-types',
48 'ringbuf-read',
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',
62 # Whitelist of entities allowed to violate case conventions
63 case_whitelist = [
64 # From QMP:
65 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
66 'CpuInfoMIPS', # PC, visible through query-cpu
67 'CpuInfoTricore', # PC, visible through query-cpu
68 'QapiErrorClass', # all members, visible through errors
69 'UuidInfo', # UUID, visible through query-uuid
70 'X86CPURegister32', # all members, visible indirectly through qom-get
71 'q_obj_CpuInfo-base', # CPU, visible through query-cpu
74 enum_types = []
75 struct_types = []
76 union_types = []
77 events = []
78 all_names = {}
81 # Parsing the schema into expressions
85 def 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
94 class QAPISchemaError(Exception):
95 def __init__(self, schema, msg):
96 Exception.__init__(self)
97 self.fname = schema.fname
98 self.msg = msg
99 self.col = 1
100 self.line = schema.line
101 for ch in schema.src[schema.line_pos:schema.pos]:
102 if ch == '\t':
103 self.col = (self.col + 7) % 8 + 1
104 else:
105 self.col += 1
106 self.info = schema.incl_info
108 def __str__(self):
109 return error_path(self.info) + \
110 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
113 class QAPIExprError(Exception):
114 def __init__(self, expr_info, msg):
115 Exception.__init__(self)
116 assert expr_info
117 self.info = expr_info
118 self.msg = msg
120 def __str__(self):
121 return error_path(self.info['parent']) + \
122 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
125 class QAPISchemaParser(object):
127 def __init__(self, fp, previously_included=[], incl_info=None):
128 abs_fname = os.path.abspath(fp.name)
129 fname = fp.name
130 self.fname = fname
131 previously_included.append(abs_fname)
132 self.incl_info = incl_info
133 self.src = fp.read()
134 if self.src == '' or self.src[-1] != '\n':
135 self.src += '\n'
136 self.cursor = 0
137 self.line = 1
138 self.line_pos = 0
139 self.exprs = []
140 self.accept()
142 while self.tok is not None:
143 expr_info = {'file': fname, 'line': self.line,
144 'parent': self.incl_info}
145 expr = self.get_expr(False)
146 if isinstance(expr, dict) and "include" in expr:
147 if len(expr) != 1:
148 raise QAPIExprError(expr_info,
149 "Invalid 'include' directive")
150 include = expr["include"]
151 if not isinstance(include, str):
152 raise QAPIExprError(expr_info,
153 "Value of 'include' must be a string")
154 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
155 include)
156 # catch inclusion cycle
157 inf = expr_info
158 while inf:
159 if incl_abs_fname == os.path.abspath(inf['file']):
160 raise QAPIExprError(expr_info, "Inclusion loop for %s"
161 % include)
162 inf = inf['parent']
163 # skip multiple include of the same file
164 if incl_abs_fname in previously_included:
165 continue
166 try:
167 fobj = open(incl_abs_fname, 'r')
168 except IOError as e:
169 raise QAPIExprError(expr_info,
170 '%s: %s' % (e.strerror, include))
171 exprs_include = QAPISchemaParser(fobj, previously_included,
172 expr_info)
173 self.exprs.extend(exprs_include.exprs)
174 else:
175 expr_elem = {'expr': expr,
176 'info': expr_info}
177 self.exprs.append(expr_elem)
179 def accept(self):
180 while True:
181 self.tok = self.src[self.cursor]
182 self.pos = self.cursor
183 self.cursor += 1
184 self.val = None
186 if self.tok == '#':
187 self.cursor = self.src.find('\n', self.cursor)
188 elif self.tok in "{}:,[]":
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':
197 raise QAPISchemaError(self,
198 'Missing terminating "\'"')
199 if esc:
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
212 for _ in range(0, 4):
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,
234 "Unknown escape \\%s" % ch)
235 esc = False
236 elif ch == "\\":
237 esc = True
238 elif ch == "'":
239 self.val = string
240 return
241 else:
242 string += ch
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
255 elif self.tok == '\n':
256 if self.cursor == len(self.src):
257 self.tok = None
258 return
259 self.line += 1
260 self.line_pos = self.cursor
261 elif not self.tok.isspace():
262 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
264 def get_members(self):
265 expr = OrderedDict()
266 if self.tok == '}':
267 self.accept()
268 return expr
269 if self.tok != "'":
270 raise QAPISchemaError(self, 'Expected string or "}"')
271 while True:
272 key = self.val
273 self.accept()
274 if self.tok != ':':
275 raise QAPISchemaError(self, 'Expected ":"')
276 self.accept()
277 if key in expr:
278 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
279 expr[key] = self.get_expr(True)
280 if self.tok == '}':
281 self.accept()
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')
289 def get_values(self):
290 expr = []
291 if self.tok == ']':
292 self.accept()
293 return expr
294 if self.tok not in "{['tfn":
295 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
296 'boolean or "null"')
297 while True:
298 expr.append(self.get_expr(True))
299 if self.tok == ']':
300 self.accept()
301 return expr
302 if self.tok != ',':
303 raise QAPISchemaError(self, 'Expected "," or "]"')
304 self.accept()
306 def get_expr(self, nested):
307 if self.tok != '{' and not nested:
308 raise QAPISchemaError(self, 'Expected "{"')
309 if self.tok == '{':
310 self.accept()
311 expr = self.get_members()
312 elif self.tok == '[':
313 self.accept()
314 expr = self.get_values()
315 elif self.tok in "'tfn":
316 expr = self.val
317 self.accept()
318 else:
319 raise QAPISchemaError(self, 'Expected "{", "[" or string')
320 return expr
323 # Semantic analysis of schema expressions
324 # TODO fold into QAPISchema
325 # TODO catching name collisions in generated code would be nice
329 def find_base_members(base):
330 if isinstance(base, dict):
331 return base
332 base_struct_define = find_struct(base)
333 if not base_struct_define:
334 return None
335 return base_struct_define['data']
338 # Return the qtype of an alternate branch, or None on error.
339 def find_alternate_member_qtype(qapi_type):
340 if qapi_type in builtin_types:
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"
346 elif find_union(qapi_type):
347 return "QTYPE_QDICT"
348 return None
351 # Return the discriminator enum define if discriminator is specified as an
352 # enum type, otherwise return None.
353 def discriminator_find_enum_define(expr):
354 base = expr.get('base')
355 discriminator = expr.get('discriminator')
357 if not (discriminator and base):
358 return None
360 base_members = find_base_members(base)
361 if not base_members:
362 return None
364 discriminator_type = base_members.get(discriminator)
365 if not discriminator_type:
366 return None
368 return find_enum(discriminator_type)
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.
374 valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
375 '[a-zA-Z][a-zA-Z0-9_-]*$')
378 def check_name(expr_info, source, name, allow_optional=False,
379 enum_member=False):
380 global valid_name
381 membername = name
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
394 if enum_member and membername[0].isdigit():
395 membername = 'D' + membername
396 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
397 # and 'q_obj_*' implicit type names.
398 if not valid_name.match(membername) or \
399 c_name(membername, False).startswith('q_'):
400 raise QAPIExprError(expr_info,
401 "%s uses invalid name '%s'" % (source, name))
404 def add_name(name, info, meta, implicit=False):
405 global all_names
406 check_name(info, "'%s'" % meta, name)
407 # FIXME should reject names that differ only in '_' vs. '.'
408 # vs. '-', because they're liable to clash in generated C.
409 if name in all_names:
410 raise QAPIExprError(info,
411 "%s '%s' is already defined"
412 % (all_names[name], name))
413 if not implicit and (name.endswith('Kind') or name.endswith('List')):
414 raise QAPIExprError(info,
415 "%s '%s' should not end in '%s'"
416 % (meta, name, name[-4:]))
417 all_names[name] = meta
420 def add_struct(definition, info):
421 global struct_types
422 name = definition['struct']
423 add_name(name, info, 'struct')
424 struct_types.append(definition)
427 def find_struct(name):
428 global struct_types
429 for struct in struct_types:
430 if struct['struct'] == name:
431 return struct
432 return None
435 def add_union(definition, info):
436 global union_types
437 name = definition['union']
438 add_name(name, info, 'union')
439 union_types.append(definition)
442 def find_union(name):
443 global union_types
444 for union in union_types:
445 if union['union'] == name:
446 return union
447 return None
450 def add_enum(name, info, enum_values=None, implicit=False):
451 global enum_types
452 add_name(name, info, 'enum', implicit)
453 enum_types.append({"enum_name": name, "enum_values": enum_values})
456 def 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
464 def is_enum(name):
465 return find_enum(name) is not None
468 def check_type(expr_info, source, value, allow_array=False,
469 allow_dict=False, allow_optional=False,
470 allow_metas=[]):
471 global all_names
473 if value is None:
474 return
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]
487 # Check if type name for value is okay
488 if isinstance(value, str):
489 if value not in all_names:
490 raise QAPIExprError(expr_info,
491 "%s uses unknown type '%s'"
492 % (source, value))
493 if not all_names[value] in allow_metas:
494 raise QAPIExprError(expr_info,
495 "%s cannot use %s type '%s'"
496 % (source, all_names[value], value))
497 return
499 if not allow_dict:
500 raise QAPIExprError(expr_info,
501 "%s should be a type name" % source)
503 if not isinstance(value, OrderedDict):
504 raise QAPIExprError(expr_info,
505 "%s should be a dictionary or type name" % source)
507 # value is a dictionary, check that each member is okay
508 for (key, arg) in value.items():
509 check_name(expr_info, "Member of %s" % source, key,
510 allow_optional=allow_optional)
511 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
512 raise QAPIExprError(expr_info,
513 "Member of %s uses reserved name '%s'"
514 % (source, key))
515 # Todo: allow dictionaries to represent default values of
516 # an optional argument.
517 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
518 allow_array=True,
519 allow_metas=['built-in', 'union', 'alternate', 'struct',
520 'enum'])
523 def check_command(expr, expr_info):
524 name = expr['command']
525 boxed = expr.get('boxed', False)
527 args_meta = ['struct']
528 if boxed:
529 args_meta += ['union', 'alternate']
530 check_type(expr_info, "'data' for command '%s'" % name,
531 expr.get('data'), allow_dict=not boxed, allow_optional=True,
532 allow_metas=args_meta)
533 returns_meta = ['union', 'struct']
534 if name in returns_whitelist:
535 returns_meta += ['built-in', 'alternate', 'enum']
536 check_type(expr_info, "'returns' for command '%s'" % name,
537 expr.get('returns'), allow_array=True,
538 allow_optional=True, allow_metas=returns_meta)
541 def check_event(expr, expr_info):
542 global events
543 name = expr['event']
544 boxed = expr.get('boxed', False)
546 meta = ['struct']
547 if boxed:
548 meta += ['union', 'alternate']
549 events.append(name)
550 check_type(expr_info, "'data' for event '%s'" % name,
551 expr.get('data'), allow_dict=not boxed, allow_optional=True,
552 allow_metas=meta)
555 def check_union(expr, expr_info):
556 name = expr['union']
557 base = expr.get('base')
558 discriminator = expr.get('discriminator')
559 members = expr['data']
561 # Two types of unions, determined by discriminator.
563 # With no discriminator it is a simple union.
564 if discriminator is None:
565 enum_define = None
566 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
567 if base is not None:
568 raise QAPIExprError(expr_info,
569 "Simple union '%s' must not have a base"
570 % name)
572 # Else, it's a flat union.
573 else:
574 # The object must have a string or dictionary 'base'.
575 check_type(expr_info, "'base' for union '%s'" % name,
576 base, allow_dict=True, allow_optional=True,
577 allow_metas=['struct'])
578 if not base:
579 raise QAPIExprError(expr_info,
580 "Flat union '%s' must have a base"
581 % name)
582 base_members = find_base_members(base)
583 assert base_members
585 # The value of member 'discriminator' must name a non-optional
586 # member of the base struct.
587 check_name(expr_info, "Discriminator of flat union '%s'" % name,
588 discriminator)
589 discriminator_type = base_members.get(discriminator)
590 if not discriminator_type:
591 raise QAPIExprError(expr_info,
592 "Discriminator '%s' is not a member of base "
593 "struct '%s'"
594 % (discriminator, base))
595 enum_define = find_enum(discriminator_type)
596 allow_metas = ['struct']
597 # Do not allow string discriminator
598 if not enum_define:
599 raise QAPIExprError(expr_info,
600 "Discriminator '%s' must be of enumeration "
601 "type" % discriminator)
603 # Check every branch; don't allow an empty union
604 if len(members) == 0:
605 raise QAPIExprError(expr_info,
606 "Union '%s' cannot have empty 'data'" % name)
607 for (key, value) in members.items():
608 check_name(expr_info, "Member of union '%s'" % name, key)
610 # Each value must name a known type
611 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
612 value, allow_array=not base, allow_metas=allow_metas)
614 # If the discriminator names an enum type, then all members
615 # of 'data' must also be members of the enum type.
616 if enum_define:
617 if key not in enum_define['enum_values']:
618 raise QAPIExprError(expr_info,
619 "Discriminator value '%s' is not found in "
620 "enum '%s'" %
621 (key, enum_define["enum_name"]))
623 # If discriminator is user-defined, ensure all values are covered
624 if enum_define:
625 for value in enum_define['enum_values']:
626 if value not in members.keys():
627 raise QAPIExprError(expr_info,
628 "Union '%s' data missing '%s' branch"
629 % (name, value))
632 def check_alternate(expr, expr_info):
633 name = expr['alternate']
634 members = expr['data']
635 types_seen = {}
637 # Check every branch; require at least two branches
638 if len(members) < 2:
639 raise QAPIExprError(expr_info,
640 "Alternate '%s' should have at least two branches "
641 "in 'data'" % name)
642 for (key, value) in members.items():
643 check_name(expr_info, "Member of alternate '%s'" % name, key)
645 # Ensure alternates have no type conflicts.
646 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
647 value,
648 allow_metas=['built-in', 'union', 'struct', 'enum'])
649 qtype = find_alternate_member_qtype(value)
650 if not qtype:
651 raise QAPIExprError(expr_info,
652 "Alternate '%s' member '%s' cannot use "
653 "type '%s'" % (name, key, value))
654 if qtype in types_seen:
655 raise QAPIExprError(expr_info,
656 "Alternate '%s' member '%s' can't "
657 "be distinguished from member '%s'"
658 % (name, key, types_seen[qtype]))
659 types_seen[qtype] = key
662 def check_enum(expr, expr_info):
663 name = expr['enum']
664 members = expr.get('data')
665 prefix = expr.get('prefix')
667 if not isinstance(members, list):
668 raise QAPIExprError(expr_info,
669 "Enum '%s' requires an array for 'data'" % name)
670 if prefix is not None and not isinstance(prefix, str):
671 raise QAPIExprError(expr_info,
672 "Enum '%s' requires a string for 'prefix'" % name)
673 for member in members:
674 check_name(expr_info, "Member of enum '%s'" % name, member,
675 enum_member=True)
678 def check_struct(expr, expr_info):
679 name = expr['struct']
680 members = expr['data']
682 check_type(expr_info, "'data' for struct '%s'" % name, members,
683 allow_dict=True, allow_optional=True)
684 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
685 allow_metas=['struct'])
688 def check_keys(expr_elem, meta, required, optional=[]):
689 expr = expr_elem['expr']
690 info = expr_elem['info']
691 name = expr[meta]
692 if not isinstance(name, str):
693 raise QAPIExprError(info,
694 "'%s' key must have a string value" % meta)
695 required = required + [meta]
696 for (key, value) in expr.items():
697 if key not in required and key not in optional:
698 raise QAPIExprError(info,
699 "Unknown key '%s' in %s '%s'"
700 % (key, meta, name))
701 if (key == 'gen' or key == 'success-response') and value is not False:
702 raise QAPIExprError(info,
703 "'%s' of %s '%s' should only use false value"
704 % (key, meta, name))
705 if key == 'boxed' and value is not True:
706 raise QAPIExprError(info,
707 "'%s' of %s '%s' should only use true value"
708 % (key, meta, name))
709 for key in required:
710 if key not in expr:
711 raise QAPIExprError(info,
712 "Key '%s' is missing from %s '%s'"
713 % (key, meta, name))
716 def check_exprs(exprs):
717 global all_names
719 # Learn the types and check for valid expression keys
720 for builtin in builtin_types.keys():
721 all_names[builtin] = 'built-in'
722 for expr_elem in exprs:
723 expr = expr_elem['expr']
724 info = expr_elem['info']
725 if 'enum' in expr:
726 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
727 add_enum(expr['enum'], info, expr['data'])
728 elif 'union' in expr:
729 check_keys(expr_elem, 'union', ['data'],
730 ['base', 'discriminator'])
731 add_union(expr, info)
732 elif 'alternate' in expr:
733 check_keys(expr_elem, 'alternate', ['data'])
734 add_name(expr['alternate'], info, 'alternate')
735 elif 'struct' in expr:
736 check_keys(expr_elem, 'struct', ['data'], ['base'])
737 add_struct(expr, info)
738 elif 'command' in expr:
739 check_keys(expr_elem, 'command', [],
740 ['data', 'returns', 'gen', 'success-response', 'boxed'])
741 add_name(expr['command'], info, 'command')
742 elif 'event' in expr:
743 check_keys(expr_elem, 'event', [], ['data', 'boxed'])
744 add_name(expr['event'], info, 'event')
745 else:
746 raise QAPIExprError(expr_elem['info'],
747 "Expression is missing metatype")
749 # Try again for hidden UnionKind enum
750 for expr_elem in exprs:
751 expr = expr_elem['expr']
752 if 'union' in expr:
753 if not discriminator_find_enum_define(expr):
754 add_enum('%sKind' % expr['union'], expr_elem['info'],
755 implicit=True)
756 elif 'alternate' in expr:
757 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
758 implicit=True)
760 # Validate that exprs make sense
761 for expr_elem in exprs:
762 expr = expr_elem['expr']
763 info = expr_elem['info']
765 if 'enum' in expr:
766 check_enum(expr, info)
767 elif 'union' in expr:
768 check_union(expr, info)
769 elif 'alternate' in expr:
770 check_alternate(expr, info)
771 elif 'struct' in expr:
772 check_struct(expr, info)
773 elif 'command' in expr:
774 check_command(expr, info)
775 elif 'event' in expr:
776 check_event(expr, info)
777 else:
778 assert False, 'unexpected meta type'
780 return exprs
784 # Schema compiler frontend
787 class QAPISchemaEntity(object):
788 def __init__(self, name, info):
789 assert isinstance(name, str)
790 self.name = name
791 # For explicitly defined entities, info points to the (explicit)
792 # definition. For builtins (and their arrays), info is None.
793 # For implicitly defined entities, info points to a place that
794 # triggered the implicit definition (there may be more than one
795 # such place).
796 self.info = info
798 def c_name(self):
799 return c_name(self.name)
801 def check(self, schema):
802 pass
804 def is_implicit(self):
805 return not self.info
807 def visit(self, visitor):
808 pass
811 class QAPISchemaVisitor(object):
812 def visit_begin(self, schema):
813 pass
815 def visit_end(self):
816 pass
818 def visit_needed(self, entity):
819 # Default to visiting everything
820 return True
822 def visit_builtin_type(self, name, info, json_type):
823 pass
825 def visit_enum_type(self, name, info, values, prefix):
826 pass
828 def visit_array_type(self, name, info, element_type):
829 pass
831 def visit_object_type(self, name, info, base, members, variants):
832 pass
834 def visit_object_type_flat(self, name, info, members, variants):
835 pass
837 def visit_alternate_type(self, name, info, variants):
838 pass
840 def visit_command(self, name, info, arg_type, ret_type,
841 gen, success_response, boxed):
842 pass
844 def visit_event(self, name, info, arg_type, boxed):
845 pass
848 class QAPISchemaType(QAPISchemaEntity):
849 # Return the C type for common use.
850 # For the types we commonly box, this is a pointer type.
851 def c_type(self):
852 pass
854 # Return the C type to be used in a parameter list.
855 def c_param_type(self):
856 return self.c_type()
858 # Return the C type to be used where we suppress boxing.
859 def c_unboxed_type(self):
860 return self.c_type()
862 def json_type(self):
863 pass
865 def alternate_qtype(self):
866 json2qtype = {
867 'string': 'QTYPE_QSTRING',
868 'number': 'QTYPE_QFLOAT',
869 'int': 'QTYPE_QINT',
870 'boolean': 'QTYPE_QBOOL',
871 'object': 'QTYPE_QDICT'
873 return json2qtype.get(self.json_type())
876 class QAPISchemaBuiltinType(QAPISchemaType):
877 def __init__(self, name, json_type, c_type):
878 QAPISchemaType.__init__(self, name, None)
879 assert not c_type or isinstance(c_type, str)
880 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
881 'value')
882 self._json_type_name = json_type
883 self._c_type_name = c_type
885 def c_name(self):
886 return self.name
888 def c_type(self):
889 return self._c_type_name
891 def c_param_type(self):
892 if self.name == 'str':
893 return 'const ' + self._c_type_name
894 return self._c_type_name
896 def json_type(self):
897 return self._json_type_name
899 def visit(self, visitor):
900 visitor.visit_builtin_type(self.name, self.info, self.json_type())
903 class QAPISchemaEnumType(QAPISchemaType):
904 def __init__(self, name, info, values, prefix):
905 QAPISchemaType.__init__(self, name, info)
906 for v in values:
907 assert isinstance(v, QAPISchemaMember)
908 v.set_owner(name)
909 assert prefix is None or isinstance(prefix, str)
910 self.values = values
911 self.prefix = prefix
913 def check(self, schema):
914 seen = {}
915 for v in self.values:
916 v.check_clash(self.info, seen)
918 def is_implicit(self):
919 # See QAPISchema._make_implicit_enum_type()
920 return self.name.endswith('Kind')
922 def c_type(self):
923 return c_name(self.name)
925 def member_names(self):
926 return [v.name for v in self.values]
928 def json_type(self):
929 return 'string'
931 def visit(self, visitor):
932 visitor.visit_enum_type(self.name, self.info,
933 self.member_names(), self.prefix)
936 class QAPISchemaArrayType(QAPISchemaType):
937 def __init__(self, name, info, element_type):
938 QAPISchemaType.__init__(self, name, info)
939 assert isinstance(element_type, str)
940 self._element_type_name = element_type
941 self.element_type = None
943 def check(self, schema):
944 self.element_type = schema.lookup_type(self._element_type_name)
945 assert self.element_type
947 def is_implicit(self):
948 return True
950 def c_type(self):
951 return c_name(self.name) + pointer_suffix
953 def json_type(self):
954 return 'array'
956 def visit(self, visitor):
957 visitor.visit_array_type(self.name, self.info, self.element_type)
960 class QAPISchemaObjectType(QAPISchemaType):
961 def __init__(self, name, info, base, local_members, variants):
962 # struct has local_members, optional base, and no variants
963 # flat union has base, variants, and no local_members
964 # simple union has local_members, variants, and no base
965 QAPISchemaType.__init__(self, name, info)
966 assert base is None or isinstance(base, str)
967 for m in local_members:
968 assert isinstance(m, QAPISchemaObjectTypeMember)
969 m.set_owner(name)
970 if variants is not None:
971 assert isinstance(variants, QAPISchemaObjectTypeVariants)
972 variants.set_owner(name)
973 self._base_name = base
974 self.base = None
975 self.local_members = local_members
976 self.variants = variants
977 self.members = None
979 def check(self, schema):
980 if self.members is False: # check for cycles
981 raise QAPIExprError(self.info,
982 "Object %s contains itself" % self.name)
983 if self.members:
984 return
985 self.members = False # mark as being checked
986 seen = OrderedDict()
987 if self._base_name:
988 self.base = schema.lookup_type(self._base_name)
989 assert isinstance(self.base, QAPISchemaObjectType)
990 self.base.check(schema)
991 self.base.check_clash(schema, self.info, seen)
992 for m in self.local_members:
993 m.check(schema)
994 m.check_clash(self.info, seen)
995 self.members = seen.values()
996 if self.variants:
997 self.variants.check(schema, seen)
998 assert self.variants.tag_member in self.members
999 self.variants.check_clash(schema, self.info, seen)
1001 # Check that the members of this type do not cause duplicate JSON members,
1002 # and update seen to track the members seen so far. Report any errors
1003 # on behalf of info, which is not necessarily self.info
1004 def check_clash(self, schema, info, seen):
1005 assert not self.variants # not implemented
1006 for m in self.members:
1007 m.check_clash(info, seen)
1009 def is_implicit(self):
1010 # See QAPISchema._make_implicit_object_type(), as well as
1011 # _def_predefineds()
1012 return self.name.startswith('q_')
1014 def is_empty(self):
1015 assert self.members is not None
1016 return not self.members and not self.variants
1018 def c_name(self):
1019 assert self.name != 'q_empty'
1020 return QAPISchemaType.c_name(self)
1022 def c_type(self):
1023 assert not self.is_implicit()
1024 return c_name(self.name) + pointer_suffix
1026 def c_unboxed_type(self):
1027 return c_name(self.name)
1029 def json_type(self):
1030 return 'object'
1032 def visit(self, visitor):
1033 visitor.visit_object_type(self.name, self.info,
1034 self.base, self.local_members, self.variants)
1035 visitor.visit_object_type_flat(self.name, self.info,
1036 self.members, self.variants)
1039 class QAPISchemaMember(object):
1040 role = 'member'
1042 def __init__(self, name):
1043 assert isinstance(name, str)
1044 self.name = name
1045 self.owner = None
1047 def set_owner(self, name):
1048 assert not self.owner
1049 self.owner = name
1051 def check_clash(self, info, seen):
1052 cname = c_name(self.name)
1053 if cname.lower() != cname and self.owner not in case_whitelist:
1054 raise QAPIExprError(info,
1055 "%s should not use uppercase" % self.describe())
1056 if cname in seen:
1057 raise QAPIExprError(info,
1058 "%s collides with %s"
1059 % (self.describe(), seen[cname].describe()))
1060 seen[cname] = self
1062 def _pretty_owner(self):
1063 owner = self.owner
1064 if owner.startswith('q_obj_'):
1065 # See QAPISchema._make_implicit_object_type() - reverse the
1066 # mapping there to create a nice human-readable description
1067 owner = owner[6:]
1068 if owner.endswith('-arg'):
1069 return '(parameter of %s)' % owner[:-4]
1070 elif owner.endswith('-base'):
1071 return '(base of %s)' % owner[:-5]
1072 else:
1073 assert owner.endswith('-wrapper')
1074 # Unreachable and not implemented
1075 assert False
1076 if owner.endswith('Kind'):
1077 # See QAPISchema._make_implicit_enum_type()
1078 return '(branch of %s)' % owner[:-4]
1079 return '(%s of %s)' % (self.role, owner)
1081 def describe(self):
1082 return "'%s' %s" % (self.name, self._pretty_owner())
1085 class QAPISchemaObjectTypeMember(QAPISchemaMember):
1086 def __init__(self, name, typ, optional):
1087 QAPISchemaMember.__init__(self, name)
1088 assert isinstance(typ, str)
1089 assert isinstance(optional, bool)
1090 self._type_name = typ
1091 self.type = None
1092 self.optional = optional
1094 def check(self, schema):
1095 assert self.owner
1096 self.type = schema.lookup_type(self._type_name)
1097 assert self.type
1100 class QAPISchemaObjectTypeVariants(object):
1101 def __init__(self, tag_name, tag_member, variants):
1102 # Flat unions pass tag_name but not tag_member.
1103 # Simple unions and alternates pass tag_member but not tag_name.
1104 # After check(), tag_member is always set, and tag_name remains
1105 # a reliable witness of being used by a flat union.
1106 assert bool(tag_member) != bool(tag_name)
1107 assert (isinstance(tag_name, str) or
1108 isinstance(tag_member, QAPISchemaObjectTypeMember))
1109 assert len(variants) > 0
1110 for v in variants:
1111 assert isinstance(v, QAPISchemaObjectTypeVariant)
1112 self._tag_name = tag_name
1113 self.tag_member = tag_member
1114 self.variants = variants
1116 def set_owner(self, name):
1117 for v in self.variants:
1118 v.set_owner(name)
1120 def check(self, schema, seen):
1121 if not self.tag_member: # flat union
1122 self.tag_member = seen[c_name(self._tag_name)]
1123 assert self._tag_name == self.tag_member.name
1124 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1125 for v in self.variants:
1126 v.check(schema)
1127 # Union names must match enum values; alternate names are
1128 # checked separately. Use 'seen' to tell the two apart.
1129 if seen:
1130 assert v.name in self.tag_member.type.member_names()
1131 assert isinstance(v.type, QAPISchemaObjectType)
1132 v.type.check(schema)
1134 def check_clash(self, schema, info, seen):
1135 for v in self.variants:
1136 # Reset seen map for each variant, since qapi names from one
1137 # branch do not affect another branch
1138 assert isinstance(v.type, QAPISchemaObjectType)
1139 v.type.check_clash(schema, info, dict(seen))
1142 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1143 role = 'branch'
1145 def __init__(self, name, typ):
1146 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1149 class QAPISchemaAlternateType(QAPISchemaType):
1150 def __init__(self, name, info, variants):
1151 QAPISchemaType.__init__(self, name, info)
1152 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1153 assert variants.tag_member
1154 variants.set_owner(name)
1155 variants.tag_member.set_owner(self.name)
1156 self.variants = variants
1158 def check(self, schema):
1159 self.variants.tag_member.check(schema)
1160 # Not calling self.variants.check_clash(), because there's nothing
1161 # to clash with
1162 self.variants.check(schema, {})
1163 # Alternate branch names have no relation to the tag enum values;
1164 # so we have to check for potential name collisions ourselves.
1165 seen = {}
1166 for v in self.variants.variants:
1167 v.check_clash(self.info, seen)
1169 def c_type(self):
1170 return c_name(self.name) + pointer_suffix
1172 def json_type(self):
1173 return 'value'
1175 def visit(self, visitor):
1176 visitor.visit_alternate_type(self.name, self.info, self.variants)
1178 def is_empty(self):
1179 return False
1182 class QAPISchemaCommand(QAPISchemaEntity):
1183 def __init__(self, name, info, arg_type, ret_type, gen, success_response,
1184 boxed):
1185 QAPISchemaEntity.__init__(self, name, info)
1186 assert not arg_type or isinstance(arg_type, str)
1187 assert not ret_type or isinstance(ret_type, str)
1188 self._arg_type_name = arg_type
1189 self.arg_type = None
1190 self._ret_type_name = ret_type
1191 self.ret_type = None
1192 self.gen = gen
1193 self.success_response = success_response
1194 self.boxed = boxed
1196 def check(self, schema):
1197 if self._arg_type_name:
1198 self.arg_type = schema.lookup_type(self._arg_type_name)
1199 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1200 isinstance(self.arg_type, QAPISchemaAlternateType))
1201 self.arg_type.check(schema)
1202 if self.boxed:
1203 if self.arg_type.is_empty():
1204 raise QAPIExprError(self.info,
1205 "Cannot use 'boxed' with empty type")
1206 else:
1207 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1208 assert not self.arg_type.variants
1209 elif self.boxed:
1210 raise QAPIExprError(self.info,
1211 "Use of 'boxed' requires 'data'")
1212 if self._ret_type_name:
1213 self.ret_type = schema.lookup_type(self._ret_type_name)
1214 assert isinstance(self.ret_type, QAPISchemaType)
1216 def visit(self, visitor):
1217 visitor.visit_command(self.name, self.info,
1218 self.arg_type, self.ret_type,
1219 self.gen, self.success_response, self.boxed)
1222 class QAPISchemaEvent(QAPISchemaEntity):
1223 def __init__(self, name, info, arg_type, boxed):
1224 QAPISchemaEntity.__init__(self, name, info)
1225 assert not arg_type or isinstance(arg_type, str)
1226 self._arg_type_name = arg_type
1227 self.arg_type = None
1228 self.boxed = boxed
1230 def check(self, schema):
1231 if self._arg_type_name:
1232 self.arg_type = schema.lookup_type(self._arg_type_name)
1233 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1234 isinstance(self.arg_type, QAPISchemaAlternateType))
1235 self.arg_type.check(schema)
1236 if self.boxed:
1237 if self.arg_type.is_empty():
1238 raise QAPIExprError(self.info,
1239 "Cannot use 'boxed' with empty type")
1240 else:
1241 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1242 assert not self.arg_type.variants
1243 elif self.boxed:
1244 raise QAPIExprError(self.info,
1245 "Use of 'boxed' requires 'data'")
1247 def visit(self, visitor):
1248 visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
1251 class QAPISchema(object):
1252 def __init__(self, fname):
1253 try:
1254 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1255 self._entity_dict = {}
1256 self._predefining = True
1257 self._def_predefineds()
1258 self._predefining = False
1259 self._def_exprs()
1260 self.check()
1261 except (QAPISchemaError, QAPIExprError) as err:
1262 print >>sys.stderr, err
1263 exit(1)
1265 def _def_entity(self, ent):
1266 # Only the predefined types are allowed to not have info
1267 assert ent.info or self._predefining
1268 assert ent.name not in self._entity_dict
1269 self._entity_dict[ent.name] = ent
1271 def lookup_entity(self, name, typ=None):
1272 ent = self._entity_dict.get(name)
1273 if typ and not isinstance(ent, typ):
1274 return None
1275 return ent
1277 def lookup_type(self, name):
1278 return self.lookup_entity(name, QAPISchemaType)
1280 def _def_builtin_type(self, name, json_type, c_type):
1281 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
1282 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1283 # qapi-types.h from a single .c, all arrays of builtins must be
1284 # declared in the first file whether or not they are used. Nicer
1285 # would be to use lazy instantiation, while figuring out how to
1286 # avoid compilation issues with multiple qapi-types.h.
1287 self._make_array_type(name, None)
1289 def _def_predefineds(self):
1290 for t in [('str', 'string', 'char' + pointer_suffix),
1291 ('number', 'number', 'double'),
1292 ('int', 'int', 'int64_t'),
1293 ('int8', 'int', 'int8_t'),
1294 ('int16', 'int', 'int16_t'),
1295 ('int32', 'int', 'int32_t'),
1296 ('int64', 'int', 'int64_t'),
1297 ('uint8', 'int', 'uint8_t'),
1298 ('uint16', 'int', 'uint16_t'),
1299 ('uint32', 'int', 'uint32_t'),
1300 ('uint64', 'int', 'uint64_t'),
1301 ('size', 'int', 'uint64_t'),
1302 ('bool', 'boolean', 'bool'),
1303 ('any', 'value', 'QObject' + pointer_suffix)]:
1304 self._def_builtin_type(*t)
1305 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1306 None, [], None)
1307 self._def_entity(self.the_empty_object_type)
1308 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1309 'qstring', 'qdict', 'qlist',
1310 'qfloat', 'qbool'])
1311 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
1312 'QTYPE'))
1314 def _make_enum_members(self, values):
1315 return [QAPISchemaMember(v) for v in values]
1317 def _make_implicit_enum_type(self, name, info, values):
1318 # See also QAPISchemaObjectTypeMember._pretty_owner()
1319 name = name + 'Kind' # Use namespace reserved by add_name()
1320 self._def_entity(QAPISchemaEnumType(
1321 name, info, self._make_enum_members(values), None))
1322 return name
1324 def _make_array_type(self, element_type, info):
1325 name = element_type + 'List' # Use namespace reserved by add_name()
1326 if not self.lookup_type(name):
1327 self._def_entity(QAPISchemaArrayType(name, info, element_type))
1328 return name
1330 def _make_implicit_object_type(self, name, info, role, members):
1331 if not members:
1332 return None
1333 # See also QAPISchemaObjectTypeMember._pretty_owner()
1334 name = 'q_obj_%s-%s' % (name, role)
1335 if not self.lookup_entity(name, QAPISchemaObjectType):
1336 self._def_entity(QAPISchemaObjectType(name, info, None,
1337 members, None))
1338 return name
1340 def _def_enum_type(self, expr, info):
1341 name = expr['enum']
1342 data = expr['data']
1343 prefix = expr.get('prefix')
1344 self._def_entity(QAPISchemaEnumType(
1345 name, info, self._make_enum_members(data), prefix))
1347 def _make_member(self, name, typ, info):
1348 optional = False
1349 if name.startswith('*'):
1350 name = name[1:]
1351 optional = True
1352 if isinstance(typ, list):
1353 assert len(typ) == 1
1354 typ = self._make_array_type(typ[0], info)
1355 return QAPISchemaObjectTypeMember(name, typ, optional)
1357 def _make_members(self, data, info):
1358 return [self._make_member(key, value, info)
1359 for (key, value) in data.iteritems()]
1361 def _def_struct_type(self, expr, info):
1362 name = expr['struct']
1363 base = expr.get('base')
1364 data = expr['data']
1365 self._def_entity(QAPISchemaObjectType(name, info, base,
1366 self._make_members(data, info),
1367 None))
1369 def _make_variant(self, case, typ):
1370 return QAPISchemaObjectTypeVariant(case, typ)
1372 def _make_simple_variant(self, case, typ, info):
1373 if isinstance(typ, list):
1374 assert len(typ) == 1
1375 typ = self._make_array_type(typ[0], info)
1376 typ = self._make_implicit_object_type(
1377 typ, info, 'wrapper', [self._make_member('data', typ, info)])
1378 return QAPISchemaObjectTypeVariant(case, typ)
1380 def _def_union_type(self, expr, info):
1381 name = expr['union']
1382 data = expr['data']
1383 base = expr.get('base')
1384 tag_name = expr.get('discriminator')
1385 tag_member = None
1386 if isinstance(base, dict):
1387 base = (self._make_implicit_object_type(
1388 name, info, 'base', self._make_members(base, info)))
1389 if tag_name:
1390 variants = [self._make_variant(key, value)
1391 for (key, value) in data.iteritems()]
1392 members = []
1393 else:
1394 variants = [self._make_simple_variant(key, value, info)
1395 for (key, value) in data.iteritems()]
1396 typ = self._make_implicit_enum_type(name, info,
1397 [v.name for v in variants])
1398 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
1399 members = [tag_member]
1400 self._def_entity(
1401 QAPISchemaObjectType(name, info, base, members,
1402 QAPISchemaObjectTypeVariants(tag_name,
1403 tag_member,
1404 variants)))
1406 def _def_alternate_type(self, expr, info):
1407 name = expr['alternate']
1408 data = expr['data']
1409 variants = [self._make_variant(key, value)
1410 for (key, value) in data.iteritems()]
1411 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
1412 self._def_entity(
1413 QAPISchemaAlternateType(name, info,
1414 QAPISchemaObjectTypeVariants(None,
1415 tag_member,
1416 variants)))
1418 def _def_command(self, expr, info):
1419 name = expr['command']
1420 data = expr.get('data')
1421 rets = expr.get('returns')
1422 gen = expr.get('gen', True)
1423 success_response = expr.get('success-response', True)
1424 boxed = expr.get('boxed', False)
1425 if isinstance(data, OrderedDict):
1426 data = self._make_implicit_object_type(
1427 name, info, 'arg', self._make_members(data, info))
1428 if isinstance(rets, list):
1429 assert len(rets) == 1
1430 rets = self._make_array_type(rets[0], info)
1431 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1432 success_response, boxed))
1434 def _def_event(self, expr, info):
1435 name = expr['event']
1436 data = expr.get('data')
1437 boxed = expr.get('boxed', False)
1438 if isinstance(data, OrderedDict):
1439 data = self._make_implicit_object_type(
1440 name, info, 'arg', self._make_members(data, info))
1441 self._def_entity(QAPISchemaEvent(name, info, data, boxed))
1443 def _def_exprs(self):
1444 for expr_elem in self.exprs:
1445 expr = expr_elem['expr']
1446 info = expr_elem['info']
1447 if 'enum' in expr:
1448 self._def_enum_type(expr, info)
1449 elif 'struct' in expr:
1450 self._def_struct_type(expr, info)
1451 elif 'union' in expr:
1452 self._def_union_type(expr, info)
1453 elif 'alternate' in expr:
1454 self._def_alternate_type(expr, info)
1455 elif 'command' in expr:
1456 self._def_command(expr, info)
1457 elif 'event' in expr:
1458 self._def_event(expr, info)
1459 else:
1460 assert False
1462 def check(self):
1463 for ent in self._entity_dict.values():
1464 ent.check(self)
1466 def visit(self, visitor):
1467 visitor.visit_begin(self)
1468 for (name, entity) in sorted(self._entity_dict.items()):
1469 if visitor.visit_needed(entity):
1470 entity.visit(visitor)
1471 visitor.visit_end()
1475 # Code generation helpers
1478 def camel_case(name):
1479 new_name = ''
1480 first = True
1481 for ch in name:
1482 if ch in ['_', '-']:
1483 first = True
1484 elif first:
1485 new_name += ch.upper()
1486 first = False
1487 else:
1488 new_name += ch.lower()
1489 return new_name
1492 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1493 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1494 # ENUM24_Name -> ENUM24_NAME
1495 def camel_to_upper(value):
1496 c_fun_str = c_name(value, False)
1497 if value.isupper():
1498 return c_fun_str
1500 new_name = ''
1501 l = len(c_fun_str)
1502 for i in range(l):
1503 c = c_fun_str[i]
1504 # When c is upper and no "_" appears before, do more checks
1505 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
1506 if i < l - 1 and c_fun_str[i + 1].islower():
1507 new_name += '_'
1508 elif c_fun_str[i - 1].isdigit():
1509 new_name += '_'
1510 new_name += c
1511 return new_name.lstrip('_').upper()
1514 def c_enum_const(type_name, const_name, prefix=None):
1515 if prefix is not None:
1516 type_name = prefix
1517 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
1519 c_name_trans = string.maketrans('.-', '__')
1522 # Map @name to a valid C identifier.
1523 # If @protect, avoid returning certain ticklish identifiers (like
1524 # C keywords) by prepending "q_".
1526 # Used for converting 'name' from a 'name':'type' qapi definition
1527 # into a generated struct member, as well as converting type names
1528 # into substrings of a generated C function name.
1529 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1530 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1531 def c_name(name, protect=True):
1532 # ANSI X3J11/88-090, 3.1.1
1533 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1534 'default', 'do', 'double', 'else', 'enum', 'extern',
1535 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1536 'return', 'short', 'signed', 'sizeof', 'static',
1537 'struct', 'switch', 'typedef', 'union', 'unsigned',
1538 'void', 'volatile', 'while'])
1539 # ISO/IEC 9899:1999, 6.4.1
1540 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1541 # ISO/IEC 9899:2011, 6.4.1
1542 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1543 '_Noreturn', '_Static_assert', '_Thread_local'])
1544 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1545 # excluding _.*
1546 gcc_words = set(['asm', 'typeof'])
1547 # C++ ISO/IEC 14882:2003 2.11
1548 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1549 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1550 'namespace', 'new', 'operator', 'private', 'protected',
1551 'public', 'reinterpret_cast', 'static_cast', 'template',
1552 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1553 'using', 'virtual', 'wchar_t',
1554 # alternative representations
1555 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1556 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1557 # namespace pollution:
1558 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
1559 name = name.translate(c_name_trans)
1560 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1561 | cpp_words | polluted_words):
1562 return "q_" + name
1563 return name
1565 eatspace = '\033EATSPACE.'
1566 pointer_suffix = ' *' + eatspace
1569 def genindent(count):
1570 ret = ""
1571 for _ in range(count):
1572 ret += " "
1573 return ret
1575 indent_level = 0
1578 def push_indent(indent_amount=4):
1579 global indent_level
1580 indent_level += indent_amount
1583 def pop_indent(indent_amount=4):
1584 global indent_level
1585 indent_level -= indent_amount
1588 # Generate @code with @kwds interpolated.
1589 # Obey indent_level, and strip eatspace.
1590 def cgen(code, **kwds):
1591 raw = code % kwds
1592 if indent_level:
1593 indent = genindent(indent_level)
1594 # re.subn() lacks flags support before Python 2.7, use re.compile()
1595 raw = re.subn(re.compile("^.", re.MULTILINE),
1596 indent + r'\g<0>', raw)
1597 raw = raw[0]
1598 return re.sub(re.escape(eatspace) + ' *', '', raw)
1601 def mcgen(code, **kwds):
1602 if code[0] == '\n':
1603 code = code[1:]
1604 return cgen(code, **kwds)
1607 def guardname(filename):
1608 return c_name(filename, protect=False).upper()
1611 def guardstart(name):
1612 return mcgen('''
1614 #ifndef %(name)s
1615 #define %(name)s
1617 ''',
1618 name=guardname(name))
1621 def guardend(name):
1622 return mcgen('''
1624 #endif /* %(name)s */
1626 ''',
1627 name=guardname(name))
1630 def gen_enum_lookup(name, values, prefix=None):
1631 ret = mcgen('''
1633 const char *const %(c_name)s_lookup[] = {
1634 ''',
1635 c_name=c_name(name))
1636 for value in values:
1637 index = c_enum_const(name, value, prefix)
1638 ret += mcgen('''
1639 [%(index)s] = "%(value)s",
1640 ''',
1641 index=index, value=value)
1643 max_index = c_enum_const(name, '_MAX', prefix)
1644 ret += mcgen('''
1645 [%(max_index)s] = NULL,
1647 ''',
1648 max_index=max_index)
1649 return ret
1652 def gen_enum(name, values, prefix=None):
1653 # append automatically generated _MAX value
1654 enum_values = values + ['_MAX']
1656 ret = mcgen('''
1658 typedef enum %(c_name)s {
1659 ''',
1660 c_name=c_name(name))
1662 i = 0
1663 for value in enum_values:
1664 ret += mcgen('''
1665 %(c_enum)s = %(i)d,
1666 ''',
1667 c_enum=c_enum_const(name, value, prefix),
1668 i=i)
1669 i += 1
1671 ret += mcgen('''
1672 } %(c_name)s;
1673 ''',
1674 c_name=c_name(name))
1676 ret += mcgen('''
1678 extern const char *const %(c_name)s_lookup[];
1679 ''',
1680 c_name=c_name(name))
1681 return ret
1684 def gen_params(arg_type, boxed, extra):
1685 if not arg_type:
1686 assert not boxed
1687 return extra
1688 ret = ''
1689 sep = ''
1690 if boxed:
1691 ret += '%s arg' % arg_type.c_param_type()
1692 sep = ', '
1693 else:
1694 assert not arg_type.variants
1695 for memb in arg_type.members:
1696 ret += sep
1697 sep = ', '
1698 if memb.optional:
1699 ret += 'bool has_%s, ' % c_name(memb.name)
1700 ret += '%s %s' % (memb.type.c_param_type(),
1701 c_name(memb.name))
1702 if extra:
1703 ret += sep + extra
1704 return ret
1708 # Common command line parsing
1712 def parse_command_line(extra_options="", extra_long_options=[]):
1714 try:
1715 opts, args = getopt.gnu_getopt(sys.argv[1:],
1716 "chp:o:" + extra_options,
1717 ["source", "header", "prefix=",
1718 "output-dir="] + extra_long_options)
1719 except getopt.GetoptError as err:
1720 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1721 sys.exit(1)
1723 output_dir = ""
1724 prefix = ""
1725 do_c = False
1726 do_h = False
1727 extra_opts = []
1729 for oa in opts:
1730 o, a = oa
1731 if o in ("-p", "--prefix"):
1732 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1733 if match.end() != len(a):
1734 print >>sys.stderr, \
1735 "%s: 'funny character '%s' in argument of --prefix" \
1736 % (sys.argv[0], a[match.end()])
1737 sys.exit(1)
1738 prefix = a
1739 elif o in ("-o", "--output-dir"):
1740 output_dir = a + "/"
1741 elif o in ("-c", "--source"):
1742 do_c = True
1743 elif o in ("-h", "--header"):
1744 do_h = True
1745 else:
1746 extra_opts.append(oa)
1748 if not do_c and not do_h:
1749 do_c = True
1750 do_h = True
1752 if len(args) != 1:
1753 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1754 sys.exit(1)
1755 fname = args[0]
1757 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1760 # Generate output files with boilerplate
1764 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1765 c_comment, h_comment):
1766 guard = guardname(prefix + h_file)
1767 c_file = output_dir + prefix + c_file
1768 h_file = output_dir + prefix + h_file
1770 if output_dir:
1771 try:
1772 os.makedirs(output_dir)
1773 except os.error as e:
1774 if e.errno != errno.EEXIST:
1775 raise
1777 def maybe_open(really, name, opt):
1778 if really:
1779 return open(name, opt)
1780 else:
1781 import StringIO
1782 return StringIO.StringIO()
1784 fdef = maybe_open(do_c, c_file, 'w')
1785 fdecl = maybe_open(do_h, h_file, 'w')
1787 fdef.write(mcgen('''
1788 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1789 %(comment)s
1790 ''',
1791 comment=c_comment))
1793 fdecl.write(mcgen('''
1794 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1795 %(comment)s
1796 #ifndef %(guard)s
1797 #define %(guard)s
1799 ''',
1800 comment=h_comment, guard=guard))
1802 return (fdef, fdecl)
1805 def close_output(fdef, fdecl):
1806 fdecl.write('''
1807 #endif
1808 ''')
1809 fdecl.close()
1810 fdef.close()