]> git.proxmox.com Git - mirror_qemu.git/blob - scripts/qapi.py
qapi: More idiomatic string operations
[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 if not valid_name.match(membername):
380 raise QAPIExprError(expr_info,
381 "%s uses invalid name '%s'" % (source, name))
382
383
384 def add_name(name, info, meta, implicit=False):
385 global all_names
386 check_name(info, "'%s'" % meta, name)
387 # FIXME should reject names that differ only in '_' vs. '.'
388 # vs. '-', because they're liable to clash in generated C.
389 if name in all_names:
390 raise QAPIExprError(info,
391 "%s '%s' is already defined"
392 % (all_names[name], name))
393 if not implicit and name.endswith('Kind'):
394 raise QAPIExprError(info,
395 "%s '%s' should not end in 'Kind'"
396 % (meta, name))
397 all_names[name] = meta
398
399
400 def add_struct(definition, info):
401 global struct_types
402 name = definition['struct']
403 add_name(name, info, 'struct')
404 struct_types.append(definition)
405
406
407 def find_struct(name):
408 global struct_types
409 for struct in struct_types:
410 if struct['struct'] == name:
411 return struct
412 return None
413
414
415 def add_union(definition, info):
416 global union_types
417 name = definition['union']
418 add_name(name, info, 'union')
419 union_types.append(definition)
420
421
422 def find_union(name):
423 global union_types
424 for union in union_types:
425 if union['union'] == name:
426 return union
427 return None
428
429
430 def add_enum(name, info, enum_values=None, implicit=False):
431 global enum_types
432 add_name(name, info, 'enum', implicit)
433 enum_types.append({"enum_name": name, "enum_values": enum_values})
434
435
436 def find_enum(name):
437 global enum_types
438 for enum in enum_types:
439 if enum['enum_name'] == name:
440 return enum
441 return None
442
443
444 def is_enum(name):
445 return find_enum(name) is not None
446
447
448 def check_type(expr_info, source, value, allow_array=False,
449 allow_dict=False, allow_optional=False,
450 allow_metas=[]):
451 global all_names
452
453 if value is None:
454 return
455
456 # Check if array type for value is okay
457 if isinstance(value, list):
458 if not allow_array:
459 raise QAPIExprError(expr_info,
460 "%s cannot be an array" % source)
461 if len(value) != 1 or not isinstance(value[0], str):
462 raise QAPIExprError(expr_info,
463 "%s: array type must contain single type name"
464 % source)
465 value = value[0]
466
467 # Check if type name for value is okay
468 if isinstance(value, str):
469 if value not in all_names:
470 raise QAPIExprError(expr_info,
471 "%s uses unknown type '%s'"
472 % (source, value))
473 if not all_names[value] in allow_metas:
474 raise QAPIExprError(expr_info,
475 "%s cannot use %s type '%s'"
476 % (source, all_names[value], value))
477 return
478
479 if not allow_dict:
480 raise QAPIExprError(expr_info,
481 "%s should be a type name" % source)
482
483 if not isinstance(value, OrderedDict):
484 raise QAPIExprError(expr_info,
485 "%s should be a dictionary or type name" % source)
486
487 # value is a dictionary, check that each member is okay
488 for (key, arg) in value.items():
489 check_name(expr_info, "Member of %s" % source, key,
490 allow_optional=allow_optional)
491 # Todo: allow dictionaries to represent default values of
492 # an optional argument.
493 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
494 allow_array=True,
495 allow_metas=['built-in', 'union', 'alternate', 'struct',
496 'enum'])
497
498
499 def check_member_clash(expr_info, base_name, data, source=""):
500 base = find_struct(base_name)
501 assert base
502 base_members = base['data']
503 for key in data.keys():
504 if key.startswith('*'):
505 key = key[1:]
506 if key in base_members or "*" + key in base_members:
507 raise QAPIExprError(expr_info,
508 "Member name '%s'%s clashes with base '%s'"
509 % (key, source, base_name))
510 if base.get('base'):
511 check_member_clash(expr_info, base['base'], data, source)
512
513
514 def check_command(expr, expr_info):
515 name = expr['command']
516
517 check_type(expr_info, "'data' for command '%s'" % name,
518 expr.get('data'), allow_dict=True, allow_optional=True,
519 allow_metas=['struct'])
520 returns_meta = ['union', 'struct']
521 if name in returns_whitelist:
522 returns_meta += ['built-in', 'alternate', 'enum']
523 check_type(expr_info, "'returns' for command '%s'" % name,
524 expr.get('returns'), allow_array=True,
525 allow_optional=True, allow_metas=returns_meta)
526
527
528 def check_event(expr, expr_info):
529 global events
530 name = expr['event']
531
532 if name.upper() == 'MAX':
533 raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
534 events.append(name)
535 check_type(expr_info, "'data' for event '%s'" % name,
536 expr.get('data'), allow_dict=True, allow_optional=True,
537 allow_metas=['struct'])
538
539
540 def check_union(expr, expr_info):
541 name = expr['union']
542 base = expr.get('base')
543 discriminator = expr.get('discriminator')
544 members = expr['data']
545 values = {'MAX': '(automatic)', 'KIND': '(automatic)'}
546
547 # Two types of unions, determined by discriminator.
548
549 # With no discriminator it is a simple union.
550 if discriminator is None:
551 enum_define = None
552 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
553 if base is not None:
554 raise QAPIExprError(expr_info,
555 "Simple union '%s' must not have a base"
556 % name)
557
558 # Else, it's a flat union.
559 else:
560 # The object must have a string member 'base'.
561 check_type(expr_info, "'base' for union '%s'" % name,
562 base, allow_metas=['struct'])
563 if not base:
564 raise QAPIExprError(expr_info,
565 "Flat union '%s' must have a base"
566 % name)
567 base_fields = find_base_fields(base)
568 assert base_fields
569
570 # The value of member 'discriminator' must name a non-optional
571 # member of the base struct.
572 check_name(expr_info, "Discriminator of flat union '%s'" % name,
573 discriminator)
574 discriminator_type = base_fields.get(discriminator)
575 if not discriminator_type:
576 raise QAPIExprError(expr_info,
577 "Discriminator '%s' is not a member of base "
578 "struct '%s'"
579 % (discriminator, base))
580 enum_define = find_enum(discriminator_type)
581 allow_metas = ['struct']
582 # Do not allow string discriminator
583 if not enum_define:
584 raise QAPIExprError(expr_info,
585 "Discriminator '%s' must be of enumeration "
586 "type" % discriminator)
587
588 # Check every branch
589 for (key, value) in members.items():
590 check_name(expr_info, "Member of union '%s'" % name, key)
591
592 # Each value must name a known type; furthermore, in flat unions,
593 # branches must be a struct with no overlapping member names
594 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
595 value, allow_array=not base, allow_metas=allow_metas)
596 if base:
597 branch_struct = find_struct(value)
598 assert branch_struct
599 check_member_clash(expr_info, base, branch_struct['data'],
600 " of branch '%s'" % key)
601
602 # If the discriminator names an enum type, then all members
603 # of 'data' must also be members of the enum type, which in turn
604 # must not collide with the discriminator name.
605 if enum_define:
606 if key not in enum_define['enum_values']:
607 raise QAPIExprError(expr_info,
608 "Discriminator value '%s' is not found in "
609 "enum '%s'" %
610 (key, enum_define["enum_name"]))
611 if discriminator in enum_define['enum_values']:
612 raise QAPIExprError(expr_info,
613 "Discriminator name '%s' collides with "
614 "enum value in '%s'" %
615 (discriminator, 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 QAPISchemaType.__init__(self, name, info)
954 assert base is None or isinstance(base, str)
955 for m in local_members:
956 assert isinstance(m, QAPISchemaObjectTypeMember)
957 assert (variants is None or
958 isinstance(variants, QAPISchemaObjectTypeVariants))
959 self._base_name = base
960 self.base = None
961 self.local_members = local_members
962 self.variants = variants
963 self.members = None
964
965 def check(self, schema):
966 assert self.members is not False # not running in cycles
967 if self.members:
968 return
969 self.members = False # mark as being checked
970 if self._base_name:
971 self.base = schema.lookup_type(self._base_name)
972 assert isinstance(self.base, QAPISchemaObjectType)
973 assert not self.base.variants # not implemented
974 self.base.check(schema)
975 members = list(self.base.members)
976 else:
977 members = []
978 seen = {}
979 for m in members:
980 assert c_name(m.name) not in seen
981 seen[m.name] = m
982 for m in self.local_members:
983 m.check(schema, members, seen)
984 if self.variants:
985 self.variants.check(schema, members, seen)
986 self.members = members
987
988 def is_implicit(self):
989 # See QAPISchema._make_implicit_object_type()
990 return self.name[0] == ':'
991
992 def c_name(self):
993 assert not self.is_implicit()
994 return QAPISchemaType.c_name(self)
995
996 def c_type(self, is_param=False):
997 assert not self.is_implicit()
998 return QAPISchemaType.c_type(self)
999
1000 def json_type(self):
1001 return 'object'
1002
1003 def visit(self, visitor):
1004 visitor.visit_object_type(self.name, self.info,
1005 self.base, self.local_members, self.variants)
1006 visitor.visit_object_type_flat(self.name, self.info,
1007 self.members, self.variants)
1008
1009
1010 class QAPISchemaObjectTypeMember(object):
1011 def __init__(self, name, typ, optional):
1012 assert isinstance(name, str)
1013 assert isinstance(typ, str)
1014 assert isinstance(optional, bool)
1015 self.name = name
1016 self._type_name = typ
1017 self.type = None
1018 self.optional = optional
1019
1020 def check(self, schema, all_members, seen):
1021 assert self.name not in seen
1022 self.type = schema.lookup_type(self._type_name)
1023 assert self.type
1024 all_members.append(self)
1025 seen[self.name] = self
1026
1027
1028 class QAPISchemaObjectTypeVariants(object):
1029 def __init__(self, tag_name, tag_member, variants):
1030 # Flat unions pass tag_name but not tag_member.
1031 # Simple unions and alternates pass tag_member but not tag_name.
1032 # After check(), tag_member is always set, and tag_name remains
1033 # a reliable witness of being used by a flat union.
1034 assert bool(tag_member) != bool(tag_name)
1035 assert (isinstance(tag_name, str) or
1036 isinstance(tag_member, QAPISchemaObjectTypeMember))
1037 for v in variants:
1038 assert isinstance(v, QAPISchemaObjectTypeVariant)
1039 self.tag_name = tag_name
1040 self.tag_member = tag_member
1041 self.variants = variants
1042
1043 def check(self, schema, members, seen):
1044 if self.tag_name:
1045 self.tag_member = seen[self.tag_name]
1046 else:
1047 self.tag_member.check(schema, members, seen)
1048 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1049 for v in self.variants:
1050 vseen = dict(seen)
1051 v.check(schema, self.tag_member.type, vseen)
1052
1053
1054 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1055 def __init__(self, name, typ):
1056 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1057
1058 def check(self, schema, tag_type, seen):
1059 QAPISchemaObjectTypeMember.check(self, schema, [], seen)
1060 assert self.name in tag_type.values
1061
1062 # This function exists to support ugly simple union special cases
1063 # TODO get rid of them, and drop the function
1064 def simple_union_type(self):
1065 if (self.type.is_implicit() and
1066 isinstance(self.type, QAPISchemaObjectType)):
1067 assert len(self.type.members) == 1
1068 assert not self.type.variants
1069 return self.type.members[0].type
1070 return None
1071
1072
1073 class QAPISchemaAlternateType(QAPISchemaType):
1074 def __init__(self, name, info, variants):
1075 QAPISchemaType.__init__(self, name, info)
1076 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1077 assert not variants.tag_name
1078 self.variants = variants
1079
1080 def check(self, schema):
1081 self.variants.check(schema, [], {})
1082
1083 def json_type(self):
1084 return 'value'
1085
1086 def visit(self, visitor):
1087 visitor.visit_alternate_type(self.name, self.info, self.variants)
1088
1089
1090 class QAPISchemaCommand(QAPISchemaEntity):
1091 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1092 QAPISchemaEntity.__init__(self, name, info)
1093 assert not arg_type or isinstance(arg_type, str)
1094 assert not ret_type or isinstance(ret_type, str)
1095 self._arg_type_name = arg_type
1096 self.arg_type = None
1097 self._ret_type_name = ret_type
1098 self.ret_type = None
1099 self.gen = gen
1100 self.success_response = success_response
1101
1102 def check(self, schema):
1103 if self._arg_type_name:
1104 self.arg_type = schema.lookup_type(self._arg_type_name)
1105 assert isinstance(self.arg_type, QAPISchemaObjectType)
1106 assert not self.arg_type.variants # not implemented
1107 if self._ret_type_name:
1108 self.ret_type = schema.lookup_type(self._ret_type_name)
1109 assert isinstance(self.ret_type, QAPISchemaType)
1110
1111 def visit(self, visitor):
1112 visitor.visit_command(self.name, self.info,
1113 self.arg_type, self.ret_type,
1114 self.gen, self.success_response)
1115
1116
1117 class QAPISchemaEvent(QAPISchemaEntity):
1118 def __init__(self, name, info, arg_type):
1119 QAPISchemaEntity.__init__(self, name, info)
1120 assert not arg_type or isinstance(arg_type, str)
1121 self._arg_type_name = arg_type
1122 self.arg_type = None
1123
1124 def check(self, schema):
1125 if self._arg_type_name:
1126 self.arg_type = schema.lookup_type(self._arg_type_name)
1127 assert isinstance(self.arg_type, QAPISchemaObjectType)
1128 assert not self.arg_type.variants # not implemented
1129
1130 def visit(self, visitor):
1131 visitor.visit_event(self.name, self.info, self.arg_type)
1132
1133
1134 class QAPISchema(object):
1135 def __init__(self, fname):
1136 try:
1137 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1138 self._entity_dict = {}
1139 self._predefining = True
1140 self._def_predefineds()
1141 self._predefining = False
1142 self._def_exprs()
1143 self.check()
1144 except (QAPISchemaError, QAPIExprError), err:
1145 print >>sys.stderr, err
1146 exit(1)
1147
1148 def _def_entity(self, ent):
1149 # Only the predefined types are allowed to not have info
1150 assert ent.info or self._predefining
1151 assert ent.name not in self._entity_dict
1152 self._entity_dict[ent.name] = ent
1153
1154 def lookup_entity(self, name, typ=None):
1155 ent = self._entity_dict.get(name)
1156 if typ and not isinstance(ent, typ):
1157 return None
1158 return ent
1159
1160 def lookup_type(self, name):
1161 return self.lookup_entity(name, QAPISchemaType)
1162
1163 def _def_builtin_type(self, name, json_type, c_type, c_null):
1164 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1165 c_type, c_null))
1166 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1167 # qapi-types.h from a single .c, all arrays of builtins must be
1168 # declared in the first file whether or not they are used. Nicer
1169 # would be to use lazy instantiation, while figuring out how to
1170 # avoid compilation issues with multiple qapi-types.h.
1171 self._make_array_type(name, None)
1172
1173 def _def_predefineds(self):
1174 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1175 ('number', 'number', 'double', '0'),
1176 ('int', 'int', 'int64_t', '0'),
1177 ('int8', 'int', 'int8_t', '0'),
1178 ('int16', 'int', 'int16_t', '0'),
1179 ('int32', 'int', 'int32_t', '0'),
1180 ('int64', 'int', 'int64_t', '0'),
1181 ('uint8', 'int', 'uint8_t', '0'),
1182 ('uint16', 'int', 'uint16_t', '0'),
1183 ('uint32', 'int', 'uint32_t', '0'),
1184 ('uint64', 'int', 'uint64_t', '0'),
1185 ('size', 'int', 'uint64_t', '0'),
1186 ('bool', 'boolean', 'bool', 'false'),
1187 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
1188 self._def_builtin_type(*t)
1189 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1190 [], None)
1191 self._def_entity(self.the_empty_object_type)
1192
1193 def _make_implicit_enum_type(self, name, info, values):
1194 name = name + 'Kind' # Use namespace reserved by add_name()
1195 self._def_entity(QAPISchemaEnumType(name, info, values, None))
1196 return name
1197
1198 def _make_array_type(self, element_type, info):
1199 # TODO fooList namespace is not reserved; user can create collisions,
1200 # or abuse our type system with ['fooList'] for 2D array
1201 name = element_type + 'List'
1202 if not self.lookup_type(name):
1203 self._def_entity(QAPISchemaArrayType(name, info, element_type))
1204 return name
1205
1206 def _make_implicit_object_type(self, name, info, role, members):
1207 if not members:
1208 return None
1209 name = ':obj-%s-%s' % (name, role)
1210 if not self.lookup_entity(name, QAPISchemaObjectType):
1211 self._def_entity(QAPISchemaObjectType(name, info, None,
1212 members, None))
1213 return name
1214
1215 def _def_enum_type(self, expr, info):
1216 name = expr['enum']
1217 data = expr['data']
1218 prefix = expr.get('prefix')
1219 self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
1220
1221 def _make_member(self, name, typ, info):
1222 optional = False
1223 if name.startswith('*'):
1224 name = name[1:]
1225 optional = True
1226 if isinstance(typ, list):
1227 assert len(typ) == 1
1228 typ = self._make_array_type(typ[0], info)
1229 return QAPISchemaObjectTypeMember(name, typ, optional)
1230
1231 def _make_members(self, data, info):
1232 return [self._make_member(key, value, info)
1233 for (key, value) in data.iteritems()]
1234
1235 def _def_struct_type(self, expr, info):
1236 name = expr['struct']
1237 base = expr.get('base')
1238 data = expr['data']
1239 self._def_entity(QAPISchemaObjectType(name, info, base,
1240 self._make_members(data, info),
1241 None))
1242
1243 def _make_variant(self, case, typ):
1244 return QAPISchemaObjectTypeVariant(case, typ)
1245
1246 def _make_simple_variant(self, case, typ, info):
1247 if isinstance(typ, list):
1248 assert len(typ) == 1
1249 typ = self._make_array_type(typ[0], info)
1250 typ = self._make_implicit_object_type(
1251 typ, info, 'wrapper', [self._make_member('data', typ, info)])
1252 return QAPISchemaObjectTypeVariant(case, typ)
1253
1254 def _make_implicit_tag(self, type_name, info, variants):
1255 typ = self._make_implicit_enum_type(type_name, info,
1256 [v.name for v in variants])
1257 return QAPISchemaObjectTypeMember('type', typ, False)
1258
1259 def _def_union_type(self, expr, info):
1260 name = expr['union']
1261 data = expr['data']
1262 base = expr.get('base')
1263 tag_name = expr.get('discriminator')
1264 tag_member = None
1265 if tag_name:
1266 variants = [self._make_variant(key, value)
1267 for (key, value) in data.iteritems()]
1268 else:
1269 variants = [self._make_simple_variant(key, value, info)
1270 for (key, value) in data.iteritems()]
1271 tag_member = self._make_implicit_tag(name, info, variants)
1272 self._def_entity(
1273 QAPISchemaObjectType(name, info, base,
1274 self._make_members(OrderedDict(), info),
1275 QAPISchemaObjectTypeVariants(tag_name,
1276 tag_member,
1277 variants)))
1278
1279 def _def_alternate_type(self, expr, info):
1280 name = expr['alternate']
1281 data = expr['data']
1282 variants = [self._make_variant(key, value)
1283 for (key, value) in data.iteritems()]
1284 tag_member = self._make_implicit_tag(name, info, variants)
1285 self._def_entity(
1286 QAPISchemaAlternateType(name, info,
1287 QAPISchemaObjectTypeVariants(None,
1288 tag_member,
1289 variants)))
1290
1291 def _def_command(self, expr, info):
1292 name = expr['command']
1293 data = expr.get('data')
1294 rets = expr.get('returns')
1295 gen = expr.get('gen', True)
1296 success_response = expr.get('success-response', True)
1297 if isinstance(data, OrderedDict):
1298 data = self._make_implicit_object_type(
1299 name, info, 'arg', self._make_members(data, info))
1300 if isinstance(rets, list):
1301 assert len(rets) == 1
1302 rets = self._make_array_type(rets[0], info)
1303 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1304 success_response))
1305
1306 def _def_event(self, expr, info):
1307 name = expr['event']
1308 data = expr.get('data')
1309 if isinstance(data, OrderedDict):
1310 data = self._make_implicit_object_type(
1311 name, info, 'arg', self._make_members(data, info))
1312 self._def_entity(QAPISchemaEvent(name, info, data))
1313
1314 def _def_exprs(self):
1315 for expr_elem in self.exprs:
1316 expr = expr_elem['expr']
1317 info = expr_elem['info']
1318 if 'enum' in expr:
1319 self._def_enum_type(expr, info)
1320 elif 'struct' in expr:
1321 self._def_struct_type(expr, info)
1322 elif 'union' in expr:
1323 self._def_union_type(expr, info)
1324 elif 'alternate' in expr:
1325 self._def_alternate_type(expr, info)
1326 elif 'command' in expr:
1327 self._def_command(expr, info)
1328 elif 'event' in expr:
1329 self._def_event(expr, info)
1330 else:
1331 assert False
1332
1333 def check(self):
1334 for ent in self._entity_dict.values():
1335 ent.check(self)
1336
1337 def visit(self, visitor):
1338 visitor.visit_begin(self)
1339 for (name, entity) in sorted(self._entity_dict.items()):
1340 if visitor.visit_needed(entity):
1341 entity.visit(visitor)
1342 visitor.visit_end()
1343
1344
1345 #
1346 # Code generation helpers
1347 #
1348
1349 def camel_case(name):
1350 new_name = ''
1351 first = True
1352 for ch in name:
1353 if ch in ['_', '-']:
1354 first = True
1355 elif first:
1356 new_name += ch.upper()
1357 first = False
1358 else:
1359 new_name += ch.lower()
1360 return new_name
1361
1362
1363 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1364 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1365 # ENUM24_Name -> ENUM24_NAME
1366 def camel_to_upper(value):
1367 c_fun_str = c_name(value, False)
1368 if value.isupper():
1369 return c_fun_str
1370
1371 new_name = ''
1372 l = len(c_fun_str)
1373 for i in range(l):
1374 c = c_fun_str[i]
1375 # When c is upper and no "_" appears before, do more checks
1376 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
1377 if i < l - 1 and c_fun_str[i + 1].islower():
1378 new_name += '_'
1379 elif c_fun_str[i - 1].isdigit():
1380 new_name += '_'
1381 new_name += c
1382 return new_name.lstrip('_').upper()
1383
1384
1385 def c_enum_const(type_name, const_name, prefix=None):
1386 if prefix is not None:
1387 type_name = prefix
1388 return camel_to_upper(type_name + '_' + const_name)
1389
1390 c_name_trans = string.maketrans('.-', '__')
1391
1392
1393 # Map @name to a valid C identifier.
1394 # If @protect, avoid returning certain ticklish identifiers (like
1395 # C keywords) by prepending "q_".
1396 #
1397 # Used for converting 'name' from a 'name':'type' qapi definition
1398 # into a generated struct member, as well as converting type names
1399 # into substrings of a generated C function name.
1400 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1401 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1402 def c_name(name, protect=True):
1403 # ANSI X3J11/88-090, 3.1.1
1404 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1405 'default', 'do', 'double', 'else', 'enum', 'extern',
1406 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1407 'return', 'short', 'signed', 'sizeof', 'static',
1408 'struct', 'switch', 'typedef', 'union', 'unsigned',
1409 'void', 'volatile', 'while'])
1410 # ISO/IEC 9899:1999, 6.4.1
1411 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1412 # ISO/IEC 9899:2011, 6.4.1
1413 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1414 '_Noreturn', '_Static_assert', '_Thread_local'])
1415 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1416 # excluding _.*
1417 gcc_words = set(['asm', 'typeof'])
1418 # C++ ISO/IEC 14882:2003 2.11
1419 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1420 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1421 'namespace', 'new', 'operator', 'private', 'protected',
1422 'public', 'reinterpret_cast', 'static_cast', 'template',
1423 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1424 'using', 'virtual', 'wchar_t',
1425 # alternative representations
1426 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1427 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1428 # namespace pollution:
1429 polluted_words = set(['unix', 'errno'])
1430 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1431 | cpp_words | polluted_words):
1432 return "q_" + name
1433 return name.translate(c_name_trans)
1434
1435 eatspace = '\033EATSPACE.'
1436 pointer_suffix = ' *' + eatspace
1437
1438
1439 def genindent(count):
1440 ret = ""
1441 for _ in range(count):
1442 ret += " "
1443 return ret
1444
1445 indent_level = 0
1446
1447
1448 def push_indent(indent_amount=4):
1449 global indent_level
1450 indent_level += indent_amount
1451
1452
1453 def pop_indent(indent_amount=4):
1454 global indent_level
1455 indent_level -= indent_amount
1456
1457
1458 # Generate @code with @kwds interpolated.
1459 # Obey indent_level, and strip eatspace.
1460 def cgen(code, **kwds):
1461 raw = code % kwds
1462 if indent_level:
1463 indent = genindent(indent_level)
1464 # re.subn() lacks flags support before Python 2.7, use re.compile()
1465 raw = re.subn(re.compile("^.", re.MULTILINE),
1466 indent + r'\g<0>', raw)
1467 raw = raw[0]
1468 return re.sub(re.escape(eatspace) + ' *', '', raw)
1469
1470
1471 def mcgen(code, **kwds):
1472 if code[0] == '\n':
1473 code = code[1:]
1474 return cgen(code, **kwds)
1475
1476
1477 def guardname(filename):
1478 return c_name(filename, protect=False).upper()
1479
1480
1481 def guardstart(name):
1482 return mcgen('''
1483
1484 #ifndef %(name)s
1485 #define %(name)s
1486
1487 ''',
1488 name=guardname(name))
1489
1490
1491 def guardend(name):
1492 return mcgen('''
1493
1494 #endif /* %(name)s */
1495
1496 ''',
1497 name=guardname(name))
1498
1499
1500 def gen_enum_lookup(name, values, prefix=None):
1501 ret = mcgen('''
1502
1503 const char *const %(c_name)s_lookup[] = {
1504 ''',
1505 c_name=c_name(name))
1506 for value in values:
1507 index = c_enum_const(name, value, prefix)
1508 ret += mcgen('''
1509 [%(index)s] = "%(value)s",
1510 ''',
1511 index=index, value=value)
1512
1513 max_index = c_enum_const(name, 'MAX', prefix)
1514 ret += mcgen('''
1515 [%(max_index)s] = NULL,
1516 };
1517 ''',
1518 max_index=max_index)
1519 return ret
1520
1521
1522 def gen_enum(name, values, prefix=None):
1523 # append automatically generated _MAX value
1524 enum_values = values + ['MAX']
1525
1526 ret = mcgen('''
1527
1528 typedef enum %(c_name)s {
1529 ''',
1530 c_name=c_name(name))
1531
1532 i = 0
1533 for value in enum_values:
1534 ret += mcgen('''
1535 %(c_enum)s = %(i)d,
1536 ''',
1537 c_enum=c_enum_const(name, value, prefix),
1538 i=i)
1539 i += 1
1540
1541 ret += mcgen('''
1542 } %(c_name)s;
1543 ''',
1544 c_name=c_name(name))
1545
1546 ret += mcgen('''
1547
1548 extern const char *const %(c_name)s_lookup[];
1549 ''',
1550 c_name=c_name(name))
1551 return ret
1552
1553
1554 def gen_params(arg_type, extra):
1555 if not arg_type:
1556 return extra
1557 assert not arg_type.variants
1558 ret = ''
1559 sep = ''
1560 for memb in arg_type.members:
1561 ret += sep
1562 sep = ', '
1563 if memb.optional:
1564 ret += 'bool has_%s, ' % c_name(memb.name)
1565 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1566 if extra:
1567 ret += sep + extra
1568 return ret
1569
1570
1571 def gen_err_check(label='out', skiperr=False):
1572 if skiperr:
1573 return ''
1574 return mcgen('''
1575 if (err) {
1576 goto %(label)s;
1577 }
1578 ''',
1579 label=label)
1580
1581
1582 def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
1583 ret = ''
1584 if skiperr:
1585 errparg = 'NULL'
1586 else:
1587 errparg = '&err'
1588
1589 for memb in members:
1590 if memb.optional:
1591 ret += mcgen('''
1592 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1593 ''',
1594 prefix=prefix, c_name=c_name(memb.name),
1595 name=memb.name, errp=errparg)
1596 ret += gen_err_check(skiperr=skiperr)
1597 ret += mcgen('''
1598 if (%(prefix)shas_%(c_name)s) {
1599 ''',
1600 prefix=prefix, c_name=c_name(memb.name))
1601 push_indent()
1602
1603 # Ugly: sometimes we need to cast away const
1604 if need_cast and memb.type.name == 'str':
1605 cast = '(char **)'
1606 else:
1607 cast = ''
1608
1609 ret += mcgen('''
1610 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1611 ''',
1612 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1613 c_name=c_name(memb.name), name=memb.name,
1614 errp=errparg)
1615 ret += gen_err_check(skiperr=skiperr)
1616
1617 if memb.optional:
1618 pop_indent()
1619 ret += mcgen('''
1620 }
1621 ''')
1622 return ret
1623
1624
1625 #
1626 # Common command line parsing
1627 #
1628
1629
1630 def parse_command_line(extra_options="", extra_long_options=[]):
1631
1632 try:
1633 opts, args = getopt.gnu_getopt(sys.argv[1:],
1634 "chp:o:" + extra_options,
1635 ["source", "header", "prefix=",
1636 "output-dir="] + extra_long_options)
1637 except getopt.GetoptError, err:
1638 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1639 sys.exit(1)
1640
1641 output_dir = ""
1642 prefix = ""
1643 do_c = False
1644 do_h = False
1645 extra_opts = []
1646
1647 for oa in opts:
1648 o, a = oa
1649 if o in ("-p", "--prefix"):
1650 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1651 if match.end() != len(a):
1652 print >>sys.stderr, \
1653 "%s: 'funny character '%s' in argument of --prefix" \
1654 % (sys.argv[0], a[match.end()])
1655 sys.exit(1)
1656 prefix = a
1657 elif o in ("-o", "--output-dir"):
1658 output_dir = a + "/"
1659 elif o in ("-c", "--source"):
1660 do_c = True
1661 elif o in ("-h", "--header"):
1662 do_h = True
1663 else:
1664 extra_opts.append(oa)
1665
1666 if not do_c and not do_h:
1667 do_c = True
1668 do_h = True
1669
1670 if len(args) != 1:
1671 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1672 sys.exit(1)
1673 fname = args[0]
1674
1675 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1676
1677 #
1678 # Generate output files with boilerplate
1679 #
1680
1681
1682 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1683 c_comment, h_comment):
1684 guard = guardname(prefix + h_file)
1685 c_file = output_dir + prefix + c_file
1686 h_file = output_dir + prefix + h_file
1687
1688 if output_dir:
1689 try:
1690 os.makedirs(output_dir)
1691 except os.error, e:
1692 if e.errno != errno.EEXIST:
1693 raise
1694
1695 def maybe_open(really, name, opt):
1696 if really:
1697 return open(name, opt)
1698 else:
1699 import StringIO
1700 return StringIO.StringIO()
1701
1702 fdef = maybe_open(do_c, c_file, 'w')
1703 fdecl = maybe_open(do_h, h_file, 'w')
1704
1705 fdef.write(mcgen('''
1706 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1707 %(comment)s
1708 ''',
1709 comment=c_comment))
1710
1711 fdecl.write(mcgen('''
1712 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1713 %(comment)s
1714 #ifndef %(guard)s
1715 #define %(guard)s
1716
1717 ''',
1718 comment=h_comment, guard=guard))
1719
1720 return (fdef, fdecl)
1721
1722
1723 def close_output(fdef, fdecl):
1724 fdecl.write('''
1725 #endif
1726 ''')
1727 fdecl.close()
1728 fdef.close()