qmp-commands: move 'drive-mirror' doc to schema
[qemu/ar7.git] / scripts / qapi.py
blob1483ec09f5a8ef9a4289ed8a67b1adcc6e7088e3
2 # QAPI helper library
4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2016 Red Hat Inc.
7 # Authors:
8 # Anthony Liguori <aliguori@us.ibm.com>
9 # Markus Armbruster <armbru@redhat.com>
11 # This work is licensed under the terms of the GNU GPL, version 2.
12 # See the COPYING file in the top-level directory.
14 import re
15 from ordereddict import OrderedDict
16 import errno
17 import getopt
18 import os
19 import sys
20 import string
22 builtin_types = {
23 'str': 'QTYPE_QSTRING',
24 'int': 'QTYPE_QINT',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
27 'int8': 'QTYPE_QINT',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
35 'size': 'QTYPE_QINT',
36 'any': None, # any QType possible, actually
37 'QType': 'QTYPE_QSTRING',
40 # Whitelist of commands allowed to return a non-dictionary
41 returns_whitelist = [
42 # From QMP:
43 'human-monitor-command',
44 'qom-get',
45 'query-migrate-cache-size',
46 'query-tpm-models',
47 'query-tpm-types',
48 'ringbuf-read',
50 # From QGA:
51 'guest-file-open',
52 'guest-fsfreeze-freeze',
53 'guest-fsfreeze-freeze-list',
54 'guest-fsfreeze-status',
55 'guest-fsfreeze-thaw',
56 'guest-get-time',
57 'guest-set-vcpus',
58 'guest-sync',
59 'guest-sync-delimited',
62 # Whitelist of entities allowed to violate case conventions
63 case_whitelist = [
64 # From QMP:
65 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
66 'CpuInfoMIPS', # PC, visible through query-cpu
67 'CpuInfoTricore', # PC, visible through query-cpu
68 'QapiErrorClass', # all members, visible through errors
69 'UuidInfo', # UUID, visible through query-uuid
70 'X86CPURegister32', # all members, visible indirectly through qom-get
71 'q_obj_CpuInfo-base', # CPU, visible through query-cpu
74 enum_types = []
75 struct_types = []
76 union_types = []
77 events = []
78 all_names = {}
81 # Parsing the schema into expressions
85 def error_path(parent):
86 res = ""
87 while parent:
88 res = ("In file included from %s:%d:\n" % (parent['file'],
89 parent['line'])) + res
90 parent = parent['parent']
91 return res
94 class QAPIError(Exception):
95 def __init__(self, fname, line, col, incl_info, msg):
96 Exception.__init__(self)
97 self.fname = fname
98 self.line = line
99 self.col = col
100 self.info = incl_info
101 self.msg = msg
103 def __str__(self):
104 loc = "%s:%d" % (self.fname, self.line)
105 if self.col is not None:
106 loc += ":%s" % self.col
107 return error_path(self.info) + "%s: %s" % (loc, self.msg)
110 class QAPIParseError(QAPIError):
111 def __init__(self, parser, msg):
112 col = 1
113 for ch in parser.src[parser.line_pos:parser.pos]:
114 if ch == '\t':
115 col = (col + 7) % 8 + 1
116 else:
117 col += 1
118 QAPIError.__init__(self, parser.fname, parser.line, col,
119 parser.incl_info, msg)
122 class QAPISemError(QAPIError):
123 def __init__(self, info, msg):
124 QAPIError.__init__(self, info['file'], info['line'], None,
125 info['parent'], msg)
128 class QAPISchemaParser(object):
130 def __init__(self, fp, previously_included=[], incl_info=None):
131 abs_fname = os.path.abspath(fp.name)
132 fname = fp.name
133 self.fname = fname
134 previously_included.append(abs_fname)
135 self.incl_info = incl_info
136 self.src = fp.read()
137 if self.src == '' or self.src[-1] != '\n':
138 self.src += '\n'
139 self.cursor = 0
140 self.line = 1
141 self.line_pos = 0
142 self.exprs = []
143 self.accept()
145 while self.tok is not None:
146 info = {'file': fname, 'line': self.line,
147 'parent': self.incl_info}
148 expr = self.get_expr(False)
149 if isinstance(expr, dict) and "include" in expr:
150 if len(expr) != 1:
151 raise QAPISemError(info, "Invalid 'include' directive")
152 include = expr["include"]
153 if not isinstance(include, str):
154 raise QAPISemError(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 = info
160 while inf:
161 if incl_abs_fname == os.path.abspath(inf['file']):
162 raise QAPISemError(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 QAPISemError(info, '%s: %s' % (e.strerror, include))
172 exprs_include = QAPISchemaParser(fobj, previously_included,
173 info)
174 self.exprs.extend(exprs_include.exprs)
175 else:
176 expr_elem = {'expr': expr,
177 'info': info}
178 self.exprs.append(expr_elem)
180 def accept(self):
181 while True:
182 self.tok = self.src[self.cursor]
183 self.pos = self.cursor
184 self.cursor += 1
185 self.val = None
187 if self.tok == '#':
188 self.cursor = self.src.find('\n', self.cursor)
189 elif self.tok in "{}:,[]":
190 return
191 elif self.tok == "'":
192 string = ''
193 esc = False
194 while True:
195 ch = self.src[self.cursor]
196 self.cursor += 1
197 if ch == '\n':
198 raise QAPIParseError(self, '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 QAPIParseError(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 QAPIParseError(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 QAPIParseError(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 QAPIParseError(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 QAPIParseError(self, 'Expected string or "}"')
271 while True:
272 key = self.val
273 self.accept()
274 if self.tok != ':':
275 raise QAPIParseError(self, 'Expected ":"')
276 self.accept()
277 if key in expr:
278 raise QAPIParseError(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 QAPIParseError(self, 'Expected "," or "}"')
285 self.accept()
286 if self.tok != "'":
287 raise QAPIParseError(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 QAPIParseError(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 QAPIParseError(self, 'Expected "," or "]"')
304 self.accept()
306 def get_expr(self, nested):
307 if self.tok != '{' and not nested:
308 raise QAPIParseError(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 QAPIParseError(self, 'Expected "{", "[" or string')
320 return expr
323 # Semantic analysis of schema expressions
324 # TODO fold into QAPISchema
325 # TODO catching name collisions in generated code would be nice
329 def find_base_members(base):
330 if isinstance(base, dict):
331 return base
332 base_struct_define = find_struct(base)
333 if not base_struct_define:
334 return None
335 return base_struct_define['data']
338 # Return the qtype of an alternate branch, or None on error.
339 def find_alternate_member_qtype(qapi_type):
340 if qapi_type in builtin_types:
341 return builtin_types[qapi_type]
342 elif find_struct(qapi_type):
343 return "QTYPE_QDICT"
344 elif find_enum(qapi_type):
345 return "QTYPE_QSTRING"
346 elif find_union(qapi_type):
347 return "QTYPE_QDICT"
348 return None
351 # Return the discriminator enum define if discriminator is specified as an
352 # enum type, otherwise return None.
353 def discriminator_find_enum_define(expr):
354 base = expr.get('base')
355 discriminator = expr.get('discriminator')
357 if not (discriminator and base):
358 return None
360 base_members = find_base_members(base)
361 if not base_members:
362 return None
364 discriminator_type = base_members.get(discriminator)
365 if not discriminator_type:
366 return None
368 return find_enum(discriminator_type)
371 # Names must be letters, numbers, -, and _. They must start with letter,
372 # except for downstream extensions which must start with __RFQDN_.
373 # Dots are only valid in the downstream extension prefix.
374 valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
375 '[a-zA-Z][a-zA-Z0-9_-]*$')
378 def check_name(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 QAPISemError(info, "%s requires a string name" % source)
385 if name.startswith('*'):
386 membername = name[1:]
387 if not allow_optional:
388 raise QAPISemError(info, "%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(), and for 'q_empty'
395 # and 'q_obj_*' implicit type names.
396 if not valid_name.match(membername) or \
397 c_name(membername, False).startswith('q_'):
398 raise QAPISemError(info, "%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 QAPISemError(info, "%s '%s' is already defined"
408 % (all_names[name], name))
409 if not implicit and (name.endswith('Kind') or name.endswith('List')):
410 raise QAPISemError(info, "%s '%s' should not end in '%s'"
411 % (meta, name, name[-4:]))
412 all_names[name] = meta
415 def add_struct(definition, info):
416 global struct_types
417 name = definition['struct']
418 add_name(name, info, 'struct')
419 struct_types.append(definition)
422 def find_struct(name):
423 global struct_types
424 for struct in struct_types:
425 if struct['struct'] == name:
426 return struct
427 return None
430 def add_union(definition, info):
431 global union_types
432 name = definition['union']
433 add_name(name, info, 'union')
434 union_types.append(definition)
437 def find_union(name):
438 global union_types
439 for union in union_types:
440 if union['union'] == name:
441 return union
442 return None
445 def add_enum(name, info, enum_values=None, implicit=False):
446 global enum_types
447 add_name(name, info, 'enum', implicit)
448 enum_types.append({"enum_name": name, "enum_values": enum_values})
451 def find_enum(name):
452 global enum_types
453 for enum in enum_types:
454 if enum['enum_name'] == name:
455 return enum
456 return None
459 def is_enum(name):
460 return find_enum(name) is not None
463 def check_type(info, source, value, allow_array=False,
464 allow_dict=False, allow_optional=False,
465 allow_metas=[]):
466 global all_names
468 if value is None:
469 return
471 # Check if array type for value is okay
472 if isinstance(value, list):
473 if not allow_array:
474 raise QAPISemError(info, "%s cannot be an array" % source)
475 if len(value) != 1 or not isinstance(value[0], str):
476 raise QAPISemError(info,
477 "%s: array type must contain single type name" %
478 source)
479 value = value[0]
481 # Check if type name for value is okay
482 if isinstance(value, str):
483 if value not in all_names:
484 raise QAPISemError(info, "%s uses unknown type '%s'"
485 % (source, value))
486 if not all_names[value] in allow_metas:
487 raise QAPISemError(info, "%s cannot use %s type '%s'" %
488 (source, all_names[value], value))
489 return
491 if not allow_dict:
492 raise QAPISemError(info, "%s should be a type name" % source)
494 if not isinstance(value, OrderedDict):
495 raise QAPISemError(info,
496 "%s should be a dictionary or type name" % source)
498 # value is a dictionary, check that each member is okay
499 for (key, arg) in value.items():
500 check_name(info, "Member of %s" % source, key,
501 allow_optional=allow_optional)
502 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
503 raise QAPISemError(info, "Member of %s uses reserved name '%s'"
504 % (source, key))
505 # Todo: allow dictionaries to represent default values of
506 # an optional argument.
507 check_type(info, "Member '%s' of %s" % (key, source), arg,
508 allow_array=True,
509 allow_metas=['built-in', 'union', 'alternate', 'struct',
510 'enum'])
513 def check_command(expr, info):
514 name = expr['command']
515 boxed = expr.get('boxed', False)
517 args_meta = ['struct']
518 if boxed:
519 args_meta += ['union', 'alternate']
520 check_type(info, "'data' for command '%s'" % name,
521 expr.get('data'), allow_dict=not boxed, allow_optional=True,
522 allow_metas=args_meta)
523 returns_meta = ['union', 'struct']
524 if name in returns_whitelist:
525 returns_meta += ['built-in', 'alternate', 'enum']
526 check_type(info, "'returns' for command '%s'" % name,
527 expr.get('returns'), allow_array=True,
528 allow_optional=True, allow_metas=returns_meta)
531 def check_event(expr, info):
532 global events
533 name = expr['event']
534 boxed = expr.get('boxed', False)
536 meta = ['struct']
537 if boxed:
538 meta += ['union', 'alternate']
539 events.append(name)
540 check_type(info, "'data' for event '%s'" % name,
541 expr.get('data'), allow_dict=not boxed, allow_optional=True,
542 allow_metas=meta)
545 def check_union(expr, info):
546 name = expr['union']
547 base = expr.get('base')
548 discriminator = expr.get('discriminator')
549 members = expr['data']
551 # Two types of unions, determined by discriminator.
553 # With no discriminator it is a simple union.
554 if discriminator is None:
555 enum_define = None
556 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
557 if base is not None:
558 raise QAPISemError(info, "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 or dictionary 'base'.
564 check_type(info, "'base' for union '%s'" % name,
565 base, allow_dict=True, allow_optional=True,
566 allow_metas=['struct'])
567 if not base:
568 raise QAPISemError(info, "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(info, "Discriminator of flat union '%s'" % name,
576 discriminator)
577 discriminator_type = base_members.get(discriminator)
578 if not discriminator_type:
579 raise QAPISemError(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 QAPISemError(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 QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
594 for (key, value) in members.items():
595 check_name(info, "Member of union '%s'" % name, key)
597 # Each value must name a known type
598 check_type(info, "Member '%s' of union '%s'" % (key, name),
599 value, allow_array=not base, allow_metas=allow_metas)
601 # If the discriminator names an enum type, then all members
602 # of 'data' must also be members of the enum type.
603 if enum_define:
604 if key not in enum_define['enum_values']:
605 raise QAPISemError(info,
606 "Discriminator value '%s' is not found in "
607 "enum '%s'"
608 % (key, enum_define["enum_name"]))
610 # If discriminator is user-defined, ensure all values are covered
611 if enum_define:
612 for value in enum_define['enum_values']:
613 if value not in members.keys():
614 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
615 % (name, value))
618 def check_alternate(expr, info):
619 name = expr['alternate']
620 members = expr['data']
621 types_seen = {}
623 # Check every branch; require at least two branches
624 if len(members) < 2:
625 raise QAPISemError(info,
626 "Alternate '%s' should have at least two branches "
627 "in 'data'" % name)
628 for (key, value) in members.items():
629 check_name(info, "Member of alternate '%s'" % name, key)
631 # Ensure alternates have no type conflicts.
632 check_type(info, "Member '%s' of alternate '%s'" % (key, name),
633 value,
634 allow_metas=['built-in', 'union', 'struct', 'enum'])
635 qtype = find_alternate_member_qtype(value)
636 if not qtype:
637 raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
638 "type '%s'" % (name, key, value))
639 if qtype in types_seen:
640 raise QAPISemError(info, "Alternate '%s' member '%s' can't "
641 "be distinguished from member '%s'"
642 % (name, key, types_seen[qtype]))
643 types_seen[qtype] = key
646 def check_enum(expr, info):
647 name = expr['enum']
648 members = expr.get('data')
649 prefix = expr.get('prefix')
651 if not isinstance(members, list):
652 raise QAPISemError(info,
653 "Enum '%s' requires an array for 'data'" % name)
654 if prefix is not None and not isinstance(prefix, str):
655 raise QAPISemError(info,
656 "Enum '%s' requires a string for 'prefix'" % name)
657 for member in members:
658 check_name(info, "Member of enum '%s'" % name, member,
659 enum_member=True)
662 def check_struct(expr, info):
663 name = expr['struct']
664 members = expr['data']
666 check_type(info, "'data' for struct '%s'" % name, members,
667 allow_dict=True, allow_optional=True)
668 check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
669 allow_metas=['struct'])
672 def check_keys(expr_elem, meta, required, optional=[]):
673 expr = expr_elem['expr']
674 info = expr_elem['info']
675 name = expr[meta]
676 if not isinstance(name, str):
677 raise QAPISemError(info, "'%s' key must have a string value" % meta)
678 required = required + [meta]
679 for (key, value) in expr.items():
680 if key not in required and key not in optional:
681 raise QAPISemError(info, "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 QAPISemError(info,
685 "'%s' of %s '%s' should only use false value"
686 % (key, meta, name))
687 if key == 'boxed' and value is not True:
688 raise QAPISemError(info,
689 "'%s' of %s '%s' should only use true value"
690 % (key, meta, name))
691 for key in required:
692 if key not in expr:
693 raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
694 % (key, meta, name))
697 def check_exprs(exprs):
698 global all_names
700 # Learn the types and check for valid expression keys
701 for builtin in builtin_types.keys():
702 all_names[builtin] = 'built-in'
703 for expr_elem in exprs:
704 expr = expr_elem['expr']
705 info = expr_elem['info']
706 if 'enum' in expr:
707 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
708 add_enum(expr['enum'], info, expr['data'])
709 elif 'union' in expr:
710 check_keys(expr_elem, 'union', ['data'],
711 ['base', 'discriminator'])
712 add_union(expr, info)
713 elif 'alternate' in expr:
714 check_keys(expr_elem, 'alternate', ['data'])
715 add_name(expr['alternate'], info, 'alternate')
716 elif 'struct' in expr:
717 check_keys(expr_elem, 'struct', ['data'], ['base'])
718 add_struct(expr, info)
719 elif 'command' in expr:
720 check_keys(expr_elem, 'command', [],
721 ['data', 'returns', 'gen', 'success-response', 'boxed'])
722 add_name(expr['command'], info, 'command')
723 elif 'event' in expr:
724 check_keys(expr_elem, 'event', [], ['data', 'boxed'])
725 add_name(expr['event'], info, 'event')
726 else:
727 raise QAPISemError(expr_elem['info'],
728 "Expression is missing metatype")
730 # Try again for hidden UnionKind enum
731 for expr_elem in exprs:
732 expr = expr_elem['expr']
733 if 'union' in expr:
734 if not discriminator_find_enum_define(expr):
735 add_enum('%sKind' % expr['union'], expr_elem['info'],
736 implicit=True)
737 elif 'alternate' in expr:
738 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
739 implicit=True)
741 # Validate that exprs make sense
742 for expr_elem in exprs:
743 expr = expr_elem['expr']
744 info = expr_elem['info']
746 if 'enum' in expr:
747 check_enum(expr, info)
748 elif 'union' in expr:
749 check_union(expr, info)
750 elif 'alternate' in expr:
751 check_alternate(expr, info)
752 elif 'struct' in expr:
753 check_struct(expr, info)
754 elif 'command' in expr:
755 check_command(expr, info)
756 elif 'event' in expr:
757 check_event(expr, info)
758 else:
759 assert False, 'unexpected meta type'
761 return exprs
765 # Schema compiler frontend
768 class QAPISchemaEntity(object):
769 def __init__(self, name, info):
770 assert isinstance(name, str)
771 self.name = name
772 # For explicitly defined entities, info points to the (explicit)
773 # definition. For builtins (and their arrays), info is None.
774 # For implicitly defined entities, info points to a place that
775 # triggered the implicit definition (there may be more than one
776 # such place).
777 self.info = info
779 def c_name(self):
780 return c_name(self.name)
782 def check(self, schema):
783 pass
785 def is_implicit(self):
786 return not self.info
788 def visit(self, visitor):
789 pass
792 class QAPISchemaVisitor(object):
793 def visit_begin(self, schema):
794 pass
796 def visit_end(self):
797 pass
799 def visit_needed(self, entity):
800 # Default to visiting everything
801 return True
803 def visit_builtin_type(self, name, info, json_type):
804 pass
806 def visit_enum_type(self, name, info, values, prefix):
807 pass
809 def visit_array_type(self, name, info, element_type):
810 pass
812 def visit_object_type(self, name, info, base, members, variants):
813 pass
815 def visit_object_type_flat(self, name, info, members, variants):
816 pass
818 def visit_alternate_type(self, name, info, variants):
819 pass
821 def visit_command(self, name, info, arg_type, ret_type,
822 gen, success_response, boxed):
823 pass
825 def visit_event(self, name, info, arg_type, boxed):
826 pass
829 class QAPISchemaType(QAPISchemaEntity):
830 # Return the C type for common use.
831 # For the types we commonly box, this is a pointer type.
832 def c_type(self):
833 pass
835 # Return the C type to be used in a parameter list.
836 def c_param_type(self):
837 return self.c_type()
839 # Return the C type to be used where we suppress boxing.
840 def c_unboxed_type(self):
841 return self.c_type()
843 def json_type(self):
844 pass
846 def alternate_qtype(self):
847 json2qtype = {
848 'string': 'QTYPE_QSTRING',
849 'number': 'QTYPE_QFLOAT',
850 'int': 'QTYPE_QINT',
851 'boolean': 'QTYPE_QBOOL',
852 'object': 'QTYPE_QDICT'
854 return json2qtype.get(self.json_type())
857 class QAPISchemaBuiltinType(QAPISchemaType):
858 def __init__(self, name, json_type, c_type):
859 QAPISchemaType.__init__(self, name, None)
860 assert not c_type or isinstance(c_type, str)
861 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
862 'value')
863 self._json_type_name = json_type
864 self._c_type_name = c_type
866 def c_name(self):
867 return self.name
869 def c_type(self):
870 return self._c_type_name
872 def c_param_type(self):
873 if self.name == 'str':
874 return 'const ' + self._c_type_name
875 return self._c_type_name
877 def json_type(self):
878 return self._json_type_name
880 def visit(self, visitor):
881 visitor.visit_builtin_type(self.name, self.info, self.json_type())
884 class QAPISchemaEnumType(QAPISchemaType):
885 def __init__(self, name, info, values, prefix):
886 QAPISchemaType.__init__(self, name, info)
887 for v in values:
888 assert isinstance(v, QAPISchemaMember)
889 v.set_owner(name)
890 assert prefix is None or isinstance(prefix, str)
891 self.values = values
892 self.prefix = prefix
894 def check(self, schema):
895 seen = {}
896 for v in self.values:
897 v.check_clash(self.info, seen)
899 def is_implicit(self):
900 # See QAPISchema._make_implicit_enum_type()
901 return self.name.endswith('Kind')
903 def c_type(self):
904 return c_name(self.name)
906 def member_names(self):
907 return [v.name for v in self.values]
909 def json_type(self):
910 return 'string'
912 def visit(self, visitor):
913 visitor.visit_enum_type(self.name, self.info,
914 self.member_names(), self.prefix)
917 class QAPISchemaArrayType(QAPISchemaType):
918 def __init__(self, name, info, element_type):
919 QAPISchemaType.__init__(self, name, info)
920 assert isinstance(element_type, str)
921 self._element_type_name = element_type
922 self.element_type = None
924 def check(self, schema):
925 self.element_type = schema.lookup_type(self._element_type_name)
926 assert self.element_type
928 def is_implicit(self):
929 return True
931 def c_type(self):
932 return c_name(self.name) + pointer_suffix
934 def json_type(self):
935 return 'array'
937 def visit(self, visitor):
938 visitor.visit_array_type(self.name, self.info, self.element_type)
941 class QAPISchemaObjectType(QAPISchemaType):
942 def __init__(self, name, info, base, local_members, variants):
943 # struct has local_members, optional base, and no variants
944 # flat union has base, variants, and no local_members
945 # simple union has local_members, variants, and no base
946 QAPISchemaType.__init__(self, name, info)
947 assert base is None or isinstance(base, str)
948 for m in local_members:
949 assert isinstance(m, QAPISchemaObjectTypeMember)
950 m.set_owner(name)
951 if variants is not None:
952 assert isinstance(variants, QAPISchemaObjectTypeVariants)
953 variants.set_owner(name)
954 self._base_name = base
955 self.base = None
956 self.local_members = local_members
957 self.variants = variants
958 self.members = None
960 def check(self, schema):
961 if self.members is False: # check for cycles
962 raise QAPISemError(self.info,
963 "Object %s contains itself" % self.name)
964 if self.members:
965 return
966 self.members = False # mark as being checked
967 seen = OrderedDict()
968 if self._base_name:
969 self.base = schema.lookup_type(self._base_name)
970 assert isinstance(self.base, QAPISchemaObjectType)
971 self.base.check(schema)
972 self.base.check_clash(schema, self.info, seen)
973 for m in self.local_members:
974 m.check(schema)
975 m.check_clash(self.info, seen)
976 self.members = seen.values()
977 if self.variants:
978 self.variants.check(schema, seen)
979 assert self.variants.tag_member in self.members
980 self.variants.check_clash(schema, self.info, seen)
982 # Check that the members of this type do not cause duplicate JSON members,
983 # and update seen to track the members seen so far. Report any errors
984 # on behalf of info, which is not necessarily self.info
985 def check_clash(self, schema, info, seen):
986 assert not self.variants # not implemented
987 for m in self.members:
988 m.check_clash(info, seen)
990 def is_implicit(self):
991 # See QAPISchema._make_implicit_object_type(), as well as
992 # _def_predefineds()
993 return self.name.startswith('q_')
995 def is_empty(self):
996 assert self.members is not None
997 return not self.members and not self.variants
999 def c_name(self):
1000 assert self.name != 'q_empty'
1001 return QAPISchemaType.c_name(self)
1003 def c_type(self):
1004 assert not self.is_implicit()
1005 return c_name(self.name) + pointer_suffix
1007 def c_unboxed_type(self):
1008 return c_name(self.name)
1010 def json_type(self):
1011 return 'object'
1013 def visit(self, visitor):
1014 visitor.visit_object_type(self.name, self.info,
1015 self.base, self.local_members, self.variants)
1016 visitor.visit_object_type_flat(self.name, self.info,
1017 self.members, self.variants)
1020 class QAPISchemaMember(object):
1021 role = 'member'
1023 def __init__(self, name):
1024 assert isinstance(name, str)
1025 self.name = name
1026 self.owner = None
1028 def set_owner(self, name):
1029 assert not self.owner
1030 self.owner = name
1032 def check_clash(self, info, seen):
1033 cname = c_name(self.name)
1034 if cname.lower() != cname and self.owner not in case_whitelist:
1035 raise QAPISemError(info,
1036 "%s should not use uppercase" % self.describe())
1037 if cname in seen:
1038 raise QAPISemError(info, "%s collides with %s" %
1039 (self.describe(), seen[cname].describe()))
1040 seen[cname] = self
1042 def _pretty_owner(self):
1043 owner = self.owner
1044 if owner.startswith('q_obj_'):
1045 # See QAPISchema._make_implicit_object_type() - reverse the
1046 # mapping there to create a nice human-readable description
1047 owner = owner[6:]
1048 if owner.endswith('-arg'):
1049 return '(parameter of %s)' % owner[:-4]
1050 elif owner.endswith('-base'):
1051 return '(base of %s)' % owner[:-5]
1052 else:
1053 assert owner.endswith('-wrapper')
1054 # Unreachable and not implemented
1055 assert False
1056 if owner.endswith('Kind'):
1057 # See QAPISchema._make_implicit_enum_type()
1058 return '(branch of %s)' % owner[:-4]
1059 return '(%s of %s)' % (self.role, owner)
1061 def describe(self):
1062 return "'%s' %s" % (self.name, self._pretty_owner())
1065 class QAPISchemaObjectTypeMember(QAPISchemaMember):
1066 def __init__(self, name, typ, optional):
1067 QAPISchemaMember.__init__(self, name)
1068 assert isinstance(typ, str)
1069 assert isinstance(optional, bool)
1070 self._type_name = typ
1071 self.type = None
1072 self.optional = optional
1074 def check(self, schema):
1075 assert self.owner
1076 self.type = schema.lookup_type(self._type_name)
1077 assert self.type
1080 class QAPISchemaObjectTypeVariants(object):
1081 def __init__(self, tag_name, tag_member, variants):
1082 # Flat unions pass tag_name but not tag_member.
1083 # Simple unions and alternates pass tag_member but not tag_name.
1084 # After check(), tag_member is always set, and tag_name remains
1085 # a reliable witness of being used by a flat union.
1086 assert bool(tag_member) != bool(tag_name)
1087 assert (isinstance(tag_name, str) or
1088 isinstance(tag_member, QAPISchemaObjectTypeMember))
1089 assert len(variants) > 0
1090 for v in variants:
1091 assert isinstance(v, QAPISchemaObjectTypeVariant)
1092 self._tag_name = tag_name
1093 self.tag_member = tag_member
1094 self.variants = variants
1096 def set_owner(self, name):
1097 for v in self.variants:
1098 v.set_owner(name)
1100 def check(self, schema, seen):
1101 if not self.tag_member: # flat union
1102 self.tag_member = seen[c_name(self._tag_name)]
1103 assert self._tag_name == self.tag_member.name
1104 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1105 for v in self.variants:
1106 v.check(schema)
1107 # Union names must match enum values; alternate names are
1108 # checked separately. Use 'seen' to tell the two apart.
1109 if seen:
1110 assert v.name in self.tag_member.type.member_names()
1111 assert isinstance(v.type, QAPISchemaObjectType)
1112 v.type.check(schema)
1114 def check_clash(self, schema, info, seen):
1115 for v in self.variants:
1116 # Reset seen map for each variant, since qapi names from one
1117 # branch do not affect another branch
1118 assert isinstance(v.type, QAPISchemaObjectType)
1119 v.type.check_clash(schema, info, dict(seen))
1122 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1123 role = 'branch'
1125 def __init__(self, name, typ):
1126 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1129 class QAPISchemaAlternateType(QAPISchemaType):
1130 def __init__(self, name, info, variants):
1131 QAPISchemaType.__init__(self, name, info)
1132 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1133 assert variants.tag_member
1134 variants.set_owner(name)
1135 variants.tag_member.set_owner(self.name)
1136 self.variants = variants
1138 def check(self, schema):
1139 self.variants.tag_member.check(schema)
1140 # Not calling self.variants.check_clash(), because there's nothing
1141 # to clash with
1142 self.variants.check(schema, {})
1143 # Alternate branch names have no relation to the tag enum values;
1144 # so we have to check for potential name collisions ourselves.
1145 seen = {}
1146 for v in self.variants.variants:
1147 v.check_clash(self.info, seen)
1149 def c_type(self):
1150 return c_name(self.name) + pointer_suffix
1152 def json_type(self):
1153 return 'value'
1155 def visit(self, visitor):
1156 visitor.visit_alternate_type(self.name, self.info, self.variants)
1158 def is_empty(self):
1159 return False
1162 class QAPISchemaCommand(QAPISchemaEntity):
1163 def __init__(self, name, info, arg_type, ret_type, gen, success_response,
1164 boxed):
1165 QAPISchemaEntity.__init__(self, name, info)
1166 assert not arg_type or isinstance(arg_type, str)
1167 assert not ret_type or isinstance(ret_type, str)
1168 self._arg_type_name = arg_type
1169 self.arg_type = None
1170 self._ret_type_name = ret_type
1171 self.ret_type = None
1172 self.gen = gen
1173 self.success_response = success_response
1174 self.boxed = boxed
1176 def check(self, schema):
1177 if self._arg_type_name:
1178 self.arg_type = schema.lookup_type(self._arg_type_name)
1179 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1180 isinstance(self.arg_type, QAPISchemaAlternateType))
1181 self.arg_type.check(schema)
1182 if self.boxed:
1183 if self.arg_type.is_empty():
1184 raise QAPISemError(self.info,
1185 "Cannot use 'boxed' with empty type")
1186 else:
1187 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1188 assert not self.arg_type.variants
1189 elif self.boxed:
1190 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
1191 if self._ret_type_name:
1192 self.ret_type = schema.lookup_type(self._ret_type_name)
1193 assert isinstance(self.ret_type, QAPISchemaType)
1195 def visit(self, visitor):
1196 visitor.visit_command(self.name, self.info,
1197 self.arg_type, self.ret_type,
1198 self.gen, self.success_response, self.boxed)
1201 class QAPISchemaEvent(QAPISchemaEntity):
1202 def __init__(self, name, info, arg_type, boxed):
1203 QAPISchemaEntity.__init__(self, name, info)
1204 assert not arg_type or isinstance(arg_type, str)
1205 self._arg_type_name = arg_type
1206 self.arg_type = None
1207 self.boxed = boxed
1209 def check(self, schema):
1210 if self._arg_type_name:
1211 self.arg_type = schema.lookup_type(self._arg_type_name)
1212 assert (isinstance(self.arg_type, QAPISchemaObjectType) or
1213 isinstance(self.arg_type, QAPISchemaAlternateType))
1214 self.arg_type.check(schema)
1215 if self.boxed:
1216 if self.arg_type.is_empty():
1217 raise QAPISemError(self.info,
1218 "Cannot use 'boxed' with empty type")
1219 else:
1220 assert not isinstance(self.arg_type, QAPISchemaAlternateType)
1221 assert not self.arg_type.variants
1222 elif self.boxed:
1223 raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
1225 def visit(self, visitor):
1226 visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
1229 class QAPISchema(object):
1230 def __init__(self, fname):
1231 try:
1232 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1233 self._entity_dict = {}
1234 self._predefining = True
1235 self._def_predefineds()
1236 self._predefining = False
1237 self._def_exprs()
1238 self.check()
1239 except QAPIError as err:
1240 print >>sys.stderr, err
1241 exit(1)
1243 def _def_entity(self, ent):
1244 # Only the predefined types are allowed to not have info
1245 assert ent.info or self._predefining
1246 assert ent.name not in self._entity_dict
1247 self._entity_dict[ent.name] = ent
1249 def lookup_entity(self, name, typ=None):
1250 ent = self._entity_dict.get(name)
1251 if typ and not isinstance(ent, typ):
1252 return None
1253 return ent
1255 def lookup_type(self, name):
1256 return self.lookup_entity(name, QAPISchemaType)
1258 def _def_builtin_type(self, name, json_type, c_type):
1259 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
1260 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1261 # qapi-types.h from a single .c, all arrays of builtins must be
1262 # declared in the first file whether or not they are used. Nicer
1263 # would be to use lazy instantiation, while figuring out how to
1264 # avoid compilation issues with multiple qapi-types.h.
1265 self._make_array_type(name, None)
1267 def _def_predefineds(self):
1268 for t in [('str', 'string', 'char' + pointer_suffix),
1269 ('number', 'number', 'double'),
1270 ('int', 'int', 'int64_t'),
1271 ('int8', 'int', 'int8_t'),
1272 ('int16', 'int', 'int16_t'),
1273 ('int32', 'int', 'int32_t'),
1274 ('int64', 'int', 'int64_t'),
1275 ('uint8', 'int', 'uint8_t'),
1276 ('uint16', 'int', 'uint16_t'),
1277 ('uint32', 'int', 'uint32_t'),
1278 ('uint64', 'int', 'uint64_t'),
1279 ('size', 'int', 'uint64_t'),
1280 ('bool', 'boolean', 'bool'),
1281 ('any', 'value', 'QObject' + pointer_suffix)]:
1282 self._def_builtin_type(*t)
1283 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1284 None, [], None)
1285 self._def_entity(self.the_empty_object_type)
1286 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1287 'qstring', 'qdict', 'qlist',
1288 'qfloat', 'qbool'])
1289 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
1290 'QTYPE'))
1292 def _make_enum_members(self, values):
1293 return [QAPISchemaMember(v) for v in values]
1295 def _make_implicit_enum_type(self, name, info, values):
1296 # See also QAPISchemaObjectTypeMember._pretty_owner()
1297 name = name + 'Kind' # Use namespace reserved by add_name()
1298 self._def_entity(QAPISchemaEnumType(
1299 name, info, self._make_enum_members(values), None))
1300 return name
1302 def _make_array_type(self, element_type, info):
1303 name = element_type + 'List' # Use namespace reserved by add_name()
1304 if not self.lookup_type(name):
1305 self._def_entity(QAPISchemaArrayType(name, info, element_type))
1306 return name
1308 def _make_implicit_object_type(self, name, info, role, members):
1309 if not members:
1310 return None
1311 # See also QAPISchemaObjectTypeMember._pretty_owner()
1312 name = 'q_obj_%s-%s' % (name, role)
1313 if not self.lookup_entity(name, QAPISchemaObjectType):
1314 self._def_entity(QAPISchemaObjectType(name, info, None,
1315 members, None))
1316 return name
1318 def _def_enum_type(self, expr, info):
1319 name = expr['enum']
1320 data = expr['data']
1321 prefix = expr.get('prefix')
1322 self._def_entity(QAPISchemaEnumType(
1323 name, info, self._make_enum_members(data), prefix))
1325 def _make_member(self, name, typ, info):
1326 optional = False
1327 if name.startswith('*'):
1328 name = name[1:]
1329 optional = True
1330 if isinstance(typ, list):
1331 assert len(typ) == 1
1332 typ = self._make_array_type(typ[0], info)
1333 return QAPISchemaObjectTypeMember(name, typ, optional)
1335 def _make_members(self, data, info):
1336 return [self._make_member(key, value, info)
1337 for (key, value) in data.iteritems()]
1339 def _def_struct_type(self, expr, info):
1340 name = expr['struct']
1341 base = expr.get('base')
1342 data = expr['data']
1343 self._def_entity(QAPISchemaObjectType(name, info, base,
1344 self._make_members(data, info),
1345 None))
1347 def _make_variant(self, case, typ):
1348 return QAPISchemaObjectTypeVariant(case, typ)
1350 def _make_simple_variant(self, case, typ, info):
1351 if isinstance(typ, list):
1352 assert len(typ) == 1
1353 typ = self._make_array_type(typ[0], info)
1354 typ = self._make_implicit_object_type(
1355 typ, info, 'wrapper', [self._make_member('data', typ, info)])
1356 return QAPISchemaObjectTypeVariant(case, typ)
1358 def _def_union_type(self, expr, info):
1359 name = expr['union']
1360 data = expr['data']
1361 base = expr.get('base')
1362 tag_name = expr.get('discriminator')
1363 tag_member = None
1364 if isinstance(base, dict):
1365 base = (self._make_implicit_object_type(
1366 name, info, 'base', self._make_members(base, info)))
1367 if tag_name:
1368 variants = [self._make_variant(key, value)
1369 for (key, value) in data.iteritems()]
1370 members = []
1371 else:
1372 variants = [self._make_simple_variant(key, value, info)
1373 for (key, value) in data.iteritems()]
1374 typ = self._make_implicit_enum_type(name, info,
1375 [v.name for v in variants])
1376 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
1377 members = [tag_member]
1378 self._def_entity(
1379 QAPISchemaObjectType(name, info, base, members,
1380 QAPISchemaObjectTypeVariants(tag_name,
1381 tag_member,
1382 variants)))
1384 def _def_alternate_type(self, expr, info):
1385 name = expr['alternate']
1386 data = expr['data']
1387 variants = [self._make_variant(key, value)
1388 for (key, value) in data.iteritems()]
1389 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
1390 self._def_entity(
1391 QAPISchemaAlternateType(name, info,
1392 QAPISchemaObjectTypeVariants(None,
1393 tag_member,
1394 variants)))
1396 def _def_command(self, expr, info):
1397 name = expr['command']
1398 data = expr.get('data')
1399 rets = expr.get('returns')
1400 gen = expr.get('gen', True)
1401 success_response = expr.get('success-response', True)
1402 boxed = expr.get('boxed', False)
1403 if isinstance(data, OrderedDict):
1404 data = self._make_implicit_object_type(
1405 name, info, 'arg', self._make_members(data, info))
1406 if isinstance(rets, list):
1407 assert len(rets) == 1
1408 rets = self._make_array_type(rets[0], info)
1409 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1410 success_response, boxed))
1412 def _def_event(self, expr, info):
1413 name = expr['event']
1414 data = expr.get('data')
1415 boxed = expr.get('boxed', False)
1416 if isinstance(data, OrderedDict):
1417 data = self._make_implicit_object_type(
1418 name, info, 'arg', self._make_members(data, info))
1419 self._def_entity(QAPISchemaEvent(name, info, data, boxed))
1421 def _def_exprs(self):
1422 for expr_elem in self.exprs:
1423 expr = expr_elem['expr']
1424 info = expr_elem['info']
1425 if 'enum' in expr:
1426 self._def_enum_type(expr, info)
1427 elif 'struct' in expr:
1428 self._def_struct_type(expr, info)
1429 elif 'union' in expr:
1430 self._def_union_type(expr, info)
1431 elif 'alternate' in expr:
1432 self._def_alternate_type(expr, info)
1433 elif 'command' in expr:
1434 self._def_command(expr, info)
1435 elif 'event' in expr:
1436 self._def_event(expr, info)
1437 else:
1438 assert False
1440 def check(self):
1441 for ent in self._entity_dict.values():
1442 ent.check(self)
1444 def visit(self, visitor):
1445 visitor.visit_begin(self)
1446 for (name, entity) in sorted(self._entity_dict.items()):
1447 if visitor.visit_needed(entity):
1448 entity.visit(visitor)
1449 visitor.visit_end()
1453 # Code generation helpers
1456 def camel_case(name):
1457 new_name = ''
1458 first = True
1459 for ch in name:
1460 if ch in ['_', '-']:
1461 first = True
1462 elif first:
1463 new_name += ch.upper()
1464 first = False
1465 else:
1466 new_name += ch.lower()
1467 return new_name
1470 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1471 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1472 # ENUM24_Name -> ENUM24_NAME
1473 def camel_to_upper(value):
1474 c_fun_str = c_name(value, False)
1475 if value.isupper():
1476 return c_fun_str
1478 new_name = ''
1479 l = len(c_fun_str)
1480 for i in range(l):
1481 c = c_fun_str[i]
1482 # When c is upper and no "_" appears before, do more checks
1483 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
1484 if i < l - 1 and c_fun_str[i + 1].islower():
1485 new_name += '_'
1486 elif c_fun_str[i - 1].isdigit():
1487 new_name += '_'
1488 new_name += c
1489 return new_name.lstrip('_').upper()
1492 def c_enum_const(type_name, const_name, prefix=None):
1493 if prefix is not None:
1494 type_name = prefix
1495 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
1497 c_name_trans = string.maketrans('.-', '__')
1500 # Map @name to a valid C identifier.
1501 # If @protect, avoid returning certain ticklish identifiers (like
1502 # C keywords) by prepending "q_".
1504 # Used for converting 'name' from a 'name':'type' qapi definition
1505 # into a generated struct member, as well as converting type names
1506 # into substrings of a generated C function name.
1507 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1508 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1509 def c_name(name, protect=True):
1510 # ANSI X3J11/88-090, 3.1.1
1511 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1512 'default', 'do', 'double', 'else', 'enum', 'extern',
1513 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1514 'return', 'short', 'signed', 'sizeof', 'static',
1515 'struct', 'switch', 'typedef', 'union', 'unsigned',
1516 'void', 'volatile', 'while'])
1517 # ISO/IEC 9899:1999, 6.4.1
1518 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1519 # ISO/IEC 9899:2011, 6.4.1
1520 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1521 '_Noreturn', '_Static_assert', '_Thread_local'])
1522 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1523 # excluding _.*
1524 gcc_words = set(['asm', 'typeof'])
1525 # C++ ISO/IEC 14882:2003 2.11
1526 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1527 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1528 'namespace', 'new', 'operator', 'private', 'protected',
1529 'public', 'reinterpret_cast', 'static_cast', 'template',
1530 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1531 'using', 'virtual', 'wchar_t',
1532 # alternative representations
1533 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1534 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1535 # namespace pollution:
1536 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
1537 name = name.translate(c_name_trans)
1538 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1539 | cpp_words | polluted_words):
1540 return "q_" + name
1541 return name
1543 eatspace = '\033EATSPACE.'
1544 pointer_suffix = ' *' + eatspace
1547 def genindent(count):
1548 ret = ""
1549 for _ in range(count):
1550 ret += " "
1551 return ret
1553 indent_level = 0
1556 def push_indent(indent_amount=4):
1557 global indent_level
1558 indent_level += indent_amount
1561 def pop_indent(indent_amount=4):
1562 global indent_level
1563 indent_level -= indent_amount
1566 # Generate @code with @kwds interpolated.
1567 # Obey indent_level, and strip eatspace.
1568 def cgen(code, **kwds):
1569 raw = code % kwds
1570 if indent_level:
1571 indent = genindent(indent_level)
1572 # re.subn() lacks flags support before Python 2.7, use re.compile()
1573 raw = re.subn(re.compile("^.", re.MULTILINE),
1574 indent + r'\g<0>', raw)
1575 raw = raw[0]
1576 return re.sub(re.escape(eatspace) + ' *', '', raw)
1579 def mcgen(code, **kwds):
1580 if code[0] == '\n':
1581 code = code[1:]
1582 return cgen(code, **kwds)
1585 def guardname(filename):
1586 return c_name(filename, protect=False).upper()
1589 def guardstart(name):
1590 return mcgen('''
1592 #ifndef %(name)s
1593 #define %(name)s
1595 ''',
1596 name=guardname(name))
1599 def guardend(name):
1600 return mcgen('''
1602 #endif /* %(name)s */
1604 ''',
1605 name=guardname(name))
1608 def gen_enum_lookup(name, values, prefix=None):
1609 ret = mcgen('''
1611 const char *const %(c_name)s_lookup[] = {
1612 ''',
1613 c_name=c_name(name))
1614 for value in values:
1615 index = c_enum_const(name, value, prefix)
1616 ret += mcgen('''
1617 [%(index)s] = "%(value)s",
1618 ''',
1619 index=index, value=value)
1621 max_index = c_enum_const(name, '_MAX', prefix)
1622 ret += mcgen('''
1623 [%(max_index)s] = NULL,
1625 ''',
1626 max_index=max_index)
1627 return ret
1630 def gen_enum(name, values, prefix=None):
1631 # append automatically generated _MAX value
1632 enum_values = values + ['_MAX']
1634 ret = mcgen('''
1636 typedef enum %(c_name)s {
1637 ''',
1638 c_name=c_name(name))
1640 i = 0
1641 for value in enum_values:
1642 ret += mcgen('''
1643 %(c_enum)s = %(i)d,
1644 ''',
1645 c_enum=c_enum_const(name, value, prefix),
1646 i=i)
1647 i += 1
1649 ret += mcgen('''
1650 } %(c_name)s;
1651 ''',
1652 c_name=c_name(name))
1654 ret += mcgen('''
1656 extern const char *const %(c_name)s_lookup[];
1657 ''',
1658 c_name=c_name(name))
1659 return ret
1662 def gen_params(arg_type, boxed, extra):
1663 if not arg_type:
1664 assert not boxed
1665 return extra
1666 ret = ''
1667 sep = ''
1668 if boxed:
1669 ret += '%s arg' % arg_type.c_param_type()
1670 sep = ', '
1671 else:
1672 assert not arg_type.variants
1673 for memb in arg_type.members:
1674 ret += sep
1675 sep = ', '
1676 if memb.optional:
1677 ret += 'bool has_%s, ' % c_name(memb.name)
1678 ret += '%s %s' % (memb.type.c_param_type(),
1679 c_name(memb.name))
1680 if extra:
1681 ret += sep + extra
1682 return ret
1686 # Common command line parsing
1690 def parse_command_line(extra_options="", extra_long_options=[]):
1692 try:
1693 opts, args = getopt.gnu_getopt(sys.argv[1:],
1694 "chp:o:" + extra_options,
1695 ["source", "header", "prefix=",
1696 "output-dir="] + extra_long_options)
1697 except getopt.GetoptError as err:
1698 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1699 sys.exit(1)
1701 output_dir = ""
1702 prefix = ""
1703 do_c = False
1704 do_h = False
1705 extra_opts = []
1707 for oa in opts:
1708 o, a = oa
1709 if o in ("-p", "--prefix"):
1710 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1711 if match.end() != len(a):
1712 print >>sys.stderr, \
1713 "%s: 'funny character '%s' in argument of --prefix" \
1714 % (sys.argv[0], a[match.end()])
1715 sys.exit(1)
1716 prefix = a
1717 elif o in ("-o", "--output-dir"):
1718 output_dir = a + "/"
1719 elif o in ("-c", "--source"):
1720 do_c = True
1721 elif o in ("-h", "--header"):
1722 do_h = True
1723 else:
1724 extra_opts.append(oa)
1726 if not do_c and not do_h:
1727 do_c = True
1728 do_h = True
1730 if len(args) != 1:
1731 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1732 sys.exit(1)
1733 fname = args[0]
1735 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1738 # Generate output files with boilerplate
1742 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1743 c_comment, h_comment):
1744 guard = guardname(prefix + h_file)
1745 c_file = output_dir + prefix + c_file
1746 h_file = output_dir + prefix + h_file
1748 if output_dir:
1749 try:
1750 os.makedirs(output_dir)
1751 except os.error as e:
1752 if e.errno != errno.EEXIST:
1753 raise
1755 def maybe_open(really, name, opt):
1756 if really:
1757 return open(name, opt)
1758 else:
1759 import StringIO
1760 return StringIO.StringIO()
1762 fdef = maybe_open(do_c, c_file, 'w')
1763 fdecl = maybe_open(do_h, h_file, 'w')
1765 fdef.write(mcgen('''
1766 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1767 %(comment)s
1768 ''',
1769 comment=c_comment))
1771 fdecl.write(mcgen('''
1772 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1773 %(comment)s
1774 #ifndef %(guard)s
1775 #define %(guard)s
1777 ''',
1778 comment=h_comment, guard=guard))
1780 return (fdef, fdecl)
1783 def close_output(fdef, fdecl):
1784 fdecl.write('''
1785 #endif
1786 ''')
1787 fdecl.close()
1788 fdef.close()