io: use qemu_accept to ensure SOCK_CLOEXEC is set
[qemu/rayw.git] / scripts / qapi.py
blob6b2aa6e3dfe43c85fd13627eab8a16c35b7a02b3
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 'QapiErrorClass', # all members, visible through errors
70 'UuidInfo', # UUID, visible through query-uuid
71 'X86CPURegister32', # all members, visible indirectly through qom-get
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 base_struct_define = find_struct(base)
331 if not base_struct_define:
332 return None
333 return base_struct_define['data']
336 # Return the qtype of an alternate branch, or None on error.
337 def find_alternate_member_qtype(qapi_type):
338 if qapi_type in builtin_types:
339 return builtin_types[qapi_type]
340 elif find_struct(qapi_type):
341 return "QTYPE_QDICT"
342 elif find_enum(qapi_type):
343 return "QTYPE_QSTRING"
344 elif find_union(qapi_type):
345 return "QTYPE_QDICT"
346 return None
349 # Return the discriminator enum define if discriminator is specified as an
350 # enum type, otherwise return None.
351 def discriminator_find_enum_define(expr):
352 base = expr.get('base')
353 discriminator = expr.get('discriminator')
355 if not (discriminator and base):
356 return None
358 base_members = find_base_members(base)
359 if not base_members:
360 return None
362 discriminator_type = base_members.get(discriminator)
363 if not discriminator_type:
364 return None
366 return find_enum(discriminator_type)
369 # Names must be letters, numbers, -, and _. They must start with letter,
370 # except for downstream extensions which must start with __RFQDN_.
371 # Dots are only valid in the downstream extension prefix.
372 valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
373 '[a-zA-Z][a-zA-Z0-9_-]*$')
376 def check_name(expr_info, source, name, allow_optional=False,
377 enum_member=False):
378 global valid_name
379 membername = name
381 if not isinstance(name, str):
382 raise QAPIExprError(expr_info,
383 "%s requires a string name" % source)
384 if name.startswith('*'):
385 membername = name[1:]
386 if not allow_optional:
387 raise QAPIExprError(expr_info,
388 "%s does not allow optional name '%s'"
389 % (source, name))
390 # Enum members can start with a digit, because the generated C
391 # code always prefixes it with the enum name
392 if enum_member and membername[0].isdigit():
393 membername = 'D' + membername
394 # Reserve the entire 'q_' namespace for c_name()
395 if not valid_name.match(membername) or \
396 c_name(membername, False).startswith('q_'):
397 raise QAPIExprError(expr_info,
398 "%s uses invalid name '%s'" % (source, name))
401 def add_name(name, info, meta, implicit=False):
402 global all_names
403 check_name(info, "'%s'" % meta, name)
404 # FIXME should reject names that differ only in '_' vs. '.'
405 # vs. '-', because they're liable to clash in generated C.
406 if name in all_names:
407 raise QAPIExprError(info,
408 "%s '%s' is already defined"
409 % (all_names[name], name))
410 if not implicit and (name.endswith('Kind') or name.endswith('List')):
411 raise QAPIExprError(info,
412 "%s '%s' should not end in '%s'"
413 % (meta, name, name[-4:]))
414 all_names[name] = meta
417 def add_struct(definition, info):
418 global struct_types
419 name = definition['struct']
420 add_name(name, info, 'struct')
421 struct_types.append(definition)
424 def find_struct(name):
425 global struct_types
426 for struct in struct_types:
427 if struct['struct'] == name:
428 return struct
429 return None
432 def add_union(definition, info):
433 global union_types
434 name = definition['union']
435 add_name(name, info, 'union')
436 union_types.append(definition)
439 def find_union(name):
440 global union_types
441 for union in union_types:
442 if union['union'] == name:
443 return union
444 return None
447 def add_enum(name, info, enum_values=None, implicit=False):
448 global enum_types
449 add_name(name, info, 'enum', implicit)
450 enum_types.append({"enum_name": name, "enum_values": enum_values})
453 def find_enum(name):
454 global enum_types
455 for enum in enum_types:
456 if enum['enum_name'] == name:
457 return enum
458 return None
461 def is_enum(name):
462 return find_enum(name) is not None
465 def check_type(expr_info, source, value, allow_array=False,
466 allow_dict=False, allow_optional=False,
467 allow_metas=[]):
468 global all_names
470 if value is None:
471 return
473 # Check if array type for value is okay
474 if isinstance(value, list):
475 if not allow_array:
476 raise QAPIExprError(expr_info,
477 "%s cannot be an array" % source)
478 if len(value) != 1 or not isinstance(value[0], str):
479 raise QAPIExprError(expr_info,
480 "%s: array type must contain single type name"
481 % source)
482 value = value[0]
484 # Check if type name for value is okay
485 if isinstance(value, str):
486 if value not in all_names:
487 raise QAPIExprError(expr_info,
488 "%s uses unknown type '%s'"
489 % (source, value))
490 if not all_names[value] in allow_metas:
491 raise QAPIExprError(expr_info,
492 "%s cannot use %s type '%s'"
493 % (source, all_names[value], value))
494 return
496 if not allow_dict:
497 raise QAPIExprError(expr_info,
498 "%s should be a type name" % source)
500 if not isinstance(value, OrderedDict):
501 raise QAPIExprError(expr_info,
502 "%s should be a dictionary or type name" % source)
504 # value is a dictionary, check that each member is okay
505 for (key, arg) in value.items():
506 check_name(expr_info, "Member of %s" % source, key,
507 allow_optional=allow_optional)
508 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
509 raise QAPIExprError(expr_info,
510 "Member of %s uses reserved name '%s'"
511 % (source, key))
512 # Todo: allow dictionaries to represent default values of
513 # an optional argument.
514 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
515 allow_array=True,
516 allow_metas=['built-in', 'union', 'alternate', 'struct',
517 'enum'])
520 def check_command(expr, expr_info):
521 name = expr['command']
523 check_type(expr_info, "'data' for command '%s'" % name,
524 expr.get('data'), allow_dict=True, allow_optional=True,
525 allow_metas=['struct'])
526 returns_meta = ['union', 'struct']
527 if name in returns_whitelist:
528 returns_meta += ['built-in', 'alternate', 'enum']
529 check_type(expr_info, "'returns' for command '%s'" % name,
530 expr.get('returns'), allow_array=True,
531 allow_optional=True, allow_metas=returns_meta)
534 def check_event(expr, expr_info):
535 global events
536 name = expr['event']
538 events.append(name)
539 check_type(expr_info, "'data' for event '%s'" % name,
540 expr.get('data'), allow_dict=True, allow_optional=True,
541 allow_metas=['struct'])
544 def check_union(expr, expr_info):
545 name = expr['union']
546 base = expr.get('base')
547 discriminator = expr.get('discriminator')
548 members = expr['data']
550 # Two types of unions, determined by discriminator.
552 # With no discriminator it is a simple union.
553 if discriminator is None:
554 enum_define = None
555 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
556 if base is not None:
557 raise QAPIExprError(expr_info,
558 "Simple union '%s' must not have a base"
559 % name)
561 # Else, it's a flat union.
562 else:
563 # The object must have a string member 'base'.
564 check_type(expr_info, "'base' for union '%s'" % name,
565 base, allow_metas=['struct'])
566 if not base:
567 raise QAPIExprError(expr_info,
568 "Flat union '%s' must have a base"
569 % name)
570 base_members = find_base_members(base)
571 assert base_members
573 # The value of member 'discriminator' must name a non-optional
574 # member of the base struct.
575 check_name(expr_info, "Discriminator of flat union '%s'" % name,
576 discriminator)
577 discriminator_type = base_members.get(discriminator)
578 if not discriminator_type:
579 raise QAPIExprError(expr_info,
580 "Discriminator '%s' is not a member of base "
581 "struct '%s'"
582 % (discriminator, base))
583 enum_define = find_enum(discriminator_type)
584 allow_metas = ['struct']
585 # Do not allow string discriminator
586 if not enum_define:
587 raise QAPIExprError(expr_info,
588 "Discriminator '%s' must be of enumeration "
589 "type" % discriminator)
591 # Check every branch; don't allow an empty union
592 if len(members) == 0:
593 raise QAPIExprError(expr_info,
594 "Union '%s' cannot have empty 'data'" % name)
595 for (key, value) in members.items():
596 check_name(expr_info, "Member of union '%s'" % name, key)
598 # Each value must name a known type
599 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
600 value, allow_array=not base, allow_metas=allow_metas)
602 # If the discriminator names an enum type, then all members
603 # of 'data' must also be members of the enum type.
604 if enum_define:
605 if key not in enum_define['enum_values']:
606 raise QAPIExprError(expr_info,
607 "Discriminator value '%s' is not found in "
608 "enum '%s'" %
609 (key, enum_define["enum_name"]))
612 def check_alternate(expr, expr_info):
613 name = expr['alternate']
614 members = expr['data']
615 types_seen = {}
617 # Check every branch; require at least two branches
618 if len(members) < 2:
619 raise QAPIExprError(expr_info,
620 "Alternate '%s' should have at least two branches "
621 "in 'data'" % name)
622 for (key, value) in members.items():
623 check_name(expr_info, "Member of alternate '%s'" % name, key)
625 # Ensure alternates have no type conflicts.
626 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
627 value,
628 allow_metas=['built-in', 'union', 'struct', 'enum'])
629 qtype = find_alternate_member_qtype(value)
630 if not qtype:
631 raise QAPIExprError(expr_info,
632 "Alternate '%s' member '%s' cannot use "
633 "type '%s'" % (name, key, value))
634 if qtype in types_seen:
635 raise QAPIExprError(expr_info,
636 "Alternate '%s' member '%s' can't "
637 "be distinguished from member '%s'"
638 % (name, key, types_seen[qtype]))
639 types_seen[qtype] = key
642 def check_enum(expr, expr_info):
643 name = expr['enum']
644 members = expr.get('data')
645 prefix = expr.get('prefix')
647 if not isinstance(members, list):
648 raise QAPIExprError(expr_info,
649 "Enum '%s' requires an array for 'data'" % name)
650 if prefix is not None and not isinstance(prefix, str):
651 raise QAPIExprError(expr_info,
652 "Enum '%s' requires a string for 'prefix'" % name)
653 for member in members:
654 check_name(expr_info, "Member of enum '%s'" % name, member,
655 enum_member=True)
658 def check_struct(expr, expr_info):
659 name = expr['struct']
660 members = expr['data']
662 check_type(expr_info, "'data' for struct '%s'" % name, members,
663 allow_dict=True, allow_optional=True)
664 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
665 allow_metas=['struct'])
668 def check_keys(expr_elem, meta, required, optional=[]):
669 expr = expr_elem['expr']
670 info = expr_elem['info']
671 name = expr[meta]
672 if not isinstance(name, str):
673 raise QAPIExprError(info,
674 "'%s' key must have a string value" % meta)
675 required = required + [meta]
676 for (key, value) in expr.items():
677 if key not in required and key not in optional:
678 raise QAPIExprError(info,
679 "Unknown key '%s' in %s '%s'"
680 % (key, meta, name))
681 if (key == 'gen' or key == 'success-response') and value is not False:
682 raise QAPIExprError(info,
683 "'%s' of %s '%s' should only use false value"
684 % (key, meta, name))
685 for key in required:
686 if key not in expr:
687 raise QAPIExprError(info,
688 "Key '%s' is missing from %s '%s'"
689 % (key, meta, name))
692 def check_exprs(exprs):
693 global all_names
695 # Learn the types and check for valid expression keys
696 for builtin in builtin_types.keys():
697 all_names[builtin] = 'built-in'
698 for expr_elem in exprs:
699 expr = expr_elem['expr']
700 info = expr_elem['info']
701 if 'enum' in expr:
702 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
703 add_enum(expr['enum'], info, expr['data'])
704 elif 'union' in expr:
705 check_keys(expr_elem, 'union', ['data'],
706 ['base', 'discriminator'])
707 add_union(expr, info)
708 elif 'alternate' in expr:
709 check_keys(expr_elem, 'alternate', ['data'])
710 add_name(expr['alternate'], info, 'alternate')
711 elif 'struct' in expr:
712 check_keys(expr_elem, 'struct', ['data'], ['base'])
713 add_struct(expr, info)
714 elif 'command' in expr:
715 check_keys(expr_elem, 'command', [],
716 ['data', 'returns', 'gen', 'success-response'])
717 add_name(expr['command'], info, 'command')
718 elif 'event' in expr:
719 check_keys(expr_elem, 'event', [], ['data'])
720 add_name(expr['event'], info, 'event')
721 else:
722 raise QAPIExprError(expr_elem['info'],
723 "Expression is missing metatype")
725 # Try again for hidden UnionKind enum
726 for expr_elem in exprs:
727 expr = expr_elem['expr']
728 if 'union' in expr:
729 if not discriminator_find_enum_define(expr):
730 add_enum('%sKind' % expr['union'], expr_elem['info'],
731 implicit=True)
732 elif 'alternate' in expr:
733 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
734 implicit=True)
736 # Validate that exprs make sense
737 for expr_elem in exprs:
738 expr = expr_elem['expr']
739 info = expr_elem['info']
741 if 'enum' in expr:
742 check_enum(expr, info)
743 elif 'union' in expr:
744 check_union(expr, info)
745 elif 'alternate' in expr:
746 check_alternate(expr, info)
747 elif 'struct' in expr:
748 check_struct(expr, info)
749 elif 'command' in expr:
750 check_command(expr, info)
751 elif 'event' in expr:
752 check_event(expr, info)
753 else:
754 assert False, 'unexpected meta type'
756 return exprs
760 # Schema compiler frontend
763 class QAPISchemaEntity(object):
764 def __init__(self, name, info):
765 assert isinstance(name, str)
766 self.name = name
767 # For explicitly defined entities, info points to the (explicit)
768 # definition. For builtins (and their arrays), info is None.
769 # For implicitly defined entities, info points to a place that
770 # triggered the implicit definition (there may be more than one
771 # such place).
772 self.info = info
774 def c_name(self):
775 return c_name(self.name)
777 def check(self, schema):
778 pass
780 def is_implicit(self):
781 return not self.info
783 def visit(self, visitor):
784 pass
787 class QAPISchemaVisitor(object):
788 def visit_begin(self, schema):
789 pass
791 def visit_end(self):
792 pass
794 def visit_needed(self, entity):
795 # Default to visiting everything
796 return True
798 def visit_builtin_type(self, name, info, json_type):
799 pass
801 def visit_enum_type(self, name, info, values, prefix):
802 pass
804 def visit_array_type(self, name, info, element_type):
805 pass
807 def visit_object_type(self, name, info, base, members, variants):
808 pass
810 def visit_object_type_flat(self, name, info, members, variants):
811 pass
813 def visit_alternate_type(self, name, info, variants):
814 pass
816 def visit_command(self, name, info, arg_type, ret_type,
817 gen, success_response):
818 pass
820 def visit_event(self, name, info, arg_type):
821 pass
824 class QAPISchemaType(QAPISchemaEntity):
825 def c_type(self, is_param=False, is_unboxed=False):
826 return c_name(self.name) + pointer_suffix
828 def c_null(self):
829 return 'NULL'
831 def json_type(self):
832 pass
834 def alternate_qtype(self):
835 json2qtype = {
836 'string': 'QTYPE_QSTRING',
837 'number': 'QTYPE_QFLOAT',
838 'int': 'QTYPE_QINT',
839 'boolean': 'QTYPE_QBOOL',
840 'object': 'QTYPE_QDICT'
842 return json2qtype.get(self.json_type())
845 class QAPISchemaBuiltinType(QAPISchemaType):
846 def __init__(self, name, json_type, c_type, c_null):
847 QAPISchemaType.__init__(self, name, None)
848 assert not c_type or isinstance(c_type, str)
849 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
850 'value')
851 self._json_type_name = json_type
852 self._c_type_name = c_type
853 self._c_null_val = c_null
855 def c_name(self):
856 return self.name
858 def c_type(self, is_param=False, is_unboxed=False):
859 if is_param and self.name == 'str':
860 return 'const ' + self._c_type_name
861 return self._c_type_name
863 def c_null(self):
864 return self._c_null_val
866 def json_type(self):
867 return self._json_type_name
869 def visit(self, visitor):
870 visitor.visit_builtin_type(self.name, self.info, self.json_type())
873 class QAPISchemaEnumType(QAPISchemaType):
874 def __init__(self, name, info, values, prefix):
875 QAPISchemaType.__init__(self, name, info)
876 for v in values:
877 assert isinstance(v, QAPISchemaMember)
878 v.set_owner(name)
879 assert prefix is None or isinstance(prefix, str)
880 self.values = values
881 self.prefix = prefix
883 def check(self, schema):
884 seen = {}
885 for v in self.values:
886 v.check_clash(self.info, seen)
888 def is_implicit(self):
889 # See QAPISchema._make_implicit_enum_type()
890 return self.name.endswith('Kind')
892 def c_type(self, is_param=False, is_unboxed=False):
893 return c_name(self.name)
895 def member_names(self):
896 return [v.name for v in self.values]
898 def c_null(self):
899 return c_enum_const(self.name, (self.member_names() + ['_MAX'])[0],
900 self.prefix)
902 def json_type(self):
903 return 'string'
905 def visit(self, visitor):
906 visitor.visit_enum_type(self.name, self.info,
907 self.member_names(), self.prefix)
910 class QAPISchemaArrayType(QAPISchemaType):
911 def __init__(self, name, info, element_type):
912 QAPISchemaType.__init__(self, name, info)
913 assert isinstance(element_type, str)
914 self._element_type_name = element_type
915 self.element_type = None
917 def check(self, schema):
918 self.element_type = schema.lookup_type(self._element_type_name)
919 assert self.element_type
921 def is_implicit(self):
922 return True
924 def json_type(self):
925 return 'array'
927 def visit(self, visitor):
928 visitor.visit_array_type(self.name, self.info, self.element_type)
931 class QAPISchemaObjectType(QAPISchemaType):
932 def __init__(self, name, info, base, local_members, variants):
933 # struct has local_members, optional base, and no variants
934 # flat union has base, variants, and no local_members
935 # simple union has local_members, variants, and no base
936 QAPISchemaType.__init__(self, name, info)
937 assert base is None or isinstance(base, str)
938 for m in local_members:
939 assert isinstance(m, QAPISchemaObjectTypeMember)
940 m.set_owner(name)
941 if variants is not None:
942 assert isinstance(variants, QAPISchemaObjectTypeVariants)
943 variants.set_owner(name)
944 self._base_name = base
945 self.base = None
946 self.local_members = local_members
947 self.variants = variants
948 self.members = None
950 def check(self, schema):
951 if self.members is False: # check for cycles
952 raise QAPIExprError(self.info,
953 "Object %s contains itself" % self.name)
954 if self.members:
955 return
956 self.members = False # mark as being checked
957 seen = OrderedDict()
958 if self._base_name:
959 self.base = schema.lookup_type(self._base_name)
960 assert isinstance(self.base, QAPISchemaObjectType)
961 self.base.check(schema)
962 self.base.check_clash(schema, self.info, seen)
963 for m in self.local_members:
964 m.check(schema)
965 m.check_clash(self.info, seen)
966 self.members = seen.values()
967 if self.variants:
968 self.variants.check(schema, seen)
969 assert self.variants.tag_member in self.members
970 self.variants.check_clash(schema, self.info, seen)
972 # Check that the members of this type do not cause duplicate JSON members,
973 # and update seen to track the members seen so far. Report any errors
974 # on behalf of info, which is not necessarily self.info
975 def check_clash(self, schema, info, seen):
976 assert not self.variants # not implemented
977 for m in self.members:
978 m.check_clash(info, seen)
980 def is_implicit(self):
981 # See QAPISchema._make_implicit_object_type()
982 return self.name[0] == ':'
984 def c_name(self):
985 assert not self.is_implicit()
986 return QAPISchemaType.c_name(self)
988 def c_type(self, is_param=False, is_unboxed=False):
989 assert not self.is_implicit()
990 if is_unboxed:
991 return c_name(self.name)
992 return c_name(self.name) + pointer_suffix
994 def json_type(self):
995 return 'object'
997 def visit(self, visitor):
998 visitor.visit_object_type(self.name, self.info,
999 self.base, self.local_members, self.variants)
1000 visitor.visit_object_type_flat(self.name, self.info,
1001 self.members, self.variants)
1004 class QAPISchemaMember(object):
1005 role = 'member'
1007 def __init__(self, name):
1008 assert isinstance(name, str)
1009 self.name = name
1010 self.owner = None
1012 def set_owner(self, name):
1013 assert not self.owner
1014 self.owner = name
1016 def check_clash(self, info, seen):
1017 cname = c_name(self.name)
1018 if cname.lower() != cname and self.owner not in case_whitelist:
1019 raise QAPIExprError(info,
1020 "%s should not use uppercase" % self.describe())
1021 if cname in seen:
1022 raise QAPIExprError(info,
1023 "%s collides with %s"
1024 % (self.describe(), seen[cname].describe()))
1025 seen[cname] = self
1027 def _pretty_owner(self):
1028 owner = self.owner
1029 if owner.startswith(':obj-'):
1030 # See QAPISchema._make_implicit_object_type() - reverse the
1031 # mapping there to create a nice human-readable description
1032 owner = owner[5:]
1033 if owner.endswith('-arg'):
1034 return '(parameter of %s)' % owner[:-4]
1035 else:
1036 assert owner.endswith('-wrapper')
1037 # Unreachable and not implemented
1038 assert False
1039 if owner.endswith('Kind'):
1040 # See QAPISchema._make_implicit_enum_type()
1041 return '(branch of %s)' % owner[:-4]
1042 return '(%s of %s)' % (self.role, owner)
1044 def describe(self):
1045 return "'%s' %s" % (self.name, self._pretty_owner())
1048 class QAPISchemaObjectTypeMember(QAPISchemaMember):
1049 def __init__(self, name, typ, optional):
1050 QAPISchemaMember.__init__(self, name)
1051 assert isinstance(typ, str)
1052 assert isinstance(optional, bool)
1053 self._type_name = typ
1054 self.type = None
1055 self.optional = optional
1057 def check(self, schema):
1058 assert self.owner
1059 self.type = schema.lookup_type(self._type_name)
1060 assert self.type
1063 class QAPISchemaObjectTypeVariants(object):
1064 def __init__(self, tag_name, tag_member, variants):
1065 # Flat unions pass tag_name but not tag_member.
1066 # Simple unions and alternates pass tag_member but not tag_name.
1067 # After check(), tag_member is always set, and tag_name remains
1068 # a reliable witness of being used by a flat union.
1069 assert bool(tag_member) != bool(tag_name)
1070 assert (isinstance(tag_name, str) or
1071 isinstance(tag_member, QAPISchemaObjectTypeMember))
1072 assert len(variants) > 0
1073 for v in variants:
1074 assert isinstance(v, QAPISchemaObjectTypeVariant)
1075 self.tag_name = tag_name
1076 self.tag_member = tag_member
1077 self.variants = variants
1079 def set_owner(self, name):
1080 for v in self.variants:
1081 v.set_owner(name)
1083 def check(self, schema, seen):
1084 if not self.tag_member: # flat union
1085 self.tag_member = seen[c_name(self.tag_name)]
1086 assert self.tag_name == self.tag_member.name
1087 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1088 for v in self.variants:
1089 v.check(schema)
1090 # Union names must match enum values; alternate names are
1091 # checked separately. Use 'seen' to tell the two apart.
1092 if seen:
1093 assert v.name in self.tag_member.type.member_names()
1094 assert isinstance(v.type, QAPISchemaObjectType)
1095 v.type.check(schema)
1097 def check_clash(self, schema, info, seen):
1098 for v in self.variants:
1099 # Reset seen map for each variant, since qapi names from one
1100 # branch do not affect another branch
1101 assert isinstance(v.type, QAPISchemaObjectType)
1102 v.type.check_clash(schema, info, dict(seen))
1105 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1106 role = 'branch'
1108 def __init__(self, name, typ):
1109 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1111 # This function exists to support ugly simple union special cases
1112 # TODO get rid of them, and drop the function
1113 def simple_union_type(self):
1114 if (self.type.is_implicit() and
1115 isinstance(self.type, QAPISchemaObjectType)):
1116 assert len(self.type.members) == 1
1117 assert not self.type.variants
1118 return self.type.members[0].type
1119 return None
1122 class QAPISchemaAlternateType(QAPISchemaType):
1123 def __init__(self, name, info, variants):
1124 QAPISchemaType.__init__(self, name, info)
1125 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1126 assert not variants.tag_name
1127 variants.set_owner(name)
1128 variants.tag_member.set_owner(self.name)
1129 self.variants = variants
1131 def check(self, schema):
1132 self.variants.tag_member.check(schema)
1133 # Not calling self.variants.check_clash(), because there's nothing
1134 # to clash with
1135 self.variants.check(schema, {})
1136 # Alternate branch names have no relation to the tag enum values;
1137 # so we have to check for potential name collisions ourselves.
1138 seen = {}
1139 for v in self.variants.variants:
1140 v.check_clash(self.info, seen)
1142 def json_type(self):
1143 return 'value'
1145 def visit(self, visitor):
1146 visitor.visit_alternate_type(self.name, self.info, self.variants)
1149 class QAPISchemaCommand(QAPISchemaEntity):
1150 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1151 QAPISchemaEntity.__init__(self, name, info)
1152 assert not arg_type or isinstance(arg_type, str)
1153 assert not ret_type or isinstance(ret_type, str)
1154 self._arg_type_name = arg_type
1155 self.arg_type = None
1156 self._ret_type_name = ret_type
1157 self.ret_type = None
1158 self.gen = gen
1159 self.success_response = success_response
1161 def check(self, schema):
1162 if self._arg_type_name:
1163 self.arg_type = schema.lookup_type(self._arg_type_name)
1164 assert isinstance(self.arg_type, QAPISchemaObjectType)
1165 assert not self.arg_type.variants # not implemented
1166 if self._ret_type_name:
1167 self.ret_type = schema.lookup_type(self._ret_type_name)
1168 assert isinstance(self.ret_type, QAPISchemaType)
1170 def visit(self, visitor):
1171 visitor.visit_command(self.name, self.info,
1172 self.arg_type, self.ret_type,
1173 self.gen, self.success_response)
1176 class QAPISchemaEvent(QAPISchemaEntity):
1177 def __init__(self, name, info, arg_type):
1178 QAPISchemaEntity.__init__(self, name, info)
1179 assert not arg_type or isinstance(arg_type, str)
1180 self._arg_type_name = arg_type
1181 self.arg_type = None
1183 def check(self, schema):
1184 if self._arg_type_name:
1185 self.arg_type = schema.lookup_type(self._arg_type_name)
1186 assert isinstance(self.arg_type, QAPISchemaObjectType)
1187 assert not self.arg_type.variants # not implemented
1189 def visit(self, visitor):
1190 visitor.visit_event(self.name, self.info, self.arg_type)
1193 class QAPISchema(object):
1194 def __init__(self, fname):
1195 try:
1196 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1197 self._entity_dict = {}
1198 self._predefining = True
1199 self._def_predefineds()
1200 self._predefining = False
1201 self._def_exprs()
1202 self.check()
1203 except (QAPISchemaError, QAPIExprError) as err:
1204 print >>sys.stderr, err
1205 exit(1)
1207 def _def_entity(self, ent):
1208 # Only the predefined types are allowed to not have info
1209 assert ent.info or self._predefining
1210 assert ent.name not in self._entity_dict
1211 self._entity_dict[ent.name] = ent
1213 def lookup_entity(self, name, typ=None):
1214 ent = self._entity_dict.get(name)
1215 if typ and not isinstance(ent, typ):
1216 return None
1217 return ent
1219 def lookup_type(self, name):
1220 return self.lookup_entity(name, QAPISchemaType)
1222 def _def_builtin_type(self, name, json_type, c_type, c_null):
1223 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1224 c_type, c_null))
1225 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1226 # qapi-types.h from a single .c, all arrays of builtins must be
1227 # declared in the first file whether or not they are used. Nicer
1228 # would be to use lazy instantiation, while figuring out how to
1229 # avoid compilation issues with multiple qapi-types.h.
1230 self._make_array_type(name, None)
1232 def _def_predefineds(self):
1233 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1234 ('number', 'number', 'double', '0'),
1235 ('int', 'int', 'int64_t', '0'),
1236 ('int8', 'int', 'int8_t', '0'),
1237 ('int16', 'int', 'int16_t', '0'),
1238 ('int32', 'int', 'int32_t', '0'),
1239 ('int64', 'int', 'int64_t', '0'),
1240 ('uint8', 'int', 'uint8_t', '0'),
1241 ('uint16', 'int', 'uint16_t', '0'),
1242 ('uint32', 'int', 'uint32_t', '0'),
1243 ('uint64', 'int', 'uint64_t', '0'),
1244 ('size', 'int', 'uint64_t', '0'),
1245 ('bool', 'boolean', 'bool', 'false'),
1246 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
1247 self._def_builtin_type(*t)
1248 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1249 [], None)
1250 self._def_entity(self.the_empty_object_type)
1251 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1252 'qstring', 'qdict', 'qlist',
1253 'qfloat', 'qbool'])
1254 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
1255 'QTYPE'))
1257 def _make_enum_members(self, values):
1258 return [QAPISchemaMember(v) for v in values]
1260 def _make_implicit_enum_type(self, name, info, values):
1261 # See also QAPISchemaObjectTypeMember._pretty_owner()
1262 name = name + 'Kind' # Use namespace reserved by add_name()
1263 self._def_entity(QAPISchemaEnumType(
1264 name, info, self._make_enum_members(values), None))
1265 return name
1267 def _make_array_type(self, element_type, info):
1268 name = element_type + 'List' # Use namespace reserved by add_name()
1269 if not self.lookup_type(name):
1270 self._def_entity(QAPISchemaArrayType(name, info, element_type))
1271 return name
1273 def _make_implicit_object_type(self, name, info, role, members):
1274 if not members:
1275 return None
1276 # See also QAPISchemaObjectTypeMember._pretty_owner()
1277 name = ':obj-%s-%s' % (name, role)
1278 if not self.lookup_entity(name, QAPISchemaObjectType):
1279 self._def_entity(QAPISchemaObjectType(name, info, None,
1280 members, None))
1281 return name
1283 def _def_enum_type(self, expr, info):
1284 name = expr['enum']
1285 data = expr['data']
1286 prefix = expr.get('prefix')
1287 self._def_entity(QAPISchemaEnumType(
1288 name, info, self._make_enum_members(data), prefix))
1290 def _make_member(self, name, typ, info):
1291 optional = False
1292 if name.startswith('*'):
1293 name = name[1:]
1294 optional = True
1295 if isinstance(typ, list):
1296 assert len(typ) == 1
1297 typ = self._make_array_type(typ[0], info)
1298 return QAPISchemaObjectTypeMember(name, typ, optional)
1300 def _make_members(self, data, info):
1301 return [self._make_member(key, value, info)
1302 for (key, value) in data.iteritems()]
1304 def _def_struct_type(self, expr, info):
1305 name = expr['struct']
1306 base = expr.get('base')
1307 data = expr['data']
1308 self._def_entity(QAPISchemaObjectType(name, info, base,
1309 self._make_members(data, info),
1310 None))
1312 def _make_variant(self, case, typ):
1313 return QAPISchemaObjectTypeVariant(case, typ)
1315 def _make_simple_variant(self, case, typ, info):
1316 if isinstance(typ, list):
1317 assert len(typ) == 1
1318 typ = self._make_array_type(typ[0], info)
1319 typ = self._make_implicit_object_type(
1320 typ, info, 'wrapper', [self._make_member('data', typ, info)])
1321 return QAPISchemaObjectTypeVariant(case, typ)
1323 def _def_union_type(self, expr, info):
1324 name = expr['union']
1325 data = expr['data']
1326 base = expr.get('base')
1327 tag_name = expr.get('discriminator')
1328 tag_member = None
1329 if tag_name:
1330 variants = [self._make_variant(key, value)
1331 for (key, value) in data.iteritems()]
1332 members = []
1333 else:
1334 variants = [self._make_simple_variant(key, value, info)
1335 for (key, value) in data.iteritems()]
1336 typ = self._make_implicit_enum_type(name, info,
1337 [v.name for v in variants])
1338 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
1339 members = [tag_member]
1340 self._def_entity(
1341 QAPISchemaObjectType(name, info, base, members,
1342 QAPISchemaObjectTypeVariants(tag_name,
1343 tag_member,
1344 variants)))
1346 def _def_alternate_type(self, expr, info):
1347 name = expr['alternate']
1348 data = expr['data']
1349 variants = [self._make_variant(key, value)
1350 for (key, value) in data.iteritems()]
1351 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
1352 self._def_entity(
1353 QAPISchemaAlternateType(name, info,
1354 QAPISchemaObjectTypeVariants(None,
1355 tag_member,
1356 variants)))
1358 def _def_command(self, expr, info):
1359 name = expr['command']
1360 data = expr.get('data')
1361 rets = expr.get('returns')
1362 gen = expr.get('gen', True)
1363 success_response = expr.get('success-response', True)
1364 if isinstance(data, OrderedDict):
1365 data = self._make_implicit_object_type(
1366 name, info, 'arg', self._make_members(data, info))
1367 if isinstance(rets, list):
1368 assert len(rets) == 1
1369 rets = self._make_array_type(rets[0], info)
1370 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1371 success_response))
1373 def _def_event(self, expr, info):
1374 name = expr['event']
1375 data = expr.get('data')
1376 if isinstance(data, OrderedDict):
1377 data = self._make_implicit_object_type(
1378 name, info, 'arg', self._make_members(data, info))
1379 self._def_entity(QAPISchemaEvent(name, info, data))
1381 def _def_exprs(self):
1382 for expr_elem in self.exprs:
1383 expr = expr_elem['expr']
1384 info = expr_elem['info']
1385 if 'enum' in expr:
1386 self._def_enum_type(expr, info)
1387 elif 'struct' in expr:
1388 self._def_struct_type(expr, info)
1389 elif 'union' in expr:
1390 self._def_union_type(expr, info)
1391 elif 'alternate' in expr:
1392 self._def_alternate_type(expr, info)
1393 elif 'command' in expr:
1394 self._def_command(expr, info)
1395 elif 'event' in expr:
1396 self._def_event(expr, info)
1397 else:
1398 assert False
1400 def check(self):
1401 for ent in self._entity_dict.values():
1402 ent.check(self)
1404 def visit(self, visitor):
1405 visitor.visit_begin(self)
1406 for (name, entity) in sorted(self._entity_dict.items()):
1407 if visitor.visit_needed(entity):
1408 entity.visit(visitor)
1409 visitor.visit_end()
1413 # Code generation helpers
1416 def camel_case(name):
1417 new_name = ''
1418 first = True
1419 for ch in name:
1420 if ch in ['_', '-']:
1421 first = True
1422 elif first:
1423 new_name += ch.upper()
1424 first = False
1425 else:
1426 new_name += ch.lower()
1427 return new_name
1430 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1431 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1432 # ENUM24_Name -> ENUM24_NAME
1433 def camel_to_upper(value):
1434 c_fun_str = c_name(value, False)
1435 if value.isupper():
1436 return c_fun_str
1438 new_name = ''
1439 l = len(c_fun_str)
1440 for i in range(l):
1441 c = c_fun_str[i]
1442 # When c is upper and no "_" appears before, do more checks
1443 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
1444 if i < l - 1 and c_fun_str[i + 1].islower():
1445 new_name += '_'
1446 elif c_fun_str[i - 1].isdigit():
1447 new_name += '_'
1448 new_name += c
1449 return new_name.lstrip('_').upper()
1452 def c_enum_const(type_name, const_name, prefix=None):
1453 if prefix is not None:
1454 type_name = prefix
1455 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
1457 c_name_trans = string.maketrans('.-', '__')
1460 # Map @name to a valid C identifier.
1461 # If @protect, avoid returning certain ticklish identifiers (like
1462 # C keywords) by prepending "q_".
1464 # Used for converting 'name' from a 'name':'type' qapi definition
1465 # into a generated struct member, as well as converting type names
1466 # into substrings of a generated C function name.
1467 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1468 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1469 def c_name(name, protect=True):
1470 # ANSI X3J11/88-090, 3.1.1
1471 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1472 'default', 'do', 'double', 'else', 'enum', 'extern',
1473 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1474 'return', 'short', 'signed', 'sizeof', 'static',
1475 'struct', 'switch', 'typedef', 'union', 'unsigned',
1476 'void', 'volatile', 'while'])
1477 # ISO/IEC 9899:1999, 6.4.1
1478 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1479 # ISO/IEC 9899:2011, 6.4.1
1480 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1481 '_Noreturn', '_Static_assert', '_Thread_local'])
1482 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1483 # excluding _.*
1484 gcc_words = set(['asm', 'typeof'])
1485 # C++ ISO/IEC 14882:2003 2.11
1486 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1487 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1488 'namespace', 'new', 'operator', 'private', 'protected',
1489 'public', 'reinterpret_cast', 'static_cast', 'template',
1490 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1491 'using', 'virtual', 'wchar_t',
1492 # alternative representations
1493 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1494 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1495 # namespace pollution:
1496 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
1497 name = name.translate(c_name_trans)
1498 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1499 | cpp_words | polluted_words):
1500 return "q_" + name
1501 return name
1503 eatspace = '\033EATSPACE.'
1504 pointer_suffix = ' *' + eatspace
1507 def genindent(count):
1508 ret = ""
1509 for _ in range(count):
1510 ret += " "
1511 return ret
1513 indent_level = 0
1516 def push_indent(indent_amount=4):
1517 global indent_level
1518 indent_level += indent_amount
1521 def pop_indent(indent_amount=4):
1522 global indent_level
1523 indent_level -= indent_amount
1526 # Generate @code with @kwds interpolated.
1527 # Obey indent_level, and strip eatspace.
1528 def cgen(code, **kwds):
1529 raw = code % kwds
1530 if indent_level:
1531 indent = genindent(indent_level)
1532 # re.subn() lacks flags support before Python 2.7, use re.compile()
1533 raw = re.subn(re.compile("^.", re.MULTILINE),
1534 indent + r'\g<0>', raw)
1535 raw = raw[0]
1536 return re.sub(re.escape(eatspace) + ' *', '', raw)
1539 def mcgen(code, **kwds):
1540 if code[0] == '\n':
1541 code = code[1:]
1542 return cgen(code, **kwds)
1545 def guardname(filename):
1546 return c_name(filename, protect=False).upper()
1549 def guardstart(name):
1550 return mcgen('''
1552 #ifndef %(name)s
1553 #define %(name)s
1555 ''',
1556 name=guardname(name))
1559 def guardend(name):
1560 return mcgen('''
1562 #endif /* %(name)s */
1564 ''',
1565 name=guardname(name))
1568 def gen_enum_lookup(name, values, prefix=None):
1569 ret = mcgen('''
1571 const char *const %(c_name)s_lookup[] = {
1572 ''',
1573 c_name=c_name(name))
1574 for value in values:
1575 index = c_enum_const(name, value, prefix)
1576 ret += mcgen('''
1577 [%(index)s] = "%(value)s",
1578 ''',
1579 index=index, value=value)
1581 max_index = c_enum_const(name, '_MAX', prefix)
1582 ret += mcgen('''
1583 [%(max_index)s] = NULL,
1585 ''',
1586 max_index=max_index)
1587 return ret
1590 def gen_enum(name, values, prefix=None):
1591 # append automatically generated _MAX value
1592 enum_values = values + ['_MAX']
1594 ret = mcgen('''
1596 typedef enum %(c_name)s {
1597 ''',
1598 c_name=c_name(name))
1600 i = 0
1601 for value in enum_values:
1602 ret += mcgen('''
1603 %(c_enum)s = %(i)d,
1604 ''',
1605 c_enum=c_enum_const(name, value, prefix),
1606 i=i)
1607 i += 1
1609 ret += mcgen('''
1610 } %(c_name)s;
1611 ''',
1612 c_name=c_name(name))
1614 ret += mcgen('''
1616 extern const char *const %(c_name)s_lookup[];
1617 ''',
1618 c_name=c_name(name))
1619 return ret
1622 def gen_params(arg_type, extra):
1623 if not arg_type:
1624 return extra
1625 assert not arg_type.variants
1626 ret = ''
1627 sep = ''
1628 for memb in arg_type.members:
1629 ret += sep
1630 sep = ', '
1631 if memb.optional:
1632 ret += 'bool has_%s, ' % c_name(memb.name)
1633 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1634 if extra:
1635 ret += sep + extra
1636 return ret
1639 def gen_err_check(label='out', skiperr=False):
1640 if skiperr:
1641 return ''
1642 return mcgen('''
1643 if (err) {
1644 goto %(label)s;
1646 ''',
1647 label=label)
1650 def gen_visit_members(members, prefix='', need_cast=False, skiperr=False,
1651 label='out'):
1652 ret = ''
1653 if skiperr:
1654 errparg = 'NULL'
1655 else:
1656 errparg = '&err'
1658 for memb in members:
1659 if memb.optional:
1660 ret += mcgen('''
1661 if (visit_optional(v, "%(name)s", &%(prefix)shas_%(c_name)s)) {
1662 ''',
1663 prefix=prefix, c_name=c_name(memb.name),
1664 name=memb.name)
1665 push_indent()
1667 # Ugly: sometimes we need to cast away const
1668 if need_cast and memb.type.name == 'str':
1669 cast = '(char **)'
1670 else:
1671 cast = ''
1673 ret += mcgen('''
1674 visit_type_%(c_type)s(v, "%(name)s", %(cast)s&%(prefix)s%(c_name)s, %(errp)s);
1675 ''',
1676 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1677 c_name=c_name(memb.name), name=memb.name,
1678 errp=errparg)
1679 ret += gen_err_check(skiperr=skiperr, label=label)
1681 if memb.optional:
1682 pop_indent()
1683 ret += mcgen('''
1685 ''')
1686 return ret
1690 # Common command line parsing
1694 def parse_command_line(extra_options="", extra_long_options=[]):
1696 try:
1697 opts, args = getopt.gnu_getopt(sys.argv[1:],
1698 "chp:o:" + extra_options,
1699 ["source", "header", "prefix=",
1700 "output-dir="] + extra_long_options)
1701 except getopt.GetoptError as err:
1702 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1703 sys.exit(1)
1705 output_dir = ""
1706 prefix = ""
1707 do_c = False
1708 do_h = False
1709 extra_opts = []
1711 for oa in opts:
1712 o, a = oa
1713 if o in ("-p", "--prefix"):
1714 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1715 if match.end() != len(a):
1716 print >>sys.stderr, \
1717 "%s: 'funny character '%s' in argument of --prefix" \
1718 % (sys.argv[0], a[match.end()])
1719 sys.exit(1)
1720 prefix = a
1721 elif o in ("-o", "--output-dir"):
1722 output_dir = a + "/"
1723 elif o in ("-c", "--source"):
1724 do_c = True
1725 elif o in ("-h", "--header"):
1726 do_h = True
1727 else:
1728 extra_opts.append(oa)
1730 if not do_c and not do_h:
1731 do_c = True
1732 do_h = True
1734 if len(args) != 1:
1735 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1736 sys.exit(1)
1737 fname = args[0]
1739 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1742 # Generate output files with boilerplate
1746 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1747 c_comment, h_comment):
1748 guard = guardname(prefix + h_file)
1749 c_file = output_dir + prefix + c_file
1750 h_file = output_dir + prefix + h_file
1752 if output_dir:
1753 try:
1754 os.makedirs(output_dir)
1755 except os.error as e:
1756 if e.errno != errno.EEXIST:
1757 raise
1759 def maybe_open(really, name, opt):
1760 if really:
1761 return open(name, opt)
1762 else:
1763 import StringIO
1764 return StringIO.StringIO()
1766 fdef = maybe_open(do_c, c_file, 'w')
1767 fdecl = maybe_open(do_h, h_file, 'w')
1769 fdef.write(mcgen('''
1770 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1771 %(comment)s
1772 ''',
1773 comment=c_comment))
1775 fdecl.write(mcgen('''
1776 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1777 %(comment)s
1778 #ifndef %(guard)s
1779 #define %(guard)s
1781 ''',
1782 comment=h_comment, guard=guard))
1784 return (fdef, fdecl)
1787 def close_output(fdef, fdecl):
1788 fdecl.write('''
1789 #endif
1790 ''')
1791 fdecl.close()
1792 fdef.close()