qapi: Inline _make_implicit_tag()
[qemu.git] / scripts / qapi.py
blob7e6c396a1d0cde81116c3e28713e8af70be7a6f4
2 # QAPI helper library
4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2015 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 enum_types = []
63 struct_types = []
64 union_types = []
65 events = []
66 all_names = {}
69 # Parsing the schema into expressions
73 def error_path(parent):
74 res = ""
75 while parent:
76 res = ("In file included from %s:%d:\n" % (parent['file'],
77 parent['line'])) + res
78 parent = parent['parent']
79 return res
82 class QAPISchemaError(Exception):
83 def __init__(self, schema, msg):
84 Exception.__init__(self)
85 self.fname = schema.fname
86 self.msg = msg
87 self.col = 1
88 self.line = schema.line
89 for ch in schema.src[schema.line_pos:schema.pos]:
90 if ch == '\t':
91 self.col = (self.col + 7) % 8 + 1
92 else:
93 self.col += 1
94 self.info = schema.incl_info
96 def __str__(self):
97 return error_path(self.info) + \
98 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
101 class QAPIExprError(Exception):
102 def __init__(self, expr_info, msg):
103 Exception.__init__(self)
104 assert expr_info
105 self.info = expr_info
106 self.msg = msg
108 def __str__(self):
109 return error_path(self.info['parent']) + \
110 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
113 class QAPISchemaParser(object):
115 def __init__(self, fp, previously_included=[], incl_info=None):
116 abs_fname = os.path.abspath(fp.name)
117 fname = fp.name
118 self.fname = fname
119 previously_included.append(abs_fname)
120 self.incl_info = incl_info
121 self.src = fp.read()
122 if self.src == '' or self.src[-1] != '\n':
123 self.src += '\n'
124 self.cursor = 0
125 self.line = 1
126 self.line_pos = 0
127 self.exprs = []
128 self.accept()
130 while self.tok is not None:
131 expr_info = {'file': fname, 'line': self.line,
132 'parent': self.incl_info}
133 expr = self.get_expr(False)
134 if isinstance(expr, dict) and "include" in expr:
135 if len(expr) != 1:
136 raise QAPIExprError(expr_info,
137 "Invalid 'include' directive")
138 include = expr["include"]
139 if not isinstance(include, str):
140 raise QAPIExprError(expr_info,
141 "Value of 'include' must be a string")
142 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
143 include)
144 # catch inclusion cycle
145 inf = expr_info
146 while inf:
147 if incl_abs_fname == os.path.abspath(inf['file']):
148 raise QAPIExprError(expr_info, "Inclusion loop for %s"
149 % include)
150 inf = inf['parent']
151 # skip multiple include of the same file
152 if incl_abs_fname in previously_included:
153 continue
154 try:
155 fobj = open(incl_abs_fname, 'r')
156 except IOError, e:
157 raise QAPIExprError(expr_info,
158 '%s: %s' % (e.strerror, include))
159 exprs_include = QAPISchemaParser(fobj, previously_included,
160 expr_info)
161 self.exprs.extend(exprs_include.exprs)
162 else:
163 expr_elem = {'expr': expr,
164 'info': expr_info}
165 self.exprs.append(expr_elem)
167 def accept(self):
168 while True:
169 self.tok = self.src[self.cursor]
170 self.pos = self.cursor
171 self.cursor += 1
172 self.val = None
174 if self.tok == '#':
175 self.cursor = self.src.find('\n', self.cursor)
176 elif self.tok in "{}:,[]":
177 return
178 elif self.tok == "'":
179 string = ''
180 esc = False
181 while True:
182 ch = self.src[self.cursor]
183 self.cursor += 1
184 if ch == '\n':
185 raise QAPISchemaError(self,
186 'Missing terminating "\'"')
187 if esc:
188 if ch == 'b':
189 string += '\b'
190 elif ch == 'f':
191 string += '\f'
192 elif ch == 'n':
193 string += '\n'
194 elif ch == 'r':
195 string += '\r'
196 elif ch == 't':
197 string += '\t'
198 elif ch == 'u':
199 value = 0
200 for _ in range(0, 4):
201 ch = self.src[self.cursor]
202 self.cursor += 1
203 if ch not in "0123456789abcdefABCDEF":
204 raise QAPISchemaError(self,
205 '\\u escape needs 4 '
206 'hex digits')
207 value = (value << 4) + int(ch, 16)
208 # If Python 2 and 3 didn't disagree so much on
209 # how to handle Unicode, then we could allow
210 # Unicode string defaults. But most of QAPI is
211 # ASCII-only, so we aren't losing much for now.
212 if not value or value > 0x7f:
213 raise QAPISchemaError(self,
214 'For now, \\u escape '
215 'only supports non-zero '
216 'values up to \\u007f')
217 string += chr(value)
218 elif ch in "\\/'\"":
219 string += ch
220 else:
221 raise QAPISchemaError(self,
222 "Unknown escape \\%s" % ch)
223 esc = False
224 elif ch == "\\":
225 esc = True
226 elif ch == "'":
227 self.val = string
228 return
229 else:
230 string += ch
231 elif self.src.startswith("true", self.pos):
232 self.val = True
233 self.cursor += 3
234 return
235 elif self.src.startswith("false", self.pos):
236 self.val = False
237 self.cursor += 4
238 return
239 elif self.src.startswith("null", self.pos):
240 self.val = None
241 self.cursor += 3
242 return
243 elif self.tok == '\n':
244 if self.cursor == len(self.src):
245 self.tok = None
246 return
247 self.line += 1
248 self.line_pos = self.cursor
249 elif not self.tok.isspace():
250 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
252 def get_members(self):
253 expr = OrderedDict()
254 if self.tok == '}':
255 self.accept()
256 return expr
257 if self.tok != "'":
258 raise QAPISchemaError(self, 'Expected string or "}"')
259 while True:
260 key = self.val
261 self.accept()
262 if self.tok != ':':
263 raise QAPISchemaError(self, 'Expected ":"')
264 self.accept()
265 if key in expr:
266 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
267 expr[key] = self.get_expr(True)
268 if self.tok == '}':
269 self.accept()
270 return expr
271 if self.tok != ',':
272 raise QAPISchemaError(self, 'Expected "," or "}"')
273 self.accept()
274 if self.tok != "'":
275 raise QAPISchemaError(self, 'Expected string')
277 def get_values(self):
278 expr = []
279 if self.tok == ']':
280 self.accept()
281 return expr
282 if self.tok not in "{['tfn":
283 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
284 'boolean or "null"')
285 while True:
286 expr.append(self.get_expr(True))
287 if self.tok == ']':
288 self.accept()
289 return expr
290 if self.tok != ',':
291 raise QAPISchemaError(self, 'Expected "," or "]"')
292 self.accept()
294 def get_expr(self, nested):
295 if self.tok != '{' and not nested:
296 raise QAPISchemaError(self, 'Expected "{"')
297 if self.tok == '{':
298 self.accept()
299 expr = self.get_members()
300 elif self.tok == '[':
301 self.accept()
302 expr = self.get_values()
303 elif self.tok in "'tfn":
304 expr = self.val
305 self.accept()
306 else:
307 raise QAPISchemaError(self, 'Expected "{", "[" or string')
308 return expr
311 # Semantic analysis of schema expressions
312 # TODO fold into QAPISchema
313 # TODO catching name collisions in generated code would be nice
317 def find_base_fields(base):
318 base_struct_define = find_struct(base)
319 if not base_struct_define:
320 return None
321 return base_struct_define['data']
324 # Return the qtype of an alternate branch, or None on error.
325 def find_alternate_member_qtype(qapi_type):
326 if qapi_type in builtin_types:
327 return builtin_types[qapi_type]
328 elif find_struct(qapi_type):
329 return "QTYPE_QDICT"
330 elif find_enum(qapi_type):
331 return "QTYPE_QSTRING"
332 elif find_union(qapi_type):
333 return "QTYPE_QDICT"
334 return None
337 # Return the discriminator enum define if discriminator is specified as an
338 # enum type, otherwise return None.
339 def discriminator_find_enum_define(expr):
340 base = expr.get('base')
341 discriminator = expr.get('discriminator')
343 if not (discriminator and base):
344 return None
346 base_fields = find_base_fields(base)
347 if not base_fields:
348 return None
350 discriminator_type = base_fields.get(discriminator)
351 if not discriminator_type:
352 return None
354 return find_enum(discriminator_type)
357 # Names must be letters, numbers, -, and _. They must start with letter,
358 # except for downstream extensions which must start with __RFQDN_.
359 # Dots are only valid in the downstream extension prefix.
360 valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
361 '[a-zA-Z][a-zA-Z0-9_-]*$')
364 def check_name(expr_info, source, name, allow_optional=False,
365 enum_member=False):
366 global valid_name
367 membername = name
369 if not isinstance(name, str):
370 raise QAPIExprError(expr_info,
371 "%s requires a string name" % source)
372 if name.startswith('*'):
373 membername = name[1:]
374 if not allow_optional:
375 raise QAPIExprError(expr_info,
376 "%s does not allow optional name '%s'"
377 % (source, name))
378 # Enum members can start with a digit, because the generated C
379 # code always prefixes it with the enum name
380 if enum_member and membername[0].isdigit():
381 membername = 'D' + membername
382 # Reserve the entire 'q_' namespace for c_name()
383 if not valid_name.match(membername) or \
384 c_name(membername, False).startswith('q_'):
385 raise QAPIExprError(expr_info,
386 "%s uses invalid name '%s'" % (source, name))
389 def add_name(name, info, meta, implicit=False):
390 global all_names
391 check_name(info, "'%s'" % meta, name)
392 # FIXME should reject names that differ only in '_' vs. '.'
393 # vs. '-', because they're liable to clash in generated C.
394 if name in all_names:
395 raise QAPIExprError(info,
396 "%s '%s' is already defined"
397 % (all_names[name], name))
398 if not implicit and (name.endswith('Kind') or name.endswith('List')):
399 raise QAPIExprError(info,
400 "%s '%s' should not end in '%s'"
401 % (meta, name, name[-4:]))
402 all_names[name] = meta
405 def add_struct(definition, info):
406 global struct_types
407 name = definition['struct']
408 add_name(name, info, 'struct')
409 struct_types.append(definition)
412 def find_struct(name):
413 global struct_types
414 for struct in struct_types:
415 if struct['struct'] == name:
416 return struct
417 return None
420 def add_union(definition, info):
421 global union_types
422 name = definition['union']
423 add_name(name, info, 'union')
424 union_types.append(definition)
427 def find_union(name):
428 global union_types
429 for union in union_types:
430 if union['union'] == name:
431 return union
432 return None
435 def add_enum(name, info, enum_values=None, implicit=False):
436 global enum_types
437 add_name(name, info, 'enum', implicit)
438 enum_types.append({"enum_name": name, "enum_values": enum_values})
441 def find_enum(name):
442 global enum_types
443 for enum in enum_types:
444 if enum['enum_name'] == name:
445 return enum
446 return None
449 def is_enum(name):
450 return find_enum(name) is not None
453 def check_type(expr_info, source, value, allow_array=False,
454 allow_dict=False, allow_optional=False,
455 allow_metas=[]):
456 global all_names
458 if value is None:
459 return
461 # Check if array type for value is okay
462 if isinstance(value, list):
463 if not allow_array:
464 raise QAPIExprError(expr_info,
465 "%s cannot be an array" % source)
466 if len(value) != 1 or not isinstance(value[0], str):
467 raise QAPIExprError(expr_info,
468 "%s: array type must contain single type name"
469 % source)
470 value = value[0]
472 # Check if type name for value is okay
473 if isinstance(value, str):
474 if value not in all_names:
475 raise QAPIExprError(expr_info,
476 "%s uses unknown type '%s'"
477 % (source, value))
478 if not all_names[value] in allow_metas:
479 raise QAPIExprError(expr_info,
480 "%s cannot use %s type '%s'"
481 % (source, all_names[value], value))
482 return
484 if not allow_dict:
485 raise QAPIExprError(expr_info,
486 "%s should be a type name" % source)
488 if not isinstance(value, OrderedDict):
489 raise QAPIExprError(expr_info,
490 "%s should be a dictionary or type name" % source)
492 # value is a dictionary, check that each member is okay
493 for (key, arg) in value.items():
494 check_name(expr_info, "Member of %s" % source, key,
495 allow_optional=allow_optional)
496 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
497 raise QAPIExprError(expr_info,
498 "Member of %s uses reserved name '%s'"
499 % (source, key))
500 # Todo: allow dictionaries to represent default values of
501 # an optional argument.
502 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
503 allow_array=True,
504 allow_metas=['built-in', 'union', 'alternate', 'struct',
505 'enum'])
508 def check_member_clash(expr_info, base_name, data, source=""):
509 base = find_struct(base_name)
510 assert base
511 base_members = base['data']
512 for key in data.keys():
513 if key.startswith('*'):
514 key = key[1:]
515 if key in base_members or "*" + key in base_members:
516 raise QAPIExprError(expr_info,
517 "Member name '%s'%s clashes with base '%s'"
518 % (key, source, base_name))
519 if base.get('base'):
520 check_member_clash(expr_info, base['base'], data, source)
523 def check_command(expr, expr_info):
524 name = expr['command']
526 check_type(expr_info, "'data' for command '%s'" % name,
527 expr.get('data'), allow_dict=True, allow_optional=True,
528 allow_metas=['struct'])
529 returns_meta = ['union', 'struct']
530 if name in returns_whitelist:
531 returns_meta += ['built-in', 'alternate', 'enum']
532 check_type(expr_info, "'returns' for command '%s'" % name,
533 expr.get('returns'), allow_array=True,
534 allow_optional=True, allow_metas=returns_meta)
537 def check_event(expr, expr_info):
538 global events
539 name = expr['event']
541 events.append(name)
542 check_type(expr_info, "'data' for event '%s'" % name,
543 expr.get('data'), allow_dict=True, allow_optional=True,
544 allow_metas=['struct'])
547 def check_union(expr, expr_info):
548 name = expr['union']
549 base = expr.get('base')
550 discriminator = expr.get('discriminator')
551 members = expr['data']
552 values = {}
554 # Two types of unions, determined by discriminator.
556 # With no discriminator it is a simple union.
557 if discriminator is None:
558 enum_define = None
559 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
560 if base is not None:
561 raise QAPIExprError(expr_info,
562 "Simple union '%s' must not have a base"
563 % name)
565 # Else, it's a flat union.
566 else:
567 # The object must have a string member 'base'.
568 check_type(expr_info, "'base' for union '%s'" % name,
569 base, allow_metas=['struct'])
570 if not base:
571 raise QAPIExprError(expr_info,
572 "Flat union '%s' must have a base"
573 % name)
574 base_fields = find_base_fields(base)
575 assert base_fields
577 # The value of member 'discriminator' must name a non-optional
578 # member of the base struct.
579 check_name(expr_info, "Discriminator of flat union '%s'" % name,
580 discriminator)
581 discriminator_type = base_fields.get(discriminator)
582 if not discriminator_type:
583 raise QAPIExprError(expr_info,
584 "Discriminator '%s' is not a member of base "
585 "struct '%s'"
586 % (discriminator, base))
587 enum_define = find_enum(discriminator_type)
588 allow_metas = ['struct']
589 # Do not allow string discriminator
590 if not enum_define:
591 raise QAPIExprError(expr_info,
592 "Discriminator '%s' must be of enumeration "
593 "type" % discriminator)
595 # Check every branch
596 for (key, value) in members.items():
597 check_name(expr_info, "Member of union '%s'" % name, key)
599 # Each value must name a known type; furthermore, in flat unions,
600 # branches must be a struct with no overlapping member names
601 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
602 value, allow_array=not base, allow_metas=allow_metas)
603 if base:
604 branch_struct = find_struct(value)
605 assert branch_struct
606 check_member_clash(expr_info, base, branch_struct['data'],
607 " of branch '%s'" % key)
609 # If the discriminator names an enum type, then all members
610 # of 'data' must also be members of the enum type.
611 if enum_define:
612 if key not in enum_define['enum_values']:
613 raise QAPIExprError(expr_info,
614 "Discriminator value '%s' is not found in "
615 "enum '%s'" %
616 (key, enum_define["enum_name"]))
618 # Otherwise, check for conflicts in the generated enum
619 else:
620 c_key = camel_to_upper(key)
621 if c_key in values:
622 raise QAPIExprError(expr_info,
623 "Union '%s' member '%s' clashes with '%s'"
624 % (name, key, values[c_key]))
625 values[c_key] = key
628 def check_alternate(expr, expr_info):
629 name = expr['alternate']
630 members = expr['data']
631 values = {}
632 types_seen = {}
634 # Check every branch
635 for (key, value) in members.items():
636 check_name(expr_info, "Member of alternate '%s'" % name, key)
638 # Check for conflicts in the branch names
639 c_key = c_name(key)
640 if c_key in values:
641 raise QAPIExprError(expr_info,
642 "Alternate '%s' member '%s' clashes with '%s'"
643 % (name, key, values[c_key]))
644 values[c_key] = key
646 # Ensure alternates have no type conflicts.
647 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
648 value,
649 allow_metas=['built-in', 'union', 'struct', 'enum'])
650 qtype = find_alternate_member_qtype(value)
651 assert qtype
652 if qtype in types_seen:
653 raise QAPIExprError(expr_info,
654 "Alternate '%s' member '%s' can't "
655 "be distinguished from member '%s'"
656 % (name, key, types_seen[qtype]))
657 types_seen[qtype] = key
660 def check_enum(expr, expr_info):
661 name = expr['enum']
662 members = expr.get('data')
663 prefix = expr.get('prefix')
664 values = {}
666 if not isinstance(members, list):
667 raise QAPIExprError(expr_info,
668 "Enum '%s' requires an array for 'data'" % name)
669 if prefix is not None and not isinstance(prefix, str):
670 raise QAPIExprError(expr_info,
671 "Enum '%s' requires a string for 'prefix'" % name)
672 for member in members:
673 check_name(expr_info, "Member of enum '%s'" % name, member,
674 enum_member=True)
675 key = camel_to_upper(member)
676 if key in values:
677 raise QAPIExprError(expr_info,
678 "Enum '%s' member '%s' clashes with '%s'"
679 % (name, member, values[key]))
680 values[key] = member
683 def check_struct(expr, expr_info):
684 name = expr['struct']
685 members = expr['data']
687 check_type(expr_info, "'data' for struct '%s'" % name, members,
688 allow_dict=True, allow_optional=True)
689 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
690 allow_metas=['struct'])
691 if expr.get('base'):
692 check_member_clash(expr_info, expr['base'], expr['data'])
695 def check_keys(expr_elem, meta, required, optional=[]):
696 expr = expr_elem['expr']
697 info = expr_elem['info']
698 name = expr[meta]
699 if not isinstance(name, str):
700 raise QAPIExprError(info,
701 "'%s' key must have a string value" % meta)
702 required = required + [meta]
703 for (key, value) in expr.items():
704 if key not in required and key not in optional:
705 raise QAPIExprError(info,
706 "Unknown key '%s' in %s '%s'"
707 % (key, meta, name))
708 if (key == 'gen' or key == 'success-response') and value is not False:
709 raise QAPIExprError(info,
710 "'%s' of %s '%s' should only use false value"
711 % (key, meta, name))
712 for key in required:
713 if key not in expr:
714 raise QAPIExprError(info,
715 "Key '%s' is missing from %s '%s'"
716 % (key, meta, name))
719 def check_exprs(exprs):
720 global all_names
722 # Learn the types and check for valid expression keys
723 for builtin in builtin_types.keys():
724 all_names[builtin] = 'built-in'
725 for expr_elem in exprs:
726 expr = expr_elem['expr']
727 info = expr_elem['info']
728 if 'enum' in expr:
729 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
730 add_enum(expr['enum'], info, expr['data'])
731 elif 'union' in expr:
732 check_keys(expr_elem, 'union', ['data'],
733 ['base', 'discriminator'])
734 add_union(expr, info)
735 elif 'alternate' in expr:
736 check_keys(expr_elem, 'alternate', ['data'])
737 add_name(expr['alternate'], info, 'alternate')
738 elif 'struct' in expr:
739 check_keys(expr_elem, 'struct', ['data'], ['base'])
740 add_struct(expr, info)
741 elif 'command' in expr:
742 check_keys(expr_elem, 'command', [],
743 ['data', 'returns', 'gen', 'success-response'])
744 add_name(expr['command'], info, 'command')
745 elif 'event' in expr:
746 check_keys(expr_elem, 'event', [], ['data'])
747 add_name(expr['event'], info, 'event')
748 else:
749 raise QAPIExprError(expr_elem['info'],
750 "Expression is missing metatype")
752 # Try again for hidden UnionKind enum
753 for expr_elem in exprs:
754 expr = expr_elem['expr']
755 if 'union' in expr:
756 if not discriminator_find_enum_define(expr):
757 add_enum('%sKind' % expr['union'], expr_elem['info'],
758 implicit=True)
759 elif 'alternate' in expr:
760 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
761 implicit=True)
763 # Validate that exprs make sense
764 for expr_elem in exprs:
765 expr = expr_elem['expr']
766 info = expr_elem['info']
768 if 'enum' in expr:
769 check_enum(expr, info)
770 elif 'union' in expr:
771 check_union(expr, info)
772 elif 'alternate' in expr:
773 check_alternate(expr, info)
774 elif 'struct' in expr:
775 check_struct(expr, info)
776 elif 'command' in expr:
777 check_command(expr, info)
778 elif 'event' in expr:
779 check_event(expr, info)
780 else:
781 assert False, 'unexpected meta type'
783 return exprs
787 # Schema compiler frontend
790 class QAPISchemaEntity(object):
791 def __init__(self, name, info):
792 assert isinstance(name, str)
793 self.name = name
794 # For explicitly defined entities, info points to the (explicit)
795 # definition. For builtins (and their arrays), info is None.
796 # For implicitly defined entities, info points to a place that
797 # triggered the implicit definition (there may be more than one
798 # such place).
799 self.info = info
801 def c_name(self):
802 return c_name(self.name)
804 def check(self, schema):
805 pass
807 def is_implicit(self):
808 return not self.info
810 def visit(self, visitor):
811 pass
814 class QAPISchemaVisitor(object):
815 def visit_begin(self, schema):
816 pass
818 def visit_end(self):
819 pass
821 def visit_needed(self, entity):
822 # Default to visiting everything
823 return True
825 def visit_builtin_type(self, name, info, json_type):
826 pass
828 def visit_enum_type(self, name, info, values, prefix):
829 pass
831 def visit_array_type(self, name, info, element_type):
832 pass
834 def visit_object_type(self, name, info, base, members, variants):
835 pass
837 def visit_object_type_flat(self, name, info, members, variants):
838 pass
840 def visit_alternate_type(self, name, info, variants):
841 pass
843 def visit_command(self, name, info, arg_type, ret_type,
844 gen, success_response):
845 pass
847 def visit_event(self, name, info, arg_type):
848 pass
851 class QAPISchemaType(QAPISchemaEntity):
852 def c_type(self, is_param=False):
853 return c_name(self.name) + pointer_suffix
855 def c_null(self):
856 return 'NULL'
858 def json_type(self):
859 pass
861 def alternate_qtype(self):
862 json2qtype = {
863 'string': 'QTYPE_QSTRING',
864 'number': 'QTYPE_QFLOAT',
865 'int': 'QTYPE_QINT',
866 'boolean': 'QTYPE_QBOOL',
867 'object': 'QTYPE_QDICT'
869 return json2qtype.get(self.json_type())
872 class QAPISchemaBuiltinType(QAPISchemaType):
873 def __init__(self, name, json_type, c_type, c_null):
874 QAPISchemaType.__init__(self, name, None)
875 assert not c_type or isinstance(c_type, str)
876 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
877 'value')
878 self._json_type_name = json_type
879 self._c_type_name = c_type
880 self._c_null_val = c_null
882 def c_name(self):
883 return self.name
885 def c_type(self, is_param=False):
886 if is_param and self.name == 'str':
887 return 'const ' + self._c_type_name
888 return self._c_type_name
890 def c_null(self):
891 return self._c_null_val
893 def json_type(self):
894 return self._json_type_name
896 def visit(self, visitor):
897 visitor.visit_builtin_type(self.name, self.info, self.json_type())
900 class QAPISchemaEnumType(QAPISchemaType):
901 def __init__(self, name, info, values, prefix):
902 QAPISchemaType.__init__(self, name, info)
903 for v in values:
904 assert isinstance(v, str)
905 assert prefix is None or isinstance(prefix, str)
906 self.values = values
907 self.prefix = prefix
909 def check(self, schema):
910 assert len(set(self.values)) == len(self.values)
912 def is_implicit(self):
913 # See QAPISchema._make_implicit_enum_type()
914 return self.name.endswith('Kind')
916 def c_type(self, is_param=False):
917 return c_name(self.name)
919 def c_null(self):
920 return c_enum_const(self.name, (self.values + ['_MAX'])[0],
921 self.prefix)
923 def json_type(self):
924 return 'string'
926 def visit(self, visitor):
927 visitor.visit_enum_type(self.name, self.info,
928 self.values, self.prefix)
931 class QAPISchemaArrayType(QAPISchemaType):
932 def __init__(self, name, info, element_type):
933 QAPISchemaType.__init__(self, name, info)
934 assert isinstance(element_type, str)
935 self._element_type_name = element_type
936 self.element_type = None
938 def check(self, schema):
939 self.element_type = schema.lookup_type(self._element_type_name)
940 assert self.element_type
942 def is_implicit(self):
943 return True
945 def json_type(self):
946 return 'array'
948 def visit(self, visitor):
949 visitor.visit_array_type(self.name, self.info, self.element_type)
952 class QAPISchemaObjectType(QAPISchemaType):
953 def __init__(self, name, info, base, local_members, variants):
954 # struct has local_members, optional base, and no variants
955 # flat union has base, variants, and no local_members
956 # simple union has local_members, variants, and no base
957 QAPISchemaType.__init__(self, name, info)
958 assert base is None or isinstance(base, str)
959 for m in local_members:
960 assert isinstance(m, QAPISchemaObjectTypeMember)
961 m.set_owner(name)
962 if variants is not None:
963 assert isinstance(variants, QAPISchemaObjectTypeVariants)
964 variants.set_owner(name)
965 self._base_name = base
966 self.base = None
967 self.local_members = local_members
968 self.variants = variants
969 self.members = None
971 def check(self, schema):
972 assert self.members is not False # not running in cycles
973 if self.members:
974 return
975 self.members = False # mark as being checked
976 seen = OrderedDict()
977 if self._base_name:
978 self.base = schema.lookup_type(self._base_name)
979 assert isinstance(self.base, QAPISchemaObjectType)
980 self.base.check(schema)
981 self.base.check_clash(schema, self.info, seen)
982 for m in self.local_members:
983 m.check(schema)
984 m.check_clash(self.info, seen)
985 self.members = seen.values()
986 if self.variants:
987 self.variants.check(schema, seen)
988 assert self.variants.tag_member in self.members
989 self.variants.check_clash(schema, self.info, seen)
991 # Check that the members of this type do not cause duplicate JSON fields,
992 # and update seen to track the members seen so far. Report any errors
993 # on behalf of info, which is not necessarily self.info
994 def check_clash(self, schema, info, seen):
995 assert not self.variants # not implemented
996 for m in self.members:
997 m.check_clash(info, seen)
999 def is_implicit(self):
1000 # See QAPISchema._make_implicit_object_type()
1001 return self.name[0] == ':'
1003 def c_name(self):
1004 assert not self.is_implicit()
1005 return QAPISchemaType.c_name(self)
1007 def c_type(self, is_param=False):
1008 assert not self.is_implicit()
1009 return QAPISchemaType.c_type(self)
1011 def json_type(self):
1012 return 'object'
1014 def visit(self, visitor):
1015 visitor.visit_object_type(self.name, self.info,
1016 self.base, self.local_members, self.variants)
1017 visitor.visit_object_type_flat(self.name, self.info,
1018 self.members, self.variants)
1021 class QAPISchemaObjectTypeMember(object):
1022 role = 'member'
1024 def __init__(self, name, typ, optional):
1025 assert isinstance(name, str)
1026 assert isinstance(typ, str)
1027 assert isinstance(optional, bool)
1028 self.name = name
1029 self._type_name = typ
1030 self.type = None
1031 self.optional = optional
1032 self.owner = None
1034 def set_owner(self, name):
1035 assert not self.owner
1036 self.owner = name
1038 def check(self, schema):
1039 assert self.owner
1040 self.type = schema.lookup_type(self._type_name)
1041 assert self.type
1043 def check_clash(self, info, seen):
1044 cname = c_name(self.name)
1045 if cname in seen:
1046 raise QAPIExprError(info,
1047 "%s collides with %s"
1048 % (self.describe(), seen[cname].describe()))
1049 seen[cname] = self
1051 def _pretty_owner(self):
1052 owner = self.owner
1053 if owner.startswith(':obj-'):
1054 # See QAPISchema._make_implicit_object_type() - reverse the
1055 # mapping there to create a nice human-readable description
1056 owner = owner[5:]
1057 if owner.endswith('-arg'):
1058 return '(parameter of %s)' % owner[:-4]
1059 else:
1060 assert owner.endswith('-wrapper')
1061 # Unreachable and not implemented
1062 assert False
1063 return '(%s of %s)' % (self.role, owner)
1065 def describe(self):
1066 return "'%s' %s" % (self.name, self._pretty_owner())
1069 class QAPISchemaObjectTypeVariants(object):
1070 def __init__(self, tag_name, tag_member, variants):
1071 # Flat unions pass tag_name but not tag_member.
1072 # Simple unions and alternates pass tag_member but not tag_name.
1073 # After check(), tag_member is always set, and tag_name remains
1074 # a reliable witness of being used by a flat union.
1075 assert bool(tag_member) != bool(tag_name)
1076 assert (isinstance(tag_name, str) or
1077 isinstance(tag_member, QAPISchemaObjectTypeMember))
1078 for v in variants:
1079 assert isinstance(v, QAPISchemaObjectTypeVariant)
1080 self.tag_name = tag_name
1081 self.tag_member = tag_member
1082 self.variants = variants
1084 def set_owner(self, name):
1085 for v in self.variants:
1086 v.set_owner(name)
1088 def check(self, schema, seen):
1089 if not self.tag_member: # flat union
1090 self.tag_member = seen[c_name(self.tag_name)]
1091 assert self.tag_name == self.tag_member.name
1092 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1093 for v in self.variants:
1094 v.check(schema)
1095 # Union names must match enum values; alternate names are
1096 # checked separately. Use 'seen' to tell the two apart.
1097 if seen:
1098 assert v.name in self.tag_member.type.values
1099 assert isinstance(v.type, QAPISchemaObjectType)
1100 v.type.check(schema)
1102 def check_clash(self, schema, info, seen):
1103 for v in self.variants:
1104 # Reset seen map for each variant, since qapi names from one
1105 # branch do not affect another branch
1106 assert isinstance(v.type, QAPISchemaObjectType)
1107 v.type.check_clash(schema, info, dict(seen))
1110 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1111 role = 'branch'
1113 def __init__(self, name, typ):
1114 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1116 # This function exists to support ugly simple union special cases
1117 # TODO get rid of them, and drop the function
1118 def simple_union_type(self):
1119 if (self.type.is_implicit() and
1120 isinstance(self.type, QAPISchemaObjectType)):
1121 assert len(self.type.members) == 1
1122 assert not self.type.variants
1123 return self.type.members[0].type
1124 return None
1127 class QAPISchemaAlternateType(QAPISchemaType):
1128 def __init__(self, name, info, variants):
1129 QAPISchemaType.__init__(self, name, info)
1130 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1131 assert not variants.tag_name
1132 variants.set_owner(name)
1133 variants.tag_member.set_owner(self.name)
1134 self.variants = variants
1136 def check(self, schema):
1137 self.variants.tag_member.check(schema)
1138 # Not calling self.variants.check_clash(), because there's nothing
1139 # to clash with
1140 self.variants.check(schema, {})
1141 # Alternate branch names have no relation to the tag enum values;
1142 # so we have to check for potential name collisions ourselves.
1143 seen = {}
1144 for v in self.variants.variants:
1145 v.check_clash(self.info, seen)
1147 def json_type(self):
1148 return 'value'
1150 def visit(self, visitor):
1151 visitor.visit_alternate_type(self.name, self.info, self.variants)
1154 class QAPISchemaCommand(QAPISchemaEntity):
1155 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1156 QAPISchemaEntity.__init__(self, name, info)
1157 assert not arg_type or isinstance(arg_type, str)
1158 assert not ret_type or isinstance(ret_type, str)
1159 self._arg_type_name = arg_type
1160 self.arg_type = None
1161 self._ret_type_name = ret_type
1162 self.ret_type = None
1163 self.gen = gen
1164 self.success_response = success_response
1166 def check(self, schema):
1167 if self._arg_type_name:
1168 self.arg_type = schema.lookup_type(self._arg_type_name)
1169 assert isinstance(self.arg_type, QAPISchemaObjectType)
1170 assert not self.arg_type.variants # not implemented
1171 if self._ret_type_name:
1172 self.ret_type = schema.lookup_type(self._ret_type_name)
1173 assert isinstance(self.ret_type, QAPISchemaType)
1175 def visit(self, visitor):
1176 visitor.visit_command(self.name, self.info,
1177 self.arg_type, self.ret_type,
1178 self.gen, self.success_response)
1181 class QAPISchemaEvent(QAPISchemaEntity):
1182 def __init__(self, name, info, arg_type):
1183 QAPISchemaEntity.__init__(self, name, info)
1184 assert not arg_type or isinstance(arg_type, str)
1185 self._arg_type_name = arg_type
1186 self.arg_type = None
1188 def check(self, schema):
1189 if self._arg_type_name:
1190 self.arg_type = schema.lookup_type(self._arg_type_name)
1191 assert isinstance(self.arg_type, QAPISchemaObjectType)
1192 assert not self.arg_type.variants # not implemented
1194 def visit(self, visitor):
1195 visitor.visit_event(self.name, self.info, self.arg_type)
1198 class QAPISchema(object):
1199 def __init__(self, fname):
1200 try:
1201 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1202 self._entity_dict = {}
1203 self._predefining = True
1204 self._def_predefineds()
1205 self._predefining = False
1206 self._def_exprs()
1207 self.check()
1208 except (QAPISchemaError, QAPIExprError), err:
1209 print >>sys.stderr, err
1210 exit(1)
1212 def _def_entity(self, ent):
1213 # Only the predefined types are allowed to not have info
1214 assert ent.info or self._predefining
1215 assert ent.name not in self._entity_dict
1216 self._entity_dict[ent.name] = ent
1218 def lookup_entity(self, name, typ=None):
1219 ent = self._entity_dict.get(name)
1220 if typ and not isinstance(ent, typ):
1221 return None
1222 return ent
1224 def lookup_type(self, name):
1225 return self.lookup_entity(name, QAPISchemaType)
1227 def _def_builtin_type(self, name, json_type, c_type, c_null):
1228 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1229 c_type, c_null))
1230 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1231 # qapi-types.h from a single .c, all arrays of builtins must be
1232 # declared in the first file whether or not they are used. Nicer
1233 # would be to use lazy instantiation, while figuring out how to
1234 # avoid compilation issues with multiple qapi-types.h.
1235 self._make_array_type(name, None)
1237 def _def_predefineds(self):
1238 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1239 ('number', 'number', 'double', '0'),
1240 ('int', 'int', 'int64_t', '0'),
1241 ('int8', 'int', 'int8_t', '0'),
1242 ('int16', 'int', 'int16_t', '0'),
1243 ('int32', 'int', 'int32_t', '0'),
1244 ('int64', 'int', 'int64_t', '0'),
1245 ('uint8', 'int', 'uint8_t', '0'),
1246 ('uint16', 'int', 'uint16_t', '0'),
1247 ('uint32', 'int', 'uint32_t', '0'),
1248 ('uint64', 'int', 'uint64_t', '0'),
1249 ('size', 'int', 'uint64_t', '0'),
1250 ('bool', 'boolean', 'bool', 'false'),
1251 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
1252 self._def_builtin_type(*t)
1253 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1254 [], None)
1255 self._def_entity(self.the_empty_object_type)
1256 self._def_entity(QAPISchemaEnumType('QType', None,
1257 ['none', 'qnull', 'qint',
1258 'qstring', 'qdict', 'qlist',
1259 'qfloat', 'qbool'],
1260 'QTYPE'))
1262 def _make_implicit_enum_type(self, name, info, values):
1263 name = name + 'Kind' # Use namespace reserved by add_name()
1264 self._def_entity(QAPISchemaEnumType(name, info, 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(name, info, data, prefix))
1289 def _make_member(self, name, typ, info):
1290 optional = False
1291 if name.startswith('*'):
1292 name = name[1:]
1293 optional = True
1294 if isinstance(typ, list):
1295 assert len(typ) == 1
1296 typ = self._make_array_type(typ[0], info)
1297 return QAPISchemaObjectTypeMember(name, typ, optional)
1299 def _make_members(self, data, info):
1300 return [self._make_member(key, value, info)
1301 for (key, value) in data.iteritems()]
1303 def _def_struct_type(self, expr, info):
1304 name = expr['struct']
1305 base = expr.get('base')
1306 data = expr['data']
1307 self._def_entity(QAPISchemaObjectType(name, info, base,
1308 self._make_members(data, info),
1309 None))
1311 def _make_variant(self, case, typ):
1312 return QAPISchemaObjectTypeVariant(case, typ)
1314 def _make_simple_variant(self, case, typ, info):
1315 if isinstance(typ, list):
1316 assert len(typ) == 1
1317 typ = self._make_array_type(typ[0], info)
1318 typ = self._make_implicit_object_type(
1319 typ, info, 'wrapper', [self._make_member('data', typ, info)])
1320 return QAPISchemaObjectTypeVariant(case, typ)
1322 def _def_union_type(self, expr, info):
1323 name = expr['union']
1324 data = expr['data']
1325 base = expr.get('base')
1326 tag_name = expr.get('discriminator')
1327 tag_member = None
1328 if tag_name:
1329 variants = [self._make_variant(key, value)
1330 for (key, value) in data.iteritems()]
1331 members = []
1332 else:
1333 variants = [self._make_simple_variant(key, value, info)
1334 for (key, value) in data.iteritems()]
1335 typ = self._make_implicit_enum_type(name, info,
1336 [v.name for v in variants])
1337 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
1338 members = [tag_member]
1339 self._def_entity(
1340 QAPISchemaObjectType(name, info, base, members,
1341 QAPISchemaObjectTypeVariants(tag_name,
1342 tag_member,
1343 variants)))
1345 def _def_alternate_type(self, expr, info):
1346 name = expr['alternate']
1347 data = expr['data']
1348 variants = [self._make_variant(key, value)
1349 for (key, value) in data.iteritems()]
1350 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
1351 self._def_entity(
1352 QAPISchemaAlternateType(name, info,
1353 QAPISchemaObjectTypeVariants(None,
1354 tag_member,
1355 variants)))
1357 def _def_command(self, expr, info):
1358 name = expr['command']
1359 data = expr.get('data')
1360 rets = expr.get('returns')
1361 gen = expr.get('gen', True)
1362 success_response = expr.get('success-response', True)
1363 if isinstance(data, OrderedDict):
1364 data = self._make_implicit_object_type(
1365 name, info, 'arg', self._make_members(data, info))
1366 if isinstance(rets, list):
1367 assert len(rets) == 1
1368 rets = self._make_array_type(rets[0], info)
1369 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1370 success_response))
1372 def _def_event(self, expr, info):
1373 name = expr['event']
1374 data = expr.get('data')
1375 if isinstance(data, OrderedDict):
1376 data = self._make_implicit_object_type(
1377 name, info, 'arg', self._make_members(data, info))
1378 self._def_entity(QAPISchemaEvent(name, info, data))
1380 def _def_exprs(self):
1381 for expr_elem in self.exprs:
1382 expr = expr_elem['expr']
1383 info = expr_elem['info']
1384 if 'enum' in expr:
1385 self._def_enum_type(expr, info)
1386 elif 'struct' in expr:
1387 self._def_struct_type(expr, info)
1388 elif 'union' in expr:
1389 self._def_union_type(expr, info)
1390 elif 'alternate' in expr:
1391 self._def_alternate_type(expr, info)
1392 elif 'command' in expr:
1393 self._def_command(expr, info)
1394 elif 'event' in expr:
1395 self._def_event(expr, info)
1396 else:
1397 assert False
1399 def check(self):
1400 for ent in self._entity_dict.values():
1401 ent.check(self)
1403 def visit(self, visitor):
1404 visitor.visit_begin(self)
1405 for (name, entity) in sorted(self._entity_dict.items()):
1406 if visitor.visit_needed(entity):
1407 entity.visit(visitor)
1408 visitor.visit_end()
1412 # Code generation helpers
1415 def camel_case(name):
1416 new_name = ''
1417 first = True
1418 for ch in name:
1419 if ch in ['_', '-']:
1420 first = True
1421 elif first:
1422 new_name += ch.upper()
1423 first = False
1424 else:
1425 new_name += ch.lower()
1426 return new_name
1429 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1430 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1431 # ENUM24_Name -> ENUM24_NAME
1432 def camel_to_upper(value):
1433 c_fun_str = c_name(value, False)
1434 if value.isupper():
1435 return c_fun_str
1437 new_name = ''
1438 l = len(c_fun_str)
1439 for i in range(l):
1440 c = c_fun_str[i]
1441 # When c is upper and no "_" appears before, do more checks
1442 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
1443 if i < l - 1 and c_fun_str[i + 1].islower():
1444 new_name += '_'
1445 elif c_fun_str[i - 1].isdigit():
1446 new_name += '_'
1447 new_name += c
1448 return new_name.lstrip('_').upper()
1451 def c_enum_const(type_name, const_name, prefix=None):
1452 if prefix is not None:
1453 type_name = prefix
1454 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
1456 c_name_trans = string.maketrans('.-', '__')
1459 # Map @name to a valid C identifier.
1460 # If @protect, avoid returning certain ticklish identifiers (like
1461 # C keywords) by prepending "q_".
1463 # Used for converting 'name' from a 'name':'type' qapi definition
1464 # into a generated struct member, as well as converting type names
1465 # into substrings of a generated C function name.
1466 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1467 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1468 def c_name(name, protect=True):
1469 # ANSI X3J11/88-090, 3.1.1
1470 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1471 'default', 'do', 'double', 'else', 'enum', 'extern',
1472 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1473 'return', 'short', 'signed', 'sizeof', 'static',
1474 'struct', 'switch', 'typedef', 'union', 'unsigned',
1475 'void', 'volatile', 'while'])
1476 # ISO/IEC 9899:1999, 6.4.1
1477 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1478 # ISO/IEC 9899:2011, 6.4.1
1479 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1480 '_Noreturn', '_Static_assert', '_Thread_local'])
1481 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1482 # excluding _.*
1483 gcc_words = set(['asm', 'typeof'])
1484 # C++ ISO/IEC 14882:2003 2.11
1485 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1486 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1487 'namespace', 'new', 'operator', 'private', 'protected',
1488 'public', 'reinterpret_cast', 'static_cast', 'template',
1489 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1490 'using', 'virtual', 'wchar_t',
1491 # alternative representations
1492 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1493 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1494 # namespace pollution:
1495 polluted_words = set(['unix', 'errno'])
1496 name = name.translate(c_name_trans)
1497 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1498 | cpp_words | polluted_words):
1499 return "q_" + name
1500 return name
1502 eatspace = '\033EATSPACE.'
1503 pointer_suffix = ' *' + eatspace
1506 def genindent(count):
1507 ret = ""
1508 for _ in range(count):
1509 ret += " "
1510 return ret
1512 indent_level = 0
1515 def push_indent(indent_amount=4):
1516 global indent_level
1517 indent_level += indent_amount
1520 def pop_indent(indent_amount=4):
1521 global indent_level
1522 indent_level -= indent_amount
1525 # Generate @code with @kwds interpolated.
1526 # Obey indent_level, and strip eatspace.
1527 def cgen(code, **kwds):
1528 raw = code % kwds
1529 if indent_level:
1530 indent = genindent(indent_level)
1531 # re.subn() lacks flags support before Python 2.7, use re.compile()
1532 raw = re.subn(re.compile("^.", re.MULTILINE),
1533 indent + r'\g<0>', raw)
1534 raw = raw[0]
1535 return re.sub(re.escape(eatspace) + ' *', '', raw)
1538 def mcgen(code, **kwds):
1539 if code[0] == '\n':
1540 code = code[1:]
1541 return cgen(code, **kwds)
1544 def guardname(filename):
1545 return c_name(filename, protect=False).upper()
1548 def guardstart(name):
1549 return mcgen('''
1551 #ifndef %(name)s
1552 #define %(name)s
1554 ''',
1555 name=guardname(name))
1558 def guardend(name):
1559 return mcgen('''
1561 #endif /* %(name)s */
1563 ''',
1564 name=guardname(name))
1567 def gen_enum_lookup(name, values, prefix=None):
1568 ret = mcgen('''
1570 const char *const %(c_name)s_lookup[] = {
1571 ''',
1572 c_name=c_name(name))
1573 for value in values:
1574 index = c_enum_const(name, value, prefix)
1575 ret += mcgen('''
1576 [%(index)s] = "%(value)s",
1577 ''',
1578 index=index, value=value)
1580 max_index = c_enum_const(name, '_MAX', prefix)
1581 ret += mcgen('''
1582 [%(max_index)s] = NULL,
1584 ''',
1585 max_index=max_index)
1586 return ret
1589 def gen_enum(name, values, prefix=None):
1590 # append automatically generated _MAX value
1591 enum_values = values + ['_MAX']
1593 ret = mcgen('''
1595 typedef enum %(c_name)s {
1596 ''',
1597 c_name=c_name(name))
1599 i = 0
1600 for value in enum_values:
1601 ret += mcgen('''
1602 %(c_enum)s = %(i)d,
1603 ''',
1604 c_enum=c_enum_const(name, value, prefix),
1605 i=i)
1606 i += 1
1608 ret += mcgen('''
1609 } %(c_name)s;
1610 ''',
1611 c_name=c_name(name))
1613 ret += mcgen('''
1615 extern const char *const %(c_name)s_lookup[];
1616 ''',
1617 c_name=c_name(name))
1618 return ret
1621 def gen_params(arg_type, extra):
1622 if not arg_type:
1623 return extra
1624 assert not arg_type.variants
1625 ret = ''
1626 sep = ''
1627 for memb in arg_type.members:
1628 ret += sep
1629 sep = ', '
1630 if memb.optional:
1631 ret += 'bool has_%s, ' % c_name(memb.name)
1632 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1633 if extra:
1634 ret += sep + extra
1635 return ret
1638 def gen_err_check(label='out', skiperr=False):
1639 if skiperr:
1640 return ''
1641 return mcgen('''
1642 if (err) {
1643 goto %(label)s;
1645 ''',
1646 label=label)
1649 def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
1650 ret = ''
1651 if skiperr:
1652 errparg = 'NULL'
1653 else:
1654 errparg = '&err'
1656 for memb in members:
1657 if memb.optional:
1658 ret += mcgen('''
1659 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1660 ''',
1661 prefix=prefix, c_name=c_name(memb.name),
1662 name=memb.name, errp=errparg)
1663 ret += gen_err_check(skiperr=skiperr)
1664 ret += mcgen('''
1665 if (%(prefix)shas_%(c_name)s) {
1666 ''',
1667 prefix=prefix, c_name=c_name(memb.name))
1668 push_indent()
1670 # Ugly: sometimes we need to cast away const
1671 if need_cast and memb.type.name == 'str':
1672 cast = '(char **)'
1673 else:
1674 cast = ''
1676 ret += mcgen('''
1677 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1678 ''',
1679 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1680 c_name=c_name(memb.name), name=memb.name,
1681 errp=errparg)
1682 ret += gen_err_check(skiperr=skiperr)
1684 if memb.optional:
1685 pop_indent()
1686 ret += mcgen('''
1688 ''')
1689 return ret
1693 # Common command line parsing
1697 def parse_command_line(extra_options="", extra_long_options=[]):
1699 try:
1700 opts, args = getopt.gnu_getopt(sys.argv[1:],
1701 "chp:o:" + extra_options,
1702 ["source", "header", "prefix=",
1703 "output-dir="] + extra_long_options)
1704 except getopt.GetoptError, err:
1705 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1706 sys.exit(1)
1708 output_dir = ""
1709 prefix = ""
1710 do_c = False
1711 do_h = False
1712 extra_opts = []
1714 for oa in opts:
1715 o, a = oa
1716 if o in ("-p", "--prefix"):
1717 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1718 if match.end() != len(a):
1719 print >>sys.stderr, \
1720 "%s: 'funny character '%s' in argument of --prefix" \
1721 % (sys.argv[0], a[match.end()])
1722 sys.exit(1)
1723 prefix = a
1724 elif o in ("-o", "--output-dir"):
1725 output_dir = a + "/"
1726 elif o in ("-c", "--source"):
1727 do_c = True
1728 elif o in ("-h", "--header"):
1729 do_h = True
1730 else:
1731 extra_opts.append(oa)
1733 if not do_c and not do_h:
1734 do_c = True
1735 do_h = True
1737 if len(args) != 1:
1738 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1739 sys.exit(1)
1740 fname = args[0]
1742 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1745 # Generate output files with boilerplate
1749 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1750 c_comment, h_comment):
1751 guard = guardname(prefix + h_file)
1752 c_file = output_dir + prefix + c_file
1753 h_file = output_dir + prefix + h_file
1755 if output_dir:
1756 try:
1757 os.makedirs(output_dir)
1758 except os.error, e:
1759 if e.errno != errno.EEXIST:
1760 raise
1762 def maybe_open(really, name, opt):
1763 if really:
1764 return open(name, opt)
1765 else:
1766 import StringIO
1767 return StringIO.StringIO()
1769 fdef = maybe_open(do_c, c_file, 'w')
1770 fdecl = maybe_open(do_h, h_file, 'w')
1772 fdef.write(mcgen('''
1773 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1774 %(comment)s
1775 ''',
1776 comment=c_comment))
1778 fdecl.write(mcgen('''
1779 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1780 %(comment)s
1781 #ifndef %(guard)s
1782 #define %(guard)s
1784 ''',
1785 comment=h_comment, guard=guard))
1787 return (fdef, fdecl)
1790 def close_output(fdef, fdecl):
1791 fdecl.write('''
1792 #endif
1793 ''')
1794 fdecl.close()
1795 fdef.close()