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