console: add & use qemu_console_lookup_by_device_name
[qemu/rayw.git] / scripts / qapi.py
blob8497777d941a6e7e8edee230d598b4a029c6ea65
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 '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
76 enum_types = []
77 struct_types = []
78 union_types = []
79 events = []
80 all_names = {}
83 # Parsing the schema into expressions
87 def 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
96 class QAPISchemaError(Exception):
97 def __init__(self, schema, msg):
98 Exception.__init__(self)
99 self.fname = schema.fname
100 self.msg = msg
101 self.col = 1
102 self.line = schema.line
103 for ch in schema.src[schema.line_pos:schema.pos]:
104 if ch == '\t':
105 self.col = (self.col + 7) % 8 + 1
106 else:
107 self.col += 1
108 self.info = schema.incl_info
110 def __str__(self):
111 return error_path(self.info) + \
112 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
115 class QAPIExprError(Exception):
116 def __init__(self, expr_info, msg):
117 Exception.__init__(self)
118 assert expr_info
119 self.info = expr_info
120 self.msg = msg
122 def __str__(self):
123 return error_path(self.info['parent']) + \
124 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
127 class QAPISchemaParser(object):
129 def __init__(self, fp, previously_included=[], incl_info=None):
130 abs_fname = os.path.abspath(fp.name)
131 fname = fp.name
132 self.fname = fname
133 previously_included.append(abs_fname)
134 self.incl_info = incl_info
135 self.src = fp.read()
136 if self.src == '' or self.src[-1] != '\n':
137 self.src += '\n'
138 self.cursor = 0
139 self.line = 1
140 self.line_pos = 0
141 self.exprs = []
142 self.accept()
144 while self.tok is not None:
145 expr_info = {'file': fname, 'line': self.line,
146 'parent': self.incl_info}
147 expr = self.get_expr(False)
148 if isinstance(expr, dict) and "include" in expr:
149 if len(expr) != 1:
150 raise QAPIExprError(expr_info,
151 "Invalid 'include' directive")
152 include = expr["include"]
153 if not isinstance(include, str):
154 raise QAPIExprError(expr_info,
155 "Value of 'include' must be a string")
156 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
157 include)
158 # catch inclusion cycle
159 inf = expr_info
160 while inf:
161 if incl_abs_fname == os.path.abspath(inf['file']):
162 raise QAPIExprError(expr_info, "Inclusion loop for %s"
163 % include)
164 inf = inf['parent']
165 # skip multiple include of the same file
166 if incl_abs_fname in previously_included:
167 continue
168 try:
169 fobj = open(incl_abs_fname, 'r')
170 except IOError as e:
171 raise QAPIExprError(expr_info,
172 '%s: %s' % (e.strerror, include))
173 exprs_include = QAPISchemaParser(fobj, previously_included,
174 expr_info)
175 self.exprs.extend(exprs_include.exprs)
176 else:
177 expr_elem = {'expr': expr,
178 'info': expr_info}
179 self.exprs.append(expr_elem)
181 def accept(self):
182 while True:
183 self.tok = self.src[self.cursor]
184 self.pos = self.cursor
185 self.cursor += 1
186 self.val = None
188 if self.tok == '#':
189 self.cursor = self.src.find('\n', self.cursor)
190 elif self.tok in "{}:,[]":
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':
199 raise QAPISchemaError(self,
200 'Missing terminating "\'"')
201 if esc:
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
214 for _ in range(0, 4):
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,
236 "Unknown escape \\%s" % ch)
237 esc = False
238 elif ch == "\\":
239 esc = True
240 elif ch == "'":
241 self.val = string
242 return
243 else:
244 string += ch
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
257 elif self.tok == '\n':
258 if self.cursor == len(self.src):
259 self.tok = None
260 return
261 self.line += 1
262 self.line_pos = self.cursor
263 elif not self.tok.isspace():
264 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
266 def get_members(self):
267 expr = OrderedDict()
268 if self.tok == '}':
269 self.accept()
270 return expr
271 if self.tok != "'":
272 raise QAPISchemaError(self, 'Expected string or "}"')
273 while True:
274 key = self.val
275 self.accept()
276 if self.tok != ':':
277 raise QAPISchemaError(self, 'Expected ":"')
278 self.accept()
279 if key in expr:
280 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
281 expr[key] = self.get_expr(True)
282 if self.tok == '}':
283 self.accept()
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')
291 def get_values(self):
292 expr = []
293 if self.tok == ']':
294 self.accept()
295 return expr
296 if self.tok not in "{['tfn":
297 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
298 'boolean or "null"')
299 while True:
300 expr.append(self.get_expr(True))
301 if self.tok == ']':
302 self.accept()
303 return expr
304 if self.tok != ',':
305 raise QAPISchemaError(self, 'Expected "," or "]"')
306 self.accept()
308 def get_expr(self, nested):
309 if self.tok != '{' and not nested:
310 raise QAPISchemaError(self, 'Expected "{"')
311 if self.tok == '{':
312 self.accept()
313 expr = self.get_members()
314 elif self.tok == '[':
315 self.accept()
316 expr = self.get_values()
317 elif self.tok in "'tfn":
318 expr = self.val
319 self.accept()
320 else:
321 raise QAPISchemaError(self, 'Expected "{", "[" or string')
322 return expr
325 # Semantic analysis of schema expressions
326 # TODO fold into QAPISchema
327 # TODO catching name collisions in generated code would be nice
331 def 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']
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_fields = find_base_fields(base)
361 if not base_fields:
362 return None
364 discriminator_type = base_fields.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()
397 if not valid_name.match(membername) or \
398 c_name(membername, False).startswith('q_'):
399 raise QAPIExprError(expr_info,
400 "%s uses invalid name '%s'" % (source, name))
403 def add_name(name, info, meta, implicit=False):
404 global all_names
405 check_name(info, "'%s'" % meta, name)
406 # FIXME should reject names that differ only in '_' vs. '.'
407 # vs. '-', because they're liable to clash in generated C.
408 if name in all_names:
409 raise QAPIExprError(info,
410 "%s '%s' is already defined"
411 % (all_names[name], name))
412 if not implicit and (name.endswith('Kind') or name.endswith('List')):
413 raise QAPIExprError(info,
414 "%s '%s' should not end in '%s'"
415 % (meta, name, name[-4:]))
416 all_names[name] = meta
419 def add_struct(definition, info):
420 global struct_types
421 name = definition['struct']
422 add_name(name, info, 'struct')
423 struct_types.append(definition)
426 def find_struct(name):
427 global struct_types
428 for struct in struct_types:
429 if struct['struct'] == name:
430 return struct
431 return None
434 def add_union(definition, info):
435 global union_types
436 name = definition['union']
437 add_name(name, info, 'union')
438 union_types.append(definition)
441 def find_union(name):
442 global union_types
443 for union in union_types:
444 if union['union'] == name:
445 return union
446 return None
449 def add_enum(name, info, enum_values=None, implicit=False):
450 global enum_types
451 add_name(name, info, 'enum', implicit)
452 enum_types.append({"enum_name": name, "enum_values": enum_values})
455 def 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
463 def is_enum(name):
464 return find_enum(name) is not None
467 def check_type(expr_info, source, value, allow_array=False,
468 allow_dict=False, allow_optional=False,
469 allow_metas=[]):
470 global all_names
472 if value is None:
473 return
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]
486 # Check if type name for value is okay
487 if isinstance(value, str):
488 if value not in all_names:
489 raise QAPIExprError(expr_info,
490 "%s uses unknown type '%s'"
491 % (source, value))
492 if not all_names[value] in allow_metas:
493 raise QAPIExprError(expr_info,
494 "%s cannot use %s type '%s'"
495 % (source, all_names[value], value))
496 return
498 if not allow_dict:
499 raise QAPIExprError(expr_info,
500 "%s should be a type name" % source)
502 if not isinstance(value, OrderedDict):
503 raise QAPIExprError(expr_info,
504 "%s should be a dictionary or type name" % source)
506 # value is a dictionary, check that each member is okay
507 for (key, arg) in value.items():
508 check_name(expr_info, "Member of %s" % source, key,
509 allow_optional=allow_optional)
510 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
511 raise QAPIExprError(expr_info,
512 "Member of %s uses reserved name '%s'"
513 % (source, key))
514 # Todo: allow dictionaries to represent default values of
515 # an optional argument.
516 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
517 allow_array=True,
518 allow_metas=['built-in', 'union', 'alternate', 'struct',
519 'enum'])
522 def check_command(expr, expr_info):
523 name = expr['command']
525 check_type(expr_info, "'data' for command '%s'" % name,
526 expr.get('data'), allow_dict=True, allow_optional=True,
527 allow_metas=['struct'])
528 returns_meta = ['union', 'struct']
529 if name in returns_whitelist:
530 returns_meta += ['built-in', 'alternate', 'enum']
531 check_type(expr_info, "'returns' for command '%s'" % name,
532 expr.get('returns'), allow_array=True,
533 allow_optional=True, allow_metas=returns_meta)
536 def check_event(expr, expr_info):
537 global events
538 name = expr['event']
540 events.append(name)
541 check_type(expr_info, "'data' for event '%s'" % name,
542 expr.get('data'), allow_dict=True, allow_optional=True,
543 allow_metas=['struct'])
546 def check_union(expr, expr_info):
547 name = expr['union']
548 base = expr.get('base')
549 discriminator = expr.get('discriminator')
550 members = expr['data']
552 # Two types of unions, determined by discriminator.
554 # With no discriminator it is a simple union.
555 if discriminator is None:
556 enum_define = None
557 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
558 if base is not None:
559 raise QAPIExprError(expr_info,
560 "Simple union '%s' must not have a base"
561 % name)
563 # Else, it's a flat union.
564 else:
565 # The object must have a string member 'base'.
566 check_type(expr_info, "'base' for union '%s'" % name,
567 base, allow_metas=['struct'])
568 if not base:
569 raise QAPIExprError(expr_info,
570 "Flat union '%s' must have a base"
571 % name)
572 base_fields = find_base_fields(base)
573 assert base_fields
575 # The value of member 'discriminator' must name a non-optional
576 # member of the base struct.
577 check_name(expr_info, "Discriminator of flat union '%s'" % name,
578 discriminator)
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 "
583 "struct '%s'"
584 % (discriminator, base))
585 enum_define = find_enum(discriminator_type)
586 allow_metas = ['struct']
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)
593 # Check every branch; don't allow an empty union
594 if len(members) == 0:
595 raise QAPIExprError(expr_info,
596 "Union '%s' cannot have empty 'data'" % name)
597 for (key, value) in members.items():
598 check_name(expr_info, "Member of union '%s'" % name, key)
600 # Each value must name a known type
601 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
602 value, allow_array=not base, allow_metas=allow_metas)
604 # If the discriminator names an enum type, then all members
605 # of 'data' must also be members of the enum type.
606 if enum_define:
607 if key not in enum_define['enum_values']:
608 raise QAPIExprError(expr_info,
609 "Discriminator value '%s' is not found in "
610 "enum '%s'" %
611 (key, enum_define["enum_name"]))
614 def check_alternate(expr, expr_info):
615 name = expr['alternate']
616 members = expr['data']
617 types_seen = {}
619 # Check every branch; require at least two branches
620 if len(members) < 2:
621 raise QAPIExprError(expr_info,
622 "Alternate '%s' should have at least two branches "
623 "in 'data'" % name)
624 for (key, value) in members.items():
625 check_name(expr_info, "Member of alternate '%s'" % name, key)
627 # Ensure alternates have no type conflicts.
628 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
629 value,
630 allow_metas=['built-in', 'union', 'struct', 'enum'])
631 qtype = find_alternate_member_qtype(value)
632 if not qtype:
633 raise QAPIExprError(expr_info,
634 "Alternate '%s' member '%s' cannot use "
635 "type '%s'" % (name, key, value))
636 if qtype in types_seen:
637 raise QAPIExprError(expr_info,
638 "Alternate '%s' member '%s' can't "
639 "be distinguished from member '%s'"
640 % (name, key, types_seen[qtype]))
641 types_seen[qtype] = key
644 def check_enum(expr, expr_info):
645 name = expr['enum']
646 members = expr.get('data')
647 prefix = expr.get('prefix')
649 if not isinstance(members, list):
650 raise QAPIExprError(expr_info,
651 "Enum '%s' requires an array for 'data'" % name)
652 if prefix is not None and not isinstance(prefix, str):
653 raise QAPIExprError(expr_info,
654 "Enum '%s' requires a string for 'prefix'" % name)
655 for member in members:
656 check_name(expr_info, "Member of enum '%s'" % name, member,
657 enum_member=True)
660 def check_struct(expr, expr_info):
661 name = expr['struct']
662 members = expr['data']
664 check_type(expr_info, "'data' for struct '%s'" % name, members,
665 allow_dict=True, allow_optional=True)
666 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
667 allow_metas=['struct'])
670 def check_keys(expr_elem, meta, required, optional=[]):
671 expr = expr_elem['expr']
672 info = expr_elem['info']
673 name = expr[meta]
674 if not isinstance(name, str):
675 raise QAPIExprError(info,
676 "'%s' key must have a string value" % meta)
677 required = required + [meta]
678 for (key, value) in expr.items():
679 if key not in required and key not in optional:
680 raise QAPIExprError(info,
681 "Unknown key '%s' in %s '%s'"
682 % (key, meta, name))
683 if (key == 'gen' or key == 'success-response') and value is not False:
684 raise QAPIExprError(info,
685 "'%s' of %s '%s' should only use false value"
686 % (key, meta, name))
687 for key in required:
688 if key not in expr:
689 raise QAPIExprError(info,
690 "Key '%s' is missing from %s '%s'"
691 % (key, meta, name))
694 def check_exprs(exprs):
695 global all_names
697 # Learn the types and check for valid expression keys
698 for builtin in builtin_types.keys():
699 all_names[builtin] = 'built-in'
700 for expr_elem in exprs:
701 expr = expr_elem['expr']
702 info = expr_elem['info']
703 if 'enum' in expr:
704 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
705 add_enum(expr['enum'], info, expr['data'])
706 elif 'union' in expr:
707 check_keys(expr_elem, 'union', ['data'],
708 ['base', 'discriminator'])
709 add_union(expr, info)
710 elif 'alternate' in expr:
711 check_keys(expr_elem, 'alternate', ['data'])
712 add_name(expr['alternate'], info, 'alternate')
713 elif 'struct' in expr:
714 check_keys(expr_elem, 'struct', ['data'], ['base'])
715 add_struct(expr, info)
716 elif 'command' in expr:
717 check_keys(expr_elem, 'command', [],
718 ['data', 'returns', 'gen', 'success-response'])
719 add_name(expr['command'], info, 'command')
720 elif 'event' in expr:
721 check_keys(expr_elem, 'event', [], ['data'])
722 add_name(expr['event'], info, 'event')
723 else:
724 raise QAPIExprError(expr_elem['info'],
725 "Expression is missing metatype")
727 # Try again for hidden UnionKind enum
728 for expr_elem in exprs:
729 expr = expr_elem['expr']
730 if 'union' in expr:
731 if not discriminator_find_enum_define(expr):
732 add_enum('%sKind' % expr['union'], expr_elem['info'],
733 implicit=True)
734 elif 'alternate' in expr:
735 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
736 implicit=True)
738 # Validate that exprs make sense
739 for expr_elem in exprs:
740 expr = expr_elem['expr']
741 info = expr_elem['info']
743 if 'enum' in expr:
744 check_enum(expr, info)
745 elif 'union' in expr:
746 check_union(expr, info)
747 elif 'alternate' in expr:
748 check_alternate(expr, info)
749 elif 'struct' in expr:
750 check_struct(expr, info)
751 elif 'command' in expr:
752 check_command(expr, info)
753 elif 'event' in expr:
754 check_event(expr, info)
755 else:
756 assert False, 'unexpected meta type'
758 return exprs
762 # Schema compiler frontend
765 class QAPISchemaEntity(object):
766 def __init__(self, name, info):
767 assert isinstance(name, str)
768 self.name = name
769 # For explicitly defined entities, info points to the (explicit)
770 # definition. For builtins (and their arrays), info is None.
771 # For implicitly defined entities, info points to a place that
772 # triggered the implicit definition (there may be more than one
773 # such place).
774 self.info = info
776 def c_name(self):
777 return c_name(self.name)
779 def check(self, schema):
780 pass
782 def is_implicit(self):
783 return not self.info
785 def visit(self, visitor):
786 pass
789 class QAPISchemaVisitor(object):
790 def visit_begin(self, schema):
791 pass
793 def visit_end(self):
794 pass
796 def visit_needed(self, entity):
797 # Default to visiting everything
798 return True
800 def visit_builtin_type(self, name, info, json_type):
801 pass
803 def visit_enum_type(self, name, info, values, prefix):
804 pass
806 def visit_array_type(self, name, info, element_type):
807 pass
809 def visit_object_type(self, name, info, base, members, variants):
810 pass
812 def visit_object_type_flat(self, name, info, members, variants):
813 pass
815 def visit_alternate_type(self, name, info, variants):
816 pass
818 def visit_command(self, name, info, arg_type, ret_type,
819 gen, success_response):
820 pass
822 def visit_event(self, name, info, arg_type):
823 pass
826 class QAPISchemaType(QAPISchemaEntity):
827 def c_type(self, is_param=False, is_unboxed=False):
828 return c_name(self.name) + pointer_suffix
830 def c_null(self):
831 return 'NULL'
833 def json_type(self):
834 pass
836 def alternate_qtype(self):
837 json2qtype = {
838 'string': 'QTYPE_QSTRING',
839 'number': 'QTYPE_QFLOAT',
840 'int': 'QTYPE_QINT',
841 'boolean': 'QTYPE_QBOOL',
842 'object': 'QTYPE_QDICT'
844 return json2qtype.get(self.json_type())
847 class QAPISchemaBuiltinType(QAPISchemaType):
848 def __init__(self, name, json_type, c_type, c_null):
849 QAPISchemaType.__init__(self, name, None)
850 assert not c_type or isinstance(c_type, str)
851 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
852 'value')
853 self._json_type_name = json_type
854 self._c_type_name = c_type
855 self._c_null_val = c_null
857 def c_name(self):
858 return self.name
860 def c_type(self, is_param=False, is_unboxed=False):
861 if is_param and self.name == 'str':
862 return 'const ' + self._c_type_name
863 return self._c_type_name
865 def c_null(self):
866 return self._c_null_val
868 def json_type(self):
869 return self._json_type_name
871 def visit(self, visitor):
872 visitor.visit_builtin_type(self.name, self.info, self.json_type())
875 class QAPISchemaEnumType(QAPISchemaType):
876 def __init__(self, name, info, values, prefix):
877 QAPISchemaType.__init__(self, name, info)
878 for v in values:
879 assert isinstance(v, QAPISchemaMember)
880 v.set_owner(name)
881 assert prefix is None or isinstance(prefix, str)
882 self.values = values
883 self.prefix = prefix
885 def check(self, schema):
886 seen = {}
887 for v in self.values:
888 v.check_clash(self.info, seen)
890 def is_implicit(self):
891 # See QAPISchema._make_implicit_enum_type()
892 return self.name.endswith('Kind')
894 def c_type(self, is_param=False, is_unboxed=False):
895 return c_name(self.name)
897 def member_names(self):
898 return [v.name for v in self.values]
900 def c_null(self):
901 return c_enum_const(self.name, (self.member_names() + ['_MAX'])[0],
902 self.prefix)
904 def json_type(self):
905 return 'string'
907 def visit(self, visitor):
908 visitor.visit_enum_type(self.name, self.info,
909 self.member_names(), self.prefix)
912 class QAPISchemaArrayType(QAPISchemaType):
913 def __init__(self, name, info, element_type):
914 QAPISchemaType.__init__(self, name, info)
915 assert isinstance(element_type, str)
916 self._element_type_name = element_type
917 self.element_type = None
919 def check(self, schema):
920 self.element_type = schema.lookup_type(self._element_type_name)
921 assert self.element_type
923 def is_implicit(self):
924 return True
926 def json_type(self):
927 return 'array'
929 def visit(self, visitor):
930 visitor.visit_array_type(self.name, self.info, self.element_type)
933 class QAPISchemaObjectType(QAPISchemaType):
934 def __init__(self, name, info, base, local_members, variants):
935 # struct has local_members, optional base, and no variants
936 # flat union has base, variants, and no local_members
937 # simple union has local_members, variants, and no base
938 QAPISchemaType.__init__(self, name, info)
939 assert base is None or isinstance(base, str)
940 for m in local_members:
941 assert isinstance(m, QAPISchemaObjectTypeMember)
942 m.set_owner(name)
943 if variants is not None:
944 assert isinstance(variants, QAPISchemaObjectTypeVariants)
945 variants.set_owner(name)
946 self._base_name = base
947 self.base = None
948 self.local_members = local_members
949 self.variants = variants
950 self.members = None
952 def check(self, schema):
953 if self.members is False: # check for cycles
954 raise QAPIExprError(self.info,
955 "Object %s contains itself" % self.name)
956 if self.members:
957 return
958 self.members = False # mark as being checked
959 seen = OrderedDict()
960 if self._base_name:
961 self.base = schema.lookup_type(self._base_name)
962 assert isinstance(self.base, QAPISchemaObjectType)
963 self.base.check(schema)
964 self.base.check_clash(schema, self.info, seen)
965 for m in self.local_members:
966 m.check(schema)
967 m.check_clash(self.info, seen)
968 self.members = seen.values()
969 if self.variants:
970 self.variants.check(schema, seen)
971 assert self.variants.tag_member in self.members
972 self.variants.check_clash(schema, self.info, seen)
974 # Check that the members of this type do not cause duplicate JSON fields,
975 # and update seen to track the members seen so far. Report any errors
976 # on behalf of info, which is not necessarily self.info
977 def check_clash(self, schema, info, seen):
978 assert not self.variants # not implemented
979 for m in self.members:
980 m.check_clash(info, seen)
982 def is_implicit(self):
983 # See QAPISchema._make_implicit_object_type()
984 return self.name[0] == ':'
986 def c_name(self):
987 assert not self.is_implicit()
988 return QAPISchemaType.c_name(self)
990 def c_type(self, is_param=False, is_unboxed=False):
991 assert not self.is_implicit()
992 if is_unboxed:
993 return c_name(self.name)
994 return c_name(self.name) + pointer_suffix
996 def json_type(self):
997 return 'object'
999 def visit(self, visitor):
1000 visitor.visit_object_type(self.name, self.info,
1001 self.base, self.local_members, self.variants)
1002 visitor.visit_object_type_flat(self.name, self.info,
1003 self.members, self.variants)
1006 class QAPISchemaMember(object):
1007 role = 'member'
1009 def __init__(self, name):
1010 assert isinstance(name, str)
1011 self.name = name
1012 self.owner = None
1014 def set_owner(self, name):
1015 assert not self.owner
1016 self.owner = name
1018 def check_clash(self, info, seen):
1019 cname = c_name(self.name)
1020 if cname.lower() != cname and self.owner not in case_whitelist:
1021 raise QAPIExprError(info,
1022 "%s should not use uppercase" % self.describe())
1023 if cname in seen:
1024 raise QAPIExprError(info,
1025 "%s collides with %s"
1026 % (self.describe(), seen[cname].describe()))
1027 seen[cname] = self
1029 def _pretty_owner(self):
1030 owner = self.owner
1031 if owner.startswith(':obj-'):
1032 # See QAPISchema._make_implicit_object_type() - reverse the
1033 # mapping there to create a nice human-readable description
1034 owner = owner[5:]
1035 if owner.endswith('-arg'):
1036 return '(parameter of %s)' % owner[:-4]
1037 else:
1038 assert owner.endswith('-wrapper')
1039 # Unreachable and not implemented
1040 assert False
1041 if owner.endswith('Kind'):
1042 # See QAPISchema._make_implicit_enum_type()
1043 return '(branch of %s)' % owner[:-4]
1044 return '(%s of %s)' % (self.role, owner)
1046 def describe(self):
1047 return "'%s' %s" % (self.name, self._pretty_owner())
1050 class QAPISchemaObjectTypeMember(QAPISchemaMember):
1051 def __init__(self, name, typ, optional):
1052 QAPISchemaMember.__init__(self, name)
1053 assert isinstance(typ, str)
1054 assert isinstance(optional, bool)
1055 self._type_name = typ
1056 self.type = None
1057 self.optional = optional
1059 def check(self, schema):
1060 assert self.owner
1061 self.type = schema.lookup_type(self._type_name)
1062 assert self.type
1065 class QAPISchemaObjectTypeVariants(object):
1066 def __init__(self, tag_name, tag_member, variants):
1067 # Flat unions pass tag_name but not tag_member.
1068 # Simple unions and alternates pass tag_member but not tag_name.
1069 # After check(), tag_member is always set, and tag_name remains
1070 # a reliable witness of being used by a flat union.
1071 assert bool(tag_member) != bool(tag_name)
1072 assert (isinstance(tag_name, str) or
1073 isinstance(tag_member, QAPISchemaObjectTypeMember))
1074 assert len(variants) > 0
1075 for v in variants:
1076 assert isinstance(v, QAPISchemaObjectTypeVariant)
1077 self.tag_name = tag_name
1078 self.tag_member = tag_member
1079 self.variants = variants
1081 def set_owner(self, name):
1082 for v in self.variants:
1083 v.set_owner(name)
1085 def check(self, schema, seen):
1086 if not self.tag_member: # flat union
1087 self.tag_member = seen[c_name(self.tag_name)]
1088 assert self.tag_name == self.tag_member.name
1089 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1090 for v in self.variants:
1091 v.check(schema)
1092 # Union names must match enum values; alternate names are
1093 # checked separately. Use 'seen' to tell the two apart.
1094 if seen:
1095 assert v.name in self.tag_member.type.member_names()
1096 assert isinstance(v.type, QAPISchemaObjectType)
1097 v.type.check(schema)
1099 def check_clash(self, schema, info, seen):
1100 for v in self.variants:
1101 # Reset seen map for each variant, since qapi names from one
1102 # branch do not affect another branch
1103 assert isinstance(v.type, QAPISchemaObjectType)
1104 v.type.check_clash(schema, info, dict(seen))
1107 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1108 role = 'branch'
1110 def __init__(self, name, typ):
1111 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1113 # This function exists to support ugly simple union special cases
1114 # TODO get rid of them, and drop the function
1115 def simple_union_type(self):
1116 if (self.type.is_implicit() and
1117 isinstance(self.type, QAPISchemaObjectType)):
1118 assert len(self.type.members) == 1
1119 assert not self.type.variants
1120 return self.type.members[0].type
1121 return None
1124 class QAPISchemaAlternateType(QAPISchemaType):
1125 def __init__(self, name, info, variants):
1126 QAPISchemaType.__init__(self, name, info)
1127 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1128 assert not variants.tag_name
1129 variants.set_owner(name)
1130 variants.tag_member.set_owner(self.name)
1131 self.variants = variants
1133 def check(self, schema):
1134 self.variants.tag_member.check(schema)
1135 # Not calling self.variants.check_clash(), because there's nothing
1136 # to clash with
1137 self.variants.check(schema, {})
1138 # Alternate branch names have no relation to the tag enum values;
1139 # so we have to check for potential name collisions ourselves.
1140 seen = {}
1141 for v in self.variants.variants:
1142 v.check_clash(self.info, seen)
1144 def json_type(self):
1145 return 'value'
1147 def visit(self, visitor):
1148 visitor.visit_alternate_type(self.name, self.info, self.variants)
1151 class QAPISchemaCommand(QAPISchemaEntity):
1152 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1153 QAPISchemaEntity.__init__(self, name, info)
1154 assert not arg_type or isinstance(arg_type, str)
1155 assert not ret_type or isinstance(ret_type, str)
1156 self._arg_type_name = arg_type
1157 self.arg_type = None
1158 self._ret_type_name = ret_type
1159 self.ret_type = None
1160 self.gen = gen
1161 self.success_response = success_response
1163 def check(self, schema):
1164 if self._arg_type_name:
1165 self.arg_type = schema.lookup_type(self._arg_type_name)
1166 assert isinstance(self.arg_type, QAPISchemaObjectType)
1167 assert not self.arg_type.variants # not implemented
1168 if self._ret_type_name:
1169 self.ret_type = schema.lookup_type(self._ret_type_name)
1170 assert isinstance(self.ret_type, QAPISchemaType)
1172 def visit(self, visitor):
1173 visitor.visit_command(self.name, self.info,
1174 self.arg_type, self.ret_type,
1175 self.gen, self.success_response)
1178 class QAPISchemaEvent(QAPISchemaEntity):
1179 def __init__(self, name, info, arg_type):
1180 QAPISchemaEntity.__init__(self, name, info)
1181 assert not arg_type or isinstance(arg_type, str)
1182 self._arg_type_name = arg_type
1183 self.arg_type = None
1185 def check(self, schema):
1186 if self._arg_type_name:
1187 self.arg_type = schema.lookup_type(self._arg_type_name)
1188 assert isinstance(self.arg_type, QAPISchemaObjectType)
1189 assert not self.arg_type.variants # not implemented
1191 def visit(self, visitor):
1192 visitor.visit_event(self.name, self.info, self.arg_type)
1195 class QAPISchema(object):
1196 def __init__(self, fname):
1197 try:
1198 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1199 self._entity_dict = {}
1200 self._predefining = True
1201 self._def_predefineds()
1202 self._predefining = False
1203 self._def_exprs()
1204 self.check()
1205 except (QAPISchemaError, QAPIExprError) as err:
1206 print >>sys.stderr, err
1207 exit(1)
1209 def _def_entity(self, ent):
1210 # Only the predefined types are allowed to not have info
1211 assert ent.info or self._predefining
1212 assert ent.name not in self._entity_dict
1213 self._entity_dict[ent.name] = ent
1215 def lookup_entity(self, name, typ=None):
1216 ent = self._entity_dict.get(name)
1217 if typ and not isinstance(ent, typ):
1218 return None
1219 return ent
1221 def lookup_type(self, name):
1222 return self.lookup_entity(name, QAPISchemaType)
1224 def _def_builtin_type(self, name, json_type, c_type, c_null):
1225 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1226 c_type, c_null))
1227 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1228 # qapi-types.h from a single .c, all arrays of builtins must be
1229 # declared in the first file whether or not they are used. Nicer
1230 # would be to use lazy instantiation, while figuring out how to
1231 # avoid compilation issues with multiple qapi-types.h.
1232 self._make_array_type(name, None)
1234 def _def_predefineds(self):
1235 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1236 ('number', 'number', 'double', '0'),
1237 ('int', 'int', 'int64_t', '0'),
1238 ('int8', 'int', 'int8_t', '0'),
1239 ('int16', 'int', 'int16_t', '0'),
1240 ('int32', 'int', 'int32_t', '0'),
1241 ('int64', 'int', 'int64_t', '0'),
1242 ('uint8', 'int', 'uint8_t', '0'),
1243 ('uint16', 'int', 'uint16_t', '0'),
1244 ('uint32', 'int', 'uint32_t', '0'),
1245 ('uint64', 'int', 'uint64_t', '0'),
1246 ('size', 'int', 'uint64_t', '0'),
1247 ('bool', 'boolean', 'bool', 'false'),
1248 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
1249 self._def_builtin_type(*t)
1250 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1251 [], None)
1252 self._def_entity(self.the_empty_object_type)
1253 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1254 'qstring', 'qdict', 'qlist',
1255 'qfloat', 'qbool'])
1256 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
1257 'QTYPE'))
1259 def _make_enum_members(self, values):
1260 return [QAPISchemaMember(v) for v in values]
1262 def _make_implicit_enum_type(self, name, info, values):
1263 # See also QAPISchemaObjectTypeMember._pretty_owner()
1264 name = name + 'Kind' # Use namespace reserved by add_name()
1265 self._def_entity(QAPISchemaEnumType(
1266 name, info, self._make_enum_members(values), None))
1267 return name
1269 def _make_array_type(self, element_type, info):
1270 name = element_type + 'List' # Use namespace reserved by add_name()
1271 if not self.lookup_type(name):
1272 self._def_entity(QAPISchemaArrayType(name, info, element_type))
1273 return name
1275 def _make_implicit_object_type(self, name, info, role, members):
1276 if not members:
1277 return None
1278 # See also QAPISchemaObjectTypeMember._pretty_owner()
1279 name = ':obj-%s-%s' % (name, role)
1280 if not self.lookup_entity(name, QAPISchemaObjectType):
1281 self._def_entity(QAPISchemaObjectType(name, info, None,
1282 members, None))
1283 return name
1285 def _def_enum_type(self, expr, info):
1286 name = expr['enum']
1287 data = expr['data']
1288 prefix = expr.get('prefix')
1289 self._def_entity(QAPISchemaEnumType(
1290 name, info, self._make_enum_members(data), prefix))
1292 def _make_member(self, name, typ, info):
1293 optional = False
1294 if name.startswith('*'):
1295 name = name[1:]
1296 optional = True
1297 if isinstance(typ, list):
1298 assert len(typ) == 1
1299 typ = self._make_array_type(typ[0], info)
1300 return QAPISchemaObjectTypeMember(name, typ, optional)
1302 def _make_members(self, data, info):
1303 return [self._make_member(key, value, info)
1304 for (key, value) in data.iteritems()]
1306 def _def_struct_type(self, expr, info):
1307 name = expr['struct']
1308 base = expr.get('base')
1309 data = expr['data']
1310 self._def_entity(QAPISchemaObjectType(name, info, base,
1311 self._make_members(data, info),
1312 None))
1314 def _make_variant(self, case, typ):
1315 return QAPISchemaObjectTypeVariant(case, typ)
1317 def _make_simple_variant(self, case, typ, info):
1318 if isinstance(typ, list):
1319 assert len(typ) == 1
1320 typ = self._make_array_type(typ[0], info)
1321 typ = self._make_implicit_object_type(
1322 typ, info, 'wrapper', [self._make_member('data', typ, info)])
1323 return QAPISchemaObjectTypeVariant(case, typ)
1325 def _def_union_type(self, expr, info):
1326 name = expr['union']
1327 data = expr['data']
1328 base = expr.get('base')
1329 tag_name = expr.get('discriminator')
1330 tag_member = None
1331 if tag_name:
1332 variants = [self._make_variant(key, value)
1333 for (key, value) in data.iteritems()]
1334 members = []
1335 else:
1336 variants = [self._make_simple_variant(key, value, info)
1337 for (key, value) in data.iteritems()]
1338 typ = self._make_implicit_enum_type(name, info,
1339 [v.name for v in variants])
1340 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
1341 members = [tag_member]
1342 self._def_entity(
1343 QAPISchemaObjectType(name, info, base, members,
1344 QAPISchemaObjectTypeVariants(tag_name,
1345 tag_member,
1346 variants)))
1348 def _def_alternate_type(self, expr, info):
1349 name = expr['alternate']
1350 data = expr['data']
1351 variants = [self._make_variant(key, value)
1352 for (key, value) in data.iteritems()]
1353 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
1354 self._def_entity(
1355 QAPISchemaAlternateType(name, info,
1356 QAPISchemaObjectTypeVariants(None,
1357 tag_member,
1358 variants)))
1360 def _def_command(self, expr, info):
1361 name = expr['command']
1362 data = expr.get('data')
1363 rets = expr.get('returns')
1364 gen = expr.get('gen', True)
1365 success_response = expr.get('success-response', True)
1366 if isinstance(data, OrderedDict):
1367 data = self._make_implicit_object_type(
1368 name, info, 'arg', self._make_members(data, info))
1369 if isinstance(rets, list):
1370 assert len(rets) == 1
1371 rets = self._make_array_type(rets[0], info)
1372 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1373 success_response))
1375 def _def_event(self, expr, info):
1376 name = expr['event']
1377 data = expr.get('data')
1378 if isinstance(data, OrderedDict):
1379 data = self._make_implicit_object_type(
1380 name, info, 'arg', self._make_members(data, info))
1381 self._def_entity(QAPISchemaEvent(name, info, data))
1383 def _def_exprs(self):
1384 for expr_elem in self.exprs:
1385 expr = expr_elem['expr']
1386 info = expr_elem['info']
1387 if 'enum' in expr:
1388 self._def_enum_type(expr, info)
1389 elif 'struct' in expr:
1390 self._def_struct_type(expr, info)
1391 elif 'union' in expr:
1392 self._def_union_type(expr, info)
1393 elif 'alternate' in expr:
1394 self._def_alternate_type(expr, info)
1395 elif 'command' in expr:
1396 self._def_command(expr, info)
1397 elif 'event' in expr:
1398 self._def_event(expr, info)
1399 else:
1400 assert False
1402 def check(self):
1403 for ent in self._entity_dict.values():
1404 ent.check(self)
1406 def visit(self, visitor):
1407 visitor.visit_begin(self)
1408 for (name, entity) in sorted(self._entity_dict.items()):
1409 if visitor.visit_needed(entity):
1410 entity.visit(visitor)
1411 visitor.visit_end()
1415 # Code generation helpers
1418 def camel_case(name):
1419 new_name = ''
1420 first = True
1421 for ch in name:
1422 if ch in ['_', '-']:
1423 first = True
1424 elif first:
1425 new_name += ch.upper()
1426 first = False
1427 else:
1428 new_name += ch.lower()
1429 return new_name
1432 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1433 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1434 # ENUM24_Name -> ENUM24_NAME
1435 def camel_to_upper(value):
1436 c_fun_str = c_name(value, False)
1437 if value.isupper():
1438 return c_fun_str
1440 new_name = ''
1441 l = len(c_fun_str)
1442 for i in range(l):
1443 c = c_fun_str[i]
1444 # When c is upper and no "_" appears before, do more checks
1445 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
1446 if i < l - 1 and c_fun_str[i + 1].islower():
1447 new_name += '_'
1448 elif c_fun_str[i - 1].isdigit():
1449 new_name += '_'
1450 new_name += c
1451 return new_name.lstrip('_').upper()
1454 def c_enum_const(type_name, const_name, prefix=None):
1455 if prefix is not None:
1456 type_name = prefix
1457 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
1459 c_name_trans = string.maketrans('.-', '__')
1462 # Map @name to a valid C identifier.
1463 # If @protect, avoid returning certain ticklish identifiers (like
1464 # C keywords) by prepending "q_".
1466 # Used for converting 'name' from a 'name':'type' qapi definition
1467 # into a generated struct member, as well as converting type names
1468 # into substrings of a generated C function name.
1469 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1470 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1471 def c_name(name, protect=True):
1472 # ANSI X3J11/88-090, 3.1.1
1473 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1474 'default', 'do', 'double', 'else', 'enum', 'extern',
1475 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1476 'return', 'short', 'signed', 'sizeof', 'static',
1477 'struct', 'switch', 'typedef', 'union', 'unsigned',
1478 'void', 'volatile', 'while'])
1479 # ISO/IEC 9899:1999, 6.4.1
1480 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1481 # ISO/IEC 9899:2011, 6.4.1
1482 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1483 '_Noreturn', '_Static_assert', '_Thread_local'])
1484 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1485 # excluding _.*
1486 gcc_words = set(['asm', 'typeof'])
1487 # C++ ISO/IEC 14882:2003 2.11
1488 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1489 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1490 'namespace', 'new', 'operator', 'private', 'protected',
1491 'public', 'reinterpret_cast', 'static_cast', 'template',
1492 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1493 'using', 'virtual', 'wchar_t',
1494 # alternative representations
1495 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1496 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1497 # namespace pollution:
1498 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
1499 name = name.translate(c_name_trans)
1500 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1501 | cpp_words | polluted_words):
1502 return "q_" + name
1503 return name
1505 eatspace = '\033EATSPACE.'
1506 pointer_suffix = ' *' + eatspace
1509 def genindent(count):
1510 ret = ""
1511 for _ in range(count):
1512 ret += " "
1513 return ret
1515 indent_level = 0
1518 def push_indent(indent_amount=4):
1519 global indent_level
1520 indent_level += indent_amount
1523 def pop_indent(indent_amount=4):
1524 global indent_level
1525 indent_level -= indent_amount
1528 # Generate @code with @kwds interpolated.
1529 # Obey indent_level, and strip eatspace.
1530 def cgen(code, **kwds):
1531 raw = code % kwds
1532 if indent_level:
1533 indent = genindent(indent_level)
1534 # re.subn() lacks flags support before Python 2.7, use re.compile()
1535 raw = re.subn(re.compile("^.", re.MULTILINE),
1536 indent + r'\g<0>', raw)
1537 raw = raw[0]
1538 return re.sub(re.escape(eatspace) + ' *', '', raw)
1541 def mcgen(code, **kwds):
1542 if code[0] == '\n':
1543 code = code[1:]
1544 return cgen(code, **kwds)
1547 def guardname(filename):
1548 return c_name(filename, protect=False).upper()
1551 def guardstart(name):
1552 return mcgen('''
1554 #ifndef %(name)s
1555 #define %(name)s
1557 ''',
1558 name=guardname(name))
1561 def guardend(name):
1562 return mcgen('''
1564 #endif /* %(name)s */
1566 ''',
1567 name=guardname(name))
1570 def gen_enum_lookup(name, values, prefix=None):
1571 ret = mcgen('''
1573 const char *const %(c_name)s_lookup[] = {
1574 ''',
1575 c_name=c_name(name))
1576 for value in values:
1577 index = c_enum_const(name, value, prefix)
1578 ret += mcgen('''
1579 [%(index)s] = "%(value)s",
1580 ''',
1581 index=index, value=value)
1583 max_index = c_enum_const(name, '_MAX', prefix)
1584 ret += mcgen('''
1585 [%(max_index)s] = NULL,
1587 ''',
1588 max_index=max_index)
1589 return ret
1592 def gen_enum(name, values, prefix=None):
1593 # append automatically generated _MAX value
1594 enum_values = values + ['_MAX']
1596 ret = mcgen('''
1598 typedef enum %(c_name)s {
1599 ''',
1600 c_name=c_name(name))
1602 i = 0
1603 for value in enum_values:
1604 ret += mcgen('''
1605 %(c_enum)s = %(i)d,
1606 ''',
1607 c_enum=c_enum_const(name, value, prefix),
1608 i=i)
1609 i += 1
1611 ret += mcgen('''
1612 } %(c_name)s;
1613 ''',
1614 c_name=c_name(name))
1616 ret += mcgen('''
1618 extern const char *const %(c_name)s_lookup[];
1619 ''',
1620 c_name=c_name(name))
1621 return ret
1624 def gen_params(arg_type, extra):
1625 if not arg_type:
1626 return extra
1627 assert not arg_type.variants
1628 ret = ''
1629 sep = ''
1630 for memb in arg_type.members:
1631 ret += sep
1632 sep = ', '
1633 if memb.optional:
1634 ret += 'bool has_%s, ' % c_name(memb.name)
1635 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1636 if extra:
1637 ret += sep + extra
1638 return ret
1641 def gen_err_check(label='out', skiperr=False):
1642 if skiperr:
1643 return ''
1644 return mcgen('''
1645 if (err) {
1646 goto %(label)s;
1648 ''',
1649 label=label)
1652 def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False,
1653 label='out'):
1654 ret = ''
1655 if skiperr:
1656 errparg = 'NULL'
1657 else:
1658 errparg = '&err'
1660 for memb in members:
1661 if memb.optional:
1662 ret += mcgen('''
1663 if (visit_optional(v, "%(name)s", &%(prefix)shas_%(c_name)s)) {
1664 ''',
1665 prefix=prefix, c_name=c_name(memb.name),
1666 name=memb.name)
1667 push_indent()
1669 # Ugly: sometimes we need to cast away const
1670 if need_cast and memb.type.name == 'str':
1671 cast = '(char **)'
1672 else:
1673 cast = ''
1675 ret += mcgen('''
1676 visit_type_%(c_type)s(v, "%(name)s", %(cast)s&%(prefix)s%(c_name)s, %(errp)s);
1677 ''',
1678 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1679 c_name=c_name(memb.name), name=memb.name,
1680 errp=errparg)
1681 ret += gen_err_check(skiperr=skiperr, label=label)
1683 if memb.optional:
1684 pop_indent()
1685 ret += mcgen('''
1687 ''')
1688 return ret
1692 # Common command line parsing
1696 def parse_command_line(extra_options="", extra_long_options=[]):
1698 try:
1699 opts, args = getopt.gnu_getopt(sys.argv[1:],
1700 "chp:o:" + extra_options,
1701 ["source", "header", "prefix=",
1702 "output-dir="] + extra_long_options)
1703 except getopt.GetoptError as err:
1704 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1705 sys.exit(1)
1707 output_dir = ""
1708 prefix = ""
1709 do_c = False
1710 do_h = False
1711 extra_opts = []
1713 for oa in opts:
1714 o, a = oa
1715 if o in ("-p", "--prefix"):
1716 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1717 if match.end() != len(a):
1718 print >>sys.stderr, \
1719 "%s: 'funny character '%s' in argument of --prefix" \
1720 % (sys.argv[0], a[match.end()])
1721 sys.exit(1)
1722 prefix = a
1723 elif o in ("-o", "--output-dir"):
1724 output_dir = a + "/"
1725 elif o in ("-c", "--source"):
1726 do_c = True
1727 elif o in ("-h", "--header"):
1728 do_h = True
1729 else:
1730 extra_opts.append(oa)
1732 if not do_c and not do_h:
1733 do_c = True
1734 do_h = True
1736 if len(args) != 1:
1737 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1738 sys.exit(1)
1739 fname = args[0]
1741 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1744 # Generate output files with boilerplate
1748 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1749 c_comment, h_comment):
1750 guard = guardname(prefix + h_file)
1751 c_file = output_dir + prefix + c_file
1752 h_file = output_dir + prefix + h_file
1754 if output_dir:
1755 try:
1756 os.makedirs(output_dir)
1757 except os.error as e:
1758 if e.errno != errno.EEXIST:
1759 raise
1761 def maybe_open(really, name, opt):
1762 if really:
1763 return open(name, opt)
1764 else:
1765 import StringIO
1766 return StringIO.StringIO()
1768 fdef = maybe_open(do_c, c_file, 'w')
1769 fdecl = maybe_open(do_h, h_file, 'w')
1771 fdef.write(mcgen('''
1772 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1773 %(comment)s
1774 ''',
1775 comment=c_comment))
1777 fdecl.write(mcgen('''
1778 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1779 %(comment)s
1780 #ifndef %(guard)s
1781 #define %(guard)s
1783 ''',
1784 comment=h_comment, guard=guard))
1786 return (fdef, fdecl)
1789 def close_output(fdef, fdecl):
1790 fdecl.write('''
1791 #endif
1792 ''')
1793 fdecl.close()
1794 fdef.close()