4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2016 Red Hat Inc.
8 # Anthony Liguori <aliguori@us.ibm.com>
9 # Markus Armbruster <armbru@redhat.com>
11 # This work is licensed under the terms of the GNU GPL, version 2.
12 # See the COPYING file in the top-level directory.
15 from ordereddict
import OrderedDict
23 'str': 'QTYPE_QSTRING',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
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',
36 'any': None, # any QType possible, actually
37 'QType': 'QTYPE_QSTRING',
40 # Whitelist of commands allowed to return a non-dictionary
43 'human-monitor-command',
45 'query-migrate-cache-size',
52 'guest-fsfreeze-freeze',
53 'guest-fsfreeze-freeze-list',
54 'guest-fsfreeze-status',
55 'guest-fsfreeze-thaw',
59 'guest-sync-delimited',
62 # Whitelist of entities allowed to violate case conventions
65 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
66 'CpuInfoMIPS', # PC, visible through query-cpu
67 'CpuInfoTricore', # PC, visible through query-cpu
68 'QapiErrorClass', # all members, visible through errors
69 'UuidInfo', # UUID, visible through query-uuid
70 'X86CPURegister32', # all members, visible indirectly through qom-get
71 'q_obj_CpuInfo-base', # CPU, visible through query-cpu
81 # Parsing the schema into expressions
85 def error_path(parent
):
88 res
= ("In file included from %s:%d:\n" % (parent
['file'],
89 parent
['line'])) + res
90 parent
= parent
['parent']
94 class QAPISchemaError(Exception):
95 def __init__(self
, schema
, msg
):
96 Exception.__init
__(self
)
97 self
.fname
= schema
.fname
100 self
.line
= schema
.line
101 for ch
in schema
.src
[schema
.line_pos
:schema
.pos
]:
103 self
.col
= (self
.col
+ 7) % 8 + 1
106 self
.info
= schema
.incl_info
109 return error_path(self
.info
) + \
110 "%s:%d:%d: %s" % (self
.fname
, self
.line
, self
.col
, self
.msg
)
113 class QAPIExprError(Exception):
114 def __init__(self
, expr_info
, msg
):
115 Exception.__init
__(self
)
117 self
.info
= expr_info
121 return error_path(self
.info
['parent']) + \
122 "%s:%d: %s" % (self
.info
['file'], self
.info
['line'], self
.msg
)
125 class QAPISchemaParser(object):
127 def __init__(self
, fp
, previously_included
=[], incl_info
=None):
128 abs_fname
= os
.path
.abspath(fp
.name
)
131 previously_included
.append(abs_fname
)
132 self
.incl_info
= incl_info
134 if self
.src
== '' or self
.src
[-1] != '\n':
142 while self
.tok
is not None:
143 expr_info
= {'file': fname
, 'line': self
.line
,
144 'parent': self
.incl_info
}
145 expr
= self
.get_expr(False)
146 if isinstance(expr
, dict) and "include" in expr
:
148 raise QAPIExprError(expr_info
,
149 "Invalid 'include' directive")
150 include
= expr
["include"]
151 if not isinstance(include
, str):
152 raise QAPIExprError(expr_info
,
153 "Value of 'include' must be a string")
154 incl_abs_fname
= os
.path
.join(os
.path
.dirname(abs_fname
),
156 # catch inclusion cycle
159 if incl_abs_fname
== os
.path
.abspath(inf
['file']):
160 raise QAPIExprError(expr_info
, "Inclusion loop for %s"
163 # skip multiple include of the same file
164 if incl_abs_fname
in previously_included
:
167 fobj
= open(incl_abs_fname
, 'r')
169 raise QAPIExprError(expr_info
,
170 '%s: %s' % (e
.strerror
, include
))
171 exprs_include
= QAPISchemaParser(fobj
, previously_included
,
173 self
.exprs
.extend(exprs_include
.exprs
)
175 expr_elem
= {'expr': expr
,
177 self
.exprs
.append(expr_elem
)
181 self
.tok
= self
.src
[self
.cursor
]
182 self
.pos
= self
.cursor
187 self
.cursor
= self
.src
.find('\n', self
.cursor
)
188 elif self
.tok
in "{}:,[]":
190 elif self
.tok
== "'":
194 ch
= self
.src
[self
.cursor
]
197 raise QAPISchemaError(self
,
198 'Missing terminating "\'"')
212 for _
in range(0, 4):
213 ch
= self
.src
[self
.cursor
]
215 if ch
not in "0123456789abcdefABCDEF":
216 raise QAPISchemaError(self
,
217 '\\u escape needs 4 '
219 value
= (value
<< 4) + int(ch
, 16)
220 # If Python 2 and 3 didn't disagree so much on
221 # how to handle Unicode, then we could allow
222 # Unicode string defaults. But most of QAPI is
223 # ASCII-only, so we aren't losing much for now.
224 if not value
or value
> 0x7f:
225 raise QAPISchemaError(self
,
226 'For now, \\u escape '
227 'only supports non-zero '
228 'values up to \\u007f')
233 raise QAPISchemaError(self
,
234 "Unknown escape \\%s" % ch
)
243 elif self
.src
.startswith("true", self
.pos
):
247 elif self
.src
.startswith("false", self
.pos
):
251 elif self
.src
.startswith("null", self
.pos
):
255 elif self
.tok
== '\n':
256 if self
.cursor
== len(self
.src
):
260 self
.line_pos
= self
.cursor
261 elif not self
.tok
.isspace():
262 raise QAPISchemaError(self
, 'Stray "%s"' % self
.tok
)
264 def get_members(self
):
270 raise QAPISchemaError(self
, 'Expected string or "}"')
275 raise QAPISchemaError(self
, 'Expected ":"')
278 raise QAPISchemaError(self
, 'Duplicate key "%s"' % key
)
279 expr
[key
] = self
.get_expr(True)
284 raise QAPISchemaError(self
, 'Expected "," or "}"')
287 raise QAPISchemaError(self
, 'Expected string')
289 def get_values(self
):
294 if self
.tok
not in "{['tfn":
295 raise QAPISchemaError(self
, 'Expected "{", "[", "]", string, '
298 expr
.append(self
.get_expr(True))
303 raise QAPISchemaError(self
, 'Expected "," or "]"')
306 def get_expr(self
, nested
):
307 if self
.tok
!= '{' and not nested
:
308 raise QAPISchemaError(self
, 'Expected "{"')
311 expr
= self
.get_members()
312 elif self
.tok
== '[':
314 expr
= self
.get_values()
315 elif self
.tok
in "'tfn":
319 raise QAPISchemaError(self
, 'Expected "{", "[" or string')
323 # Semantic analysis of schema expressions
324 # TODO fold into QAPISchema
325 # TODO catching name collisions in generated code would be nice
329 def find_base_members(base
):
330 if isinstance(base
, dict):
332 base_struct_define
= find_struct(base
)
333 if not base_struct_define
:
335 return base_struct_define
['data']
338 # Return the qtype of an alternate branch, or None on error.
339 def find_alternate_member_qtype(qapi_type
):
340 if qapi_type
in builtin_types
:
341 return builtin_types
[qapi_type
]
342 elif find_struct(qapi_type
):
344 elif find_enum(qapi_type
):
345 return "QTYPE_QSTRING"
346 elif find_union(qapi_type
):
351 # Return the discriminator enum define if discriminator is specified as an
352 # enum type, otherwise return None.
353 def discriminator_find_enum_define(expr
):
354 base
= expr
.get('base')
355 discriminator
= expr
.get('discriminator')
357 if not (discriminator
and base
):
360 base_members
= find_base_members(base
)
364 discriminator_type
= base_members
.get(discriminator
)
365 if not discriminator_type
:
368 return find_enum(discriminator_type
)
371 # Names must be letters, numbers, -, and _. They must start with letter,
372 # except for downstream extensions which must start with __RFQDN_.
373 # Dots are only valid in the downstream extension prefix.
374 valid_name
= re
.compile('^(__[a-zA-Z0-9.-]+_)?'
375 '[a-zA-Z][a-zA-Z0-9_-]*$')
378 def check_name(expr_info
, source
, name
, allow_optional
=False,
383 if not isinstance(name
, str):
384 raise QAPIExprError(expr_info
,
385 "%s requires a string name" % source
)
386 if name
.startswith('*'):
387 membername
= name
[1:]
388 if not allow_optional
:
389 raise QAPIExprError(expr_info
,
390 "%s does not allow optional name '%s'"
392 # Enum members can start with a digit, because the generated C
393 # code always prefixes it with the enum name
394 if enum_member
and membername
[0].isdigit():
395 membername
= 'D' + membername
396 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
397 # and 'q_obj_*' implicit type names.
398 if not valid_name
.match(membername
) or \
399 c_name(membername
, False).startswith('q_'):
400 raise QAPIExprError(expr_info
,
401 "%s uses invalid name '%s'" % (source
, name
))
404 def add_name(name
, info
, meta
, implicit
=False):
406 check_name(info
, "'%s'" % meta
, name
)
407 # FIXME should reject names that differ only in '_' vs. '.'
408 # vs. '-', because they're liable to clash in generated C.
409 if name
in all_names
:
410 raise QAPIExprError(info
,
411 "%s '%s' is already defined"
412 % (all_names
[name
], name
))
413 if not implicit
and (name
.endswith('Kind') or name
.endswith('List')):
414 raise QAPIExprError(info
,
415 "%s '%s' should not end in '%s'"
416 % (meta
, name
, name
[-4:]))
417 all_names
[name
] = meta
420 def add_struct(definition
, info
):
422 name
= definition
['struct']
423 add_name(name
, info
, 'struct')
424 struct_types
.append(definition
)
427 def find_struct(name
):
429 for struct
in struct_types
:
430 if struct
['struct'] == name
:
435 def add_union(definition
, info
):
437 name
= definition
['union']
438 add_name(name
, info
, 'union')
439 union_types
.append(definition
)
442 def find_union(name
):
444 for union
in union_types
:
445 if union
['union'] == name
:
450 def add_enum(name
, info
, enum_values
=None, implicit
=False):
452 add_name(name
, info
, 'enum', implicit
)
453 enum_types
.append({"enum_name": name
, "enum_values": enum_values
})
458 for enum
in enum_types
:
459 if enum
['enum_name'] == name
:
465 return find_enum(name
) is not None
468 def check_type(expr_info
, source
, value
, allow_array
=False,
469 allow_dict
=False, allow_optional
=False,
476 # Check if array type for value is okay
477 if isinstance(value
, list):
479 raise QAPIExprError(expr_info
,
480 "%s cannot be an array" % source
)
481 if len(value
) != 1 or not isinstance(value
[0], str):
482 raise QAPIExprError(expr_info
,
483 "%s: array type must contain single type name"
487 # Check if type name for value is okay
488 if isinstance(value
, str):
489 if value
not in all_names
:
490 raise QAPIExprError(expr_info
,
491 "%s uses unknown type '%s'"
493 if not all_names
[value
] in allow_metas
:
494 raise QAPIExprError(expr_info
,
495 "%s cannot use %s type '%s'"
496 % (source
, all_names
[value
], value
))
500 raise QAPIExprError(expr_info
,
501 "%s should be a type name" % source
)
503 if not isinstance(value
, OrderedDict
):
504 raise QAPIExprError(expr_info
,
505 "%s should be a dictionary or type name" % source
)
507 # value is a dictionary, check that each member is okay
508 for (key
, arg
) in value
.items():
509 check_name(expr_info
, "Member of %s" % source
, key
,
510 allow_optional
=allow_optional
)
511 if c_name(key
, False) == 'u' or c_name(key
, False).startswith('has_'):
512 raise QAPIExprError(expr_info
,
513 "Member of %s uses reserved name '%s'"
515 # Todo: allow dictionaries to represent default values of
516 # an optional argument.
517 check_type(expr_info
, "Member '%s' of %s" % (key
, source
), arg
,
519 allow_metas
=['built-in', 'union', 'alternate', 'struct',
523 def check_command(expr
, expr_info
):
524 name
= expr
['command']
525 boxed
= expr
.get('boxed', False)
527 args_meta
= ['struct']
529 args_meta
+= ['union', 'alternate']
530 check_type(expr_info
, "'data' for command '%s'" % name
,
531 expr
.get('data'), allow_dict
=not boxed
, allow_optional
=True,
532 allow_metas
=args_meta
)
533 returns_meta
= ['union', 'struct']
534 if name
in returns_whitelist
:
535 returns_meta
+= ['built-in', 'alternate', 'enum']
536 check_type(expr_info
, "'returns' for command '%s'" % name
,
537 expr
.get('returns'), allow_array
=True,
538 allow_optional
=True, allow_metas
=returns_meta
)
541 def check_event(expr
, expr_info
):
544 boxed
= expr
.get('boxed', False)
548 meta
+= ['union', 'alternate']
550 check_type(expr_info
, "'data' for event '%s'" % name
,
551 expr
.get('data'), allow_dict
=not boxed
, allow_optional
=True,
555 def check_union(expr
, expr_info
):
557 base
= expr
.get('base')
558 discriminator
= expr
.get('discriminator')
559 members
= expr
['data']
561 # Two types of unions, determined by discriminator.
563 # With no discriminator it is a simple union.
564 if discriminator
is None:
566 allow_metas
= ['built-in', 'union', 'alternate', 'struct', 'enum']
568 raise QAPIExprError(expr_info
,
569 "Simple union '%s' must not have a base"
572 # Else, it's a flat union.
574 # The object must have a string or dictionary 'base'.
575 check_type(expr_info
, "'base' for union '%s'" % name
,
576 base
, allow_dict
=True, allow_optional
=True,
577 allow_metas
=['struct'])
579 raise QAPIExprError(expr_info
,
580 "Flat union '%s' must have a base"
582 base_members
= find_base_members(base
)
585 # The value of member 'discriminator' must name a non-optional
586 # member of the base struct.
587 check_name(expr_info
, "Discriminator of flat union '%s'" % name
,
589 discriminator_type
= base_members
.get(discriminator
)
590 if not discriminator_type
:
591 raise QAPIExprError(expr_info
,
592 "Discriminator '%s' is not a member of base "
594 % (discriminator
, base
))
595 enum_define
= find_enum(discriminator_type
)
596 allow_metas
= ['struct']
597 # Do not allow string discriminator
599 raise QAPIExprError(expr_info
,
600 "Discriminator '%s' must be of enumeration "
601 "type" % discriminator
)
603 # Check every branch; don't allow an empty union
604 if len(members
) == 0:
605 raise QAPIExprError(expr_info
,
606 "Union '%s' cannot have empty 'data'" % name
)
607 for (key
, value
) in members
.items():
608 check_name(expr_info
, "Member of union '%s'" % name
, key
)
610 # Each value must name a known type
611 check_type(expr_info
, "Member '%s' of union '%s'" % (key
, name
),
612 value
, allow_array
=not base
, allow_metas
=allow_metas
)
614 # If the discriminator names an enum type, then all members
615 # of 'data' must also be members of the enum type.
617 if key
not in enum_define
['enum_values']:
618 raise QAPIExprError(expr_info
,
619 "Discriminator value '%s' is not found in "
621 (key
, enum_define
["enum_name"]))
623 # If discriminator is user-defined, ensure all values are covered
625 for value
in enum_define
['enum_values']:
626 if value
not in members
.keys():
627 raise QAPIExprError(expr_info
,
628 "Union '%s' data missing '%s' branch"
632 def check_alternate(expr
, expr_info
):
633 name
= expr
['alternate']
634 members
= expr
['data']
637 # Check every branch; require at least two branches
639 raise QAPIExprError(expr_info
,
640 "Alternate '%s' should have at least two branches "
642 for (key
, value
) in members
.items():
643 check_name(expr_info
, "Member of alternate '%s'" % name
, key
)
645 # Ensure alternates have no type conflicts.
646 check_type(expr_info
, "Member '%s' of alternate '%s'" % (key
, name
),
648 allow_metas
=['built-in', 'union', 'struct', 'enum'])
649 qtype
= find_alternate_member_qtype(value
)
651 raise QAPIExprError(expr_info
,
652 "Alternate '%s' member '%s' cannot use "
653 "type '%s'" % (name
, key
, value
))
654 if qtype
in types_seen
:
655 raise QAPIExprError(expr_info
,
656 "Alternate '%s' member '%s' can't "
657 "be distinguished from member '%s'"
658 % (name
, key
, types_seen
[qtype
]))
659 types_seen
[qtype
] = key
662 def check_enum(expr
, expr_info
):
664 members
= expr
.get('data')
665 prefix
= expr
.get('prefix')
667 if not isinstance(members
, list):
668 raise QAPIExprError(expr_info
,
669 "Enum '%s' requires an array for 'data'" % name
)
670 if prefix
is not None and not isinstance(prefix
, str):
671 raise QAPIExprError(expr_info
,
672 "Enum '%s' requires a string for 'prefix'" % name
)
673 for member
in members
:
674 check_name(expr_info
, "Member of enum '%s'" % name
, member
,
678 def check_struct(expr
, expr_info
):
679 name
= expr
['struct']
680 members
= expr
['data']
682 check_type(expr_info
, "'data' for struct '%s'" % name
, members
,
683 allow_dict
=True, allow_optional
=True)
684 check_type(expr_info
, "'base' for struct '%s'" % name
, expr
.get('base'),
685 allow_metas
=['struct'])
688 def check_keys(expr_elem
, meta
, required
, optional
=[]):
689 expr
= expr_elem
['expr']
690 info
= expr_elem
['info']
692 if not isinstance(name
, str):
693 raise QAPIExprError(info
,
694 "'%s' key must have a string value" % meta
)
695 required
= required
+ [meta
]
696 for (key
, value
) in expr
.items():
697 if key
not in required
and key
not in optional
:
698 raise QAPIExprError(info
,
699 "Unknown key '%s' in %s '%s'"
701 if (key
== 'gen' or key
== 'success-response') and value
is not False:
702 raise QAPIExprError(info
,
703 "'%s' of %s '%s' should only use false value"
705 if key
== 'boxed' and value
is not True:
706 raise QAPIExprError(info
,
707 "'%s' of %s '%s' should only use true value"
711 raise QAPIExprError(info
,
712 "Key '%s' is missing from %s '%s'"
716 def check_exprs(exprs
):
719 # Learn the types and check for valid expression keys
720 for builtin
in builtin_types
.keys():
721 all_names
[builtin
] = 'built-in'
722 for expr_elem
in exprs
:
723 expr
= expr_elem
['expr']
724 info
= expr_elem
['info']
726 check_keys(expr_elem
, 'enum', ['data'], ['prefix'])
727 add_enum(expr
['enum'], info
, expr
['data'])
728 elif 'union' in expr
:
729 check_keys(expr_elem
, 'union', ['data'],
730 ['base', 'discriminator'])
731 add_union(expr
, info
)
732 elif 'alternate' in expr
:
733 check_keys(expr_elem
, 'alternate', ['data'])
734 add_name(expr
['alternate'], info
, 'alternate')
735 elif 'struct' in expr
:
736 check_keys(expr_elem
, 'struct', ['data'], ['base'])
737 add_struct(expr
, info
)
738 elif 'command' in expr
:
739 check_keys(expr_elem
, 'command', [],
740 ['data', 'returns', 'gen', 'success-response', 'boxed'])
741 add_name(expr
['command'], info
, 'command')
742 elif 'event' in expr
:
743 check_keys(expr_elem
, 'event', [], ['data', 'boxed'])
744 add_name(expr
['event'], info
, 'event')
746 raise QAPIExprError(expr_elem
['info'],
747 "Expression is missing metatype")
749 # Try again for hidden UnionKind enum
750 for expr_elem
in exprs
:
751 expr
= expr_elem
['expr']
753 if not discriminator_find_enum_define(expr
):
754 add_enum('%sKind' % expr
['union'], expr_elem
['info'],
756 elif 'alternate' in expr
:
757 add_enum('%sKind' % expr
['alternate'], expr_elem
['info'],
760 # Validate that exprs make sense
761 for expr_elem
in exprs
:
762 expr
= expr_elem
['expr']
763 info
= expr_elem
['info']
766 check_enum(expr
, info
)
767 elif 'union' in expr
:
768 check_union(expr
, info
)
769 elif 'alternate' in expr
:
770 check_alternate(expr
, info
)
771 elif 'struct' in expr
:
772 check_struct(expr
, info
)
773 elif 'command' in expr
:
774 check_command(expr
, info
)
775 elif 'event' in expr
:
776 check_event(expr
, info
)
778 assert False, 'unexpected meta type'
784 # Schema compiler frontend
787 class QAPISchemaEntity(object):
788 def __init__(self
, name
, info
):
789 assert isinstance(name
, str)
791 # For explicitly defined entities, info points to the (explicit)
792 # definition. For builtins (and their arrays), info is None.
793 # For implicitly defined entities, info points to a place that
794 # triggered the implicit definition (there may be more than one
799 return c_name(self
.name
)
801 def check(self
, schema
):
804 def is_implicit(self
):
807 def visit(self
, visitor
):
811 class QAPISchemaVisitor(object):
812 def visit_begin(self
, schema
):
818 def visit_needed(self
, entity
):
819 # Default to visiting everything
822 def visit_builtin_type(self
, name
, info
, json_type
):
825 def visit_enum_type(self
, name
, info
, values
, prefix
):
828 def visit_array_type(self
, name
, info
, element_type
):
831 def visit_object_type(self
, name
, info
, base
, members
, variants
):
834 def visit_object_type_flat(self
, name
, info
, members
, variants
):
837 def visit_alternate_type(self
, name
, info
, variants
):
840 def visit_command(self
, name
, info
, arg_type
, ret_type
,
841 gen
, success_response
, boxed
):
844 def visit_event(self
, name
, info
, arg_type
, boxed
):
848 class QAPISchemaType(QAPISchemaEntity
):
849 # Return the C type for common use.
850 # For the types we commonly box, this is a pointer type.
854 # Return the C type to be used in a parameter list.
855 def c_param_type(self
):
858 # Return the C type to be used where we suppress boxing.
859 def c_unboxed_type(self
):
865 def alternate_qtype(self
):
867 'string': 'QTYPE_QSTRING',
868 'number': 'QTYPE_QFLOAT',
870 'boolean': 'QTYPE_QBOOL',
871 'object': 'QTYPE_QDICT'
873 return json2qtype
.get(self
.json_type())
876 class QAPISchemaBuiltinType(QAPISchemaType
):
877 def __init__(self
, name
, json_type
, c_type
):
878 QAPISchemaType
.__init
__(self
, name
, None)
879 assert not c_type
or isinstance(c_type
, str)
880 assert json_type
in ('string', 'number', 'int', 'boolean', 'null',
882 self
._json
_type
_name
= json_type
883 self
._c
_type
_name
= c_type
889 return self
._c
_type
_name
891 def c_param_type(self
):
892 if self
.name
== 'str':
893 return 'const ' + self
._c
_type
_name
894 return self
._c
_type
_name
897 return self
._json
_type
_name
899 def visit(self
, visitor
):
900 visitor
.visit_builtin_type(self
.name
, self
.info
, self
.json_type())
903 class QAPISchemaEnumType(QAPISchemaType
):
904 def __init__(self
, name
, info
, values
, prefix
):
905 QAPISchemaType
.__init
__(self
, name
, info
)
907 assert isinstance(v
, QAPISchemaMember
)
909 assert prefix
is None or isinstance(prefix
, str)
913 def check(self
, schema
):
915 for v
in self
.values
:
916 v
.check_clash(self
.info
, seen
)
918 def is_implicit(self
):
919 # See QAPISchema._make_implicit_enum_type()
920 return self
.name
.endswith('Kind')
923 return c_name(self
.name
)
925 def member_names(self
):
926 return [v
.name
for v
in self
.values
]
931 def visit(self
, visitor
):
932 visitor
.visit_enum_type(self
.name
, self
.info
,
933 self
.member_names(), self
.prefix
)
936 class QAPISchemaArrayType(QAPISchemaType
):
937 def __init__(self
, name
, info
, element_type
):
938 QAPISchemaType
.__init
__(self
, name
, info
)
939 assert isinstance(element_type
, str)
940 self
._element
_type
_name
= element_type
941 self
.element_type
= None
943 def check(self
, schema
):
944 self
.element_type
= schema
.lookup_type(self
._element
_type
_name
)
945 assert self
.element_type
947 def is_implicit(self
):
951 return c_name(self
.name
) + pointer_suffix
956 def visit(self
, visitor
):
957 visitor
.visit_array_type(self
.name
, self
.info
, self
.element_type
)
960 class QAPISchemaObjectType(QAPISchemaType
):
961 def __init__(self
, name
, info
, base
, local_members
, variants
):
962 # struct has local_members, optional base, and no variants
963 # flat union has base, variants, and no local_members
964 # simple union has local_members, variants, and no base
965 QAPISchemaType
.__init
__(self
, name
, info
)
966 assert base
is None or isinstance(base
, str)
967 for m
in local_members
:
968 assert isinstance(m
, QAPISchemaObjectTypeMember
)
970 if variants
is not None:
971 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
972 variants
.set_owner(name
)
973 self
._base
_name
= base
975 self
.local_members
= local_members
976 self
.variants
= variants
979 def check(self
, schema
):
980 if self
.members
is False: # check for cycles
981 raise QAPIExprError(self
.info
,
982 "Object %s contains itself" % self
.name
)
985 self
.members
= False # mark as being checked
988 self
.base
= schema
.lookup_type(self
._base
_name
)
989 assert isinstance(self
.base
, QAPISchemaObjectType
)
990 self
.base
.check(schema
)
991 self
.base
.check_clash(schema
, self
.info
, seen
)
992 for m
in self
.local_members
:
994 m
.check_clash(self
.info
, seen
)
995 self
.members
= seen
.values()
997 self
.variants
.check(schema
, seen
)
998 assert self
.variants
.tag_member
in self
.members
999 self
.variants
.check_clash(schema
, self
.info
, seen
)
1001 # Check that the members of this type do not cause duplicate JSON members,
1002 # and update seen to track the members seen so far. Report any errors
1003 # on behalf of info, which is not necessarily self.info
1004 def check_clash(self
, schema
, info
, seen
):
1005 assert not self
.variants
# not implemented
1006 for m
in self
.members
:
1007 m
.check_clash(info
, seen
)
1009 def is_implicit(self
):
1010 # See QAPISchema._make_implicit_object_type(), as well as
1011 # _def_predefineds()
1012 return self
.name
.startswith('q_')
1015 assert self
.members
is not None
1016 return not self
.members
and not self
.variants
1019 assert self
.name
!= 'q_empty'
1020 return QAPISchemaType
.c_name(self
)
1023 assert not self
.is_implicit()
1024 return c_name(self
.name
) + pointer_suffix
1026 def c_unboxed_type(self
):
1027 return c_name(self
.name
)
1029 def json_type(self
):
1032 def visit(self
, visitor
):
1033 visitor
.visit_object_type(self
.name
, self
.info
,
1034 self
.base
, self
.local_members
, self
.variants
)
1035 visitor
.visit_object_type_flat(self
.name
, self
.info
,
1036 self
.members
, self
.variants
)
1039 class QAPISchemaMember(object):
1042 def __init__(self
, name
):
1043 assert isinstance(name
, str)
1047 def set_owner(self
, name
):
1048 assert not self
.owner
1051 def check_clash(self
, info
, seen
):
1052 cname
= c_name(self
.name
)
1053 if cname
.lower() != cname
and self
.owner
not in case_whitelist
:
1054 raise QAPIExprError(info
,
1055 "%s should not use uppercase" % self
.describe())
1057 raise QAPIExprError(info
,
1058 "%s collides with %s"
1059 % (self
.describe(), seen
[cname
].describe()))
1062 def _pretty_owner(self
):
1064 if owner
.startswith('q_obj_'):
1065 # See QAPISchema._make_implicit_object_type() - reverse the
1066 # mapping there to create a nice human-readable description
1068 if owner
.endswith('-arg'):
1069 return '(parameter of %s)' % owner
[:-4]
1070 elif owner
.endswith('-base'):
1071 return '(base of %s)' % owner
[:-5]
1073 assert owner
.endswith('-wrapper')
1074 # Unreachable and not implemented
1076 if owner
.endswith('Kind'):
1077 # See QAPISchema._make_implicit_enum_type()
1078 return '(branch of %s)' % owner
[:-4]
1079 return '(%s of %s)' % (self
.role
, owner
)
1082 return "'%s' %s" % (self
.name
, self
._pretty
_owner
())
1085 class QAPISchemaObjectTypeMember(QAPISchemaMember
):
1086 def __init__(self
, name
, typ
, optional
):
1087 QAPISchemaMember
.__init
__(self
, name
)
1088 assert isinstance(typ
, str)
1089 assert isinstance(optional
, bool)
1090 self
._type
_name
= typ
1092 self
.optional
= optional
1094 def check(self
, schema
):
1096 self
.type = schema
.lookup_type(self
._type
_name
)
1100 class QAPISchemaObjectTypeVariants(object):
1101 def __init__(self
, tag_name
, tag_member
, variants
):
1102 # Flat unions pass tag_name but not tag_member.
1103 # Simple unions and alternates pass tag_member but not tag_name.
1104 # After check(), tag_member is always set, and tag_name remains
1105 # a reliable witness of being used by a flat union.
1106 assert bool(tag_member
) != bool(tag_name
)
1107 assert (isinstance(tag_name
, str) or
1108 isinstance(tag_member
, QAPISchemaObjectTypeMember
))
1109 assert len(variants
) > 0
1111 assert isinstance(v
, QAPISchemaObjectTypeVariant
)
1112 self
._tag
_name
= tag_name
1113 self
.tag_member
= tag_member
1114 self
.variants
= variants
1116 def set_owner(self
, name
):
1117 for v
in self
.variants
:
1120 def check(self
, schema
, seen
):
1121 if not self
.tag_member
: # flat union
1122 self
.tag_member
= seen
[c_name(self
._tag
_name
)]
1123 assert self
._tag
_name
== self
.tag_member
.name
1124 assert isinstance(self
.tag_member
.type, QAPISchemaEnumType
)
1125 for v
in self
.variants
:
1127 # Union names must match enum values; alternate names are
1128 # checked separately. Use 'seen' to tell the two apart.
1130 assert v
.name
in self
.tag_member
.type.member_names()
1131 assert isinstance(v
.type, QAPISchemaObjectType
)
1132 v
.type.check(schema
)
1134 def check_clash(self
, schema
, info
, seen
):
1135 for v
in self
.variants
:
1136 # Reset seen map for each variant, since qapi names from one
1137 # branch do not affect another branch
1138 assert isinstance(v
.type, QAPISchemaObjectType
)
1139 v
.type.check_clash(schema
, info
, dict(seen
))
1142 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember
):
1145 def __init__(self
, name
, typ
):
1146 QAPISchemaObjectTypeMember
.__init
__(self
, name
, typ
, False)
1149 class QAPISchemaAlternateType(QAPISchemaType
):
1150 def __init__(self
, name
, info
, variants
):
1151 QAPISchemaType
.__init
__(self
, name
, info
)
1152 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
1153 assert variants
.tag_member
1154 variants
.set_owner(name
)
1155 variants
.tag_member
.set_owner(self
.name
)
1156 self
.variants
= variants
1158 def check(self
, schema
):
1159 self
.variants
.tag_member
.check(schema
)
1160 # Not calling self.variants.check_clash(), because there's nothing
1162 self
.variants
.check(schema
, {})
1163 # Alternate branch names have no relation to the tag enum values;
1164 # so we have to check for potential name collisions ourselves.
1166 for v
in self
.variants
.variants
:
1167 v
.check_clash(self
.info
, seen
)
1170 return c_name(self
.name
) + pointer_suffix
1172 def json_type(self
):
1175 def visit(self
, visitor
):
1176 visitor
.visit_alternate_type(self
.name
, self
.info
, self
.variants
)
1182 class QAPISchemaCommand(QAPISchemaEntity
):
1183 def __init__(self
, name
, info
, arg_type
, ret_type
, gen
, success_response
,
1185 QAPISchemaEntity
.__init
__(self
, name
, info
)
1186 assert not arg_type
or isinstance(arg_type
, str)
1187 assert not ret_type
or isinstance(ret_type
, str)
1188 self
._arg
_type
_name
= arg_type
1189 self
.arg_type
= None
1190 self
._ret
_type
_name
= ret_type
1191 self
.ret_type
= None
1193 self
.success_response
= success_response
1196 def check(self
, schema
):
1197 if self
._arg
_type
_name
:
1198 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1199 assert (isinstance(self
.arg_type
, QAPISchemaObjectType
) or
1200 isinstance(self
.arg_type
, QAPISchemaAlternateType
))
1201 self
.arg_type
.check(schema
)
1203 if self
.arg_type
.is_empty():
1204 raise QAPIExprError(self
.info
,
1205 "Cannot use 'boxed' with empty type")
1207 assert not isinstance(self
.arg_type
, QAPISchemaAlternateType
)
1208 assert not self
.arg_type
.variants
1210 raise QAPIExprError(self
.info
,
1211 "Use of 'boxed' requires 'data'")
1212 if self
._ret
_type
_name
:
1213 self
.ret_type
= schema
.lookup_type(self
._ret
_type
_name
)
1214 assert isinstance(self
.ret_type
, QAPISchemaType
)
1216 def visit(self
, visitor
):
1217 visitor
.visit_command(self
.name
, self
.info
,
1218 self
.arg_type
, self
.ret_type
,
1219 self
.gen
, self
.success_response
, self
.boxed
)
1222 class QAPISchemaEvent(QAPISchemaEntity
):
1223 def __init__(self
, name
, info
, arg_type
, boxed
):
1224 QAPISchemaEntity
.__init
__(self
, name
, info
)
1225 assert not arg_type
or isinstance(arg_type
, str)
1226 self
._arg
_type
_name
= arg_type
1227 self
.arg_type
= None
1230 def check(self
, schema
):
1231 if self
._arg
_type
_name
:
1232 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1233 assert (isinstance(self
.arg_type
, QAPISchemaObjectType
) or
1234 isinstance(self
.arg_type
, QAPISchemaAlternateType
))
1235 self
.arg_type
.check(schema
)
1237 if self
.arg_type
.is_empty():
1238 raise QAPIExprError(self
.info
,
1239 "Cannot use 'boxed' with empty type")
1241 assert not isinstance(self
.arg_type
, QAPISchemaAlternateType
)
1242 assert not self
.arg_type
.variants
1244 raise QAPIExprError(self
.info
,
1245 "Use of 'boxed' requires 'data'")
1247 def visit(self
, visitor
):
1248 visitor
.visit_event(self
.name
, self
.info
, self
.arg_type
, self
.boxed
)
1251 class QAPISchema(object):
1252 def __init__(self
, fname
):
1254 self
.exprs
= check_exprs(QAPISchemaParser(open(fname
, "r")).exprs
)
1255 self
._entity
_dict
= {}
1256 self
._predefining
= True
1257 self
._def
_predefineds
()
1258 self
._predefining
= False
1261 except (QAPISchemaError
, QAPIExprError
) as err
:
1262 print >>sys
.stderr
, err
1265 def _def_entity(self
, ent
):
1266 # Only the predefined types are allowed to not have info
1267 assert ent
.info
or self
._predefining
1268 assert ent
.name
not in self
._entity
_dict
1269 self
._entity
_dict
[ent
.name
] = ent
1271 def lookup_entity(self
, name
, typ
=None):
1272 ent
= self
._entity
_dict
.get(name
)
1273 if typ
and not isinstance(ent
, typ
):
1277 def lookup_type(self
, name
):
1278 return self
.lookup_entity(name
, QAPISchemaType
)
1280 def _def_builtin_type(self
, name
, json_type
, c_type
):
1281 self
._def
_entity
(QAPISchemaBuiltinType(name
, json_type
, c_type
))
1282 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1283 # qapi-types.h from a single .c, all arrays of builtins must be
1284 # declared in the first file whether or not they are used. Nicer
1285 # would be to use lazy instantiation, while figuring out how to
1286 # avoid compilation issues with multiple qapi-types.h.
1287 self
._make
_array
_type
(name
, None)
1289 def _def_predefineds(self
):
1290 for t
in [('str', 'string', 'char' + pointer_suffix
),
1291 ('number', 'number', 'double'),
1292 ('int', 'int', 'int64_t'),
1293 ('int8', 'int', 'int8_t'),
1294 ('int16', 'int', 'int16_t'),
1295 ('int32', 'int', 'int32_t'),
1296 ('int64', 'int', 'int64_t'),
1297 ('uint8', 'int', 'uint8_t'),
1298 ('uint16', 'int', 'uint16_t'),
1299 ('uint32', 'int', 'uint32_t'),
1300 ('uint64', 'int', 'uint64_t'),
1301 ('size', 'int', 'uint64_t'),
1302 ('bool', 'boolean', 'bool'),
1303 ('any', 'value', 'QObject' + pointer_suffix
)]:
1304 self
._def
_builtin
_type
(*t
)
1305 self
.the_empty_object_type
= QAPISchemaObjectType('q_empty', None,
1307 self
._def
_entity
(self
.the_empty_object_type
)
1308 qtype_values
= self
._make
_enum
_members
(['none', 'qnull', 'qint',
1309 'qstring', 'qdict', 'qlist',
1311 self
._def
_entity
(QAPISchemaEnumType('QType', None, qtype_values
,
1314 def _make_enum_members(self
, values
):
1315 return [QAPISchemaMember(v
) for v
in values
]
1317 def _make_implicit_enum_type(self
, name
, info
, values
):
1318 # See also QAPISchemaObjectTypeMember._pretty_owner()
1319 name
= name
+ 'Kind' # Use namespace reserved by add_name()
1320 self
._def
_entity
(QAPISchemaEnumType(
1321 name
, info
, self
._make
_enum
_members
(values
), None))
1324 def _make_array_type(self
, element_type
, info
):
1325 name
= element_type
+ 'List' # Use namespace reserved by add_name()
1326 if not self
.lookup_type(name
):
1327 self
._def
_entity
(QAPISchemaArrayType(name
, info
, element_type
))
1330 def _make_implicit_object_type(self
, name
, info
, role
, members
):
1333 # See also QAPISchemaObjectTypeMember._pretty_owner()
1334 name
= 'q_obj_%s-%s' % (name
, role
)
1335 if not self
.lookup_entity(name
, QAPISchemaObjectType
):
1336 self
._def
_entity
(QAPISchemaObjectType(name
, info
, None,
1340 def _def_enum_type(self
, expr
, info
):
1343 prefix
= expr
.get('prefix')
1344 self
._def
_entity
(QAPISchemaEnumType(
1345 name
, info
, self
._make
_enum
_members
(data
), prefix
))
1347 def _make_member(self
, name
, typ
, info
):
1349 if name
.startswith('*'):
1352 if isinstance(typ
, list):
1353 assert len(typ
) == 1
1354 typ
= self
._make
_array
_type
(typ
[0], info
)
1355 return QAPISchemaObjectTypeMember(name
, typ
, optional
)
1357 def _make_members(self
, data
, info
):
1358 return [self
._make
_member
(key
, value
, info
)
1359 for (key
, value
) in data
.iteritems()]
1361 def _def_struct_type(self
, expr
, info
):
1362 name
= expr
['struct']
1363 base
= expr
.get('base')
1365 self
._def
_entity
(QAPISchemaObjectType(name
, info
, base
,
1366 self
._make
_members
(data
, info
),
1369 def _make_variant(self
, case
, typ
):
1370 return QAPISchemaObjectTypeVariant(case
, typ
)
1372 def _make_simple_variant(self
, case
, typ
, info
):
1373 if isinstance(typ
, list):
1374 assert len(typ
) == 1
1375 typ
= self
._make
_array
_type
(typ
[0], info
)
1376 typ
= self
._make
_implicit
_object
_type
(
1377 typ
, info
, 'wrapper', [self
._make
_member
('data', typ
, info
)])
1378 return QAPISchemaObjectTypeVariant(case
, typ
)
1380 def _def_union_type(self
, expr
, info
):
1381 name
= expr
['union']
1383 base
= expr
.get('base')
1384 tag_name
= expr
.get('discriminator')
1386 if isinstance(base
, dict):
1387 base
= (self
._make
_implicit
_object
_type
(
1388 name
, info
, 'base', self
._make
_members
(base
, info
)))
1390 variants
= [self
._make
_variant
(key
, value
)
1391 for (key
, value
) in data
.iteritems()]
1394 variants
= [self
._make
_simple
_variant
(key
, value
, info
)
1395 for (key
, value
) in data
.iteritems()]
1396 typ
= self
._make
_implicit
_enum
_type
(name
, info
,
1397 [v
.name
for v
in variants
])
1398 tag_member
= QAPISchemaObjectTypeMember('type', typ
, False)
1399 members
= [tag_member
]
1401 QAPISchemaObjectType(name
, info
, base
, members
,
1402 QAPISchemaObjectTypeVariants(tag_name
,
1406 def _def_alternate_type(self
, expr
, info
):
1407 name
= expr
['alternate']
1409 variants
= [self
._make
_variant
(key
, value
)
1410 for (key
, value
) in data
.iteritems()]
1411 tag_member
= QAPISchemaObjectTypeMember('type', 'QType', False)
1413 QAPISchemaAlternateType(name
, info
,
1414 QAPISchemaObjectTypeVariants(None,
1418 def _def_command(self
, expr
, info
):
1419 name
= expr
['command']
1420 data
= expr
.get('data')
1421 rets
= expr
.get('returns')
1422 gen
= expr
.get('gen', True)
1423 success_response
= expr
.get('success-response', True)
1424 boxed
= expr
.get('boxed', False)
1425 if isinstance(data
, OrderedDict
):
1426 data
= self
._make
_implicit
_object
_type
(
1427 name
, info
, 'arg', self
._make
_members
(data
, info
))
1428 if isinstance(rets
, list):
1429 assert len(rets
) == 1
1430 rets
= self
._make
_array
_type
(rets
[0], info
)
1431 self
._def
_entity
(QAPISchemaCommand(name
, info
, data
, rets
, gen
,
1432 success_response
, boxed
))
1434 def _def_event(self
, expr
, info
):
1435 name
= expr
['event']
1436 data
= expr
.get('data')
1437 boxed
= expr
.get('boxed', False)
1438 if isinstance(data
, OrderedDict
):
1439 data
= self
._make
_implicit
_object
_type
(
1440 name
, info
, 'arg', self
._make
_members
(data
, info
))
1441 self
._def
_entity
(QAPISchemaEvent(name
, info
, data
, boxed
))
1443 def _def_exprs(self
):
1444 for expr_elem
in self
.exprs
:
1445 expr
= expr_elem
['expr']
1446 info
= expr_elem
['info']
1448 self
._def
_enum
_type
(expr
, info
)
1449 elif 'struct' in expr
:
1450 self
._def
_struct
_type
(expr
, info
)
1451 elif 'union' in expr
:
1452 self
._def
_union
_type
(expr
, info
)
1453 elif 'alternate' in expr
:
1454 self
._def
_alternate
_type
(expr
, info
)
1455 elif 'command' in expr
:
1456 self
._def
_command
(expr
, info
)
1457 elif 'event' in expr
:
1458 self
._def
_event
(expr
, info
)
1463 for ent
in self
._entity
_dict
.values():
1466 def visit(self
, visitor
):
1467 visitor
.visit_begin(self
)
1468 for (name
, entity
) in sorted(self
._entity
_dict
.items()):
1469 if visitor
.visit_needed(entity
):
1470 entity
.visit(visitor
)
1475 # Code generation helpers
1478 def camel_case(name
):
1482 if ch
in ['_', '-']:
1485 new_name
+= ch
.upper()
1488 new_name
+= ch
.lower()
1492 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1493 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1494 # ENUM24_Name -> ENUM24_NAME
1495 def camel_to_upper(value
):
1496 c_fun_str
= c_name(value
, False)
1504 # When c is upper and no "_" appears before, do more checks
1505 if c
.isupper() and (i
> 0) and c_fun_str
[i
- 1] != "_":
1506 if i
< l
- 1 and c_fun_str
[i
+ 1].islower():
1508 elif c_fun_str
[i
- 1].isdigit():
1511 return new_name
.lstrip('_').upper()
1514 def c_enum_const(type_name
, const_name
, prefix
=None):
1515 if prefix
is not None:
1517 return camel_to_upper(type_name
) + '_' + c_name(const_name
, False).upper()
1519 c_name_trans
= string
.maketrans('.-', '__')
1522 # Map @name to a valid C identifier.
1523 # If @protect, avoid returning certain ticklish identifiers (like
1524 # C keywords) by prepending "q_".
1526 # Used for converting 'name' from a 'name':'type' qapi definition
1527 # into a generated struct member, as well as converting type names
1528 # into substrings of a generated C function name.
1529 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1530 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1531 def c_name(name
, protect
=True):
1532 # ANSI X3J11/88-090, 3.1.1
1533 c89_words
= set(['auto', 'break', 'case', 'char', 'const', 'continue',
1534 'default', 'do', 'double', 'else', 'enum', 'extern',
1535 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1536 'return', 'short', 'signed', 'sizeof', 'static',
1537 'struct', 'switch', 'typedef', 'union', 'unsigned',
1538 'void', 'volatile', 'while'])
1539 # ISO/IEC 9899:1999, 6.4.1
1540 c99_words
= set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1541 # ISO/IEC 9899:2011, 6.4.1
1542 c11_words
= set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1543 '_Noreturn', '_Static_assert', '_Thread_local'])
1544 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1546 gcc_words
= set(['asm', 'typeof'])
1547 # C++ ISO/IEC 14882:2003 2.11
1548 cpp_words
= set(['bool', 'catch', 'class', 'const_cast', 'delete',
1549 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1550 'namespace', 'new', 'operator', 'private', 'protected',
1551 'public', 'reinterpret_cast', 'static_cast', 'template',
1552 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1553 'using', 'virtual', 'wchar_t',
1554 # alternative representations
1555 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1556 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1557 # namespace pollution:
1558 polluted_words
= set(['unix', 'errno', 'mips', 'sparc'])
1559 name
= name
.translate(c_name_trans
)
1560 if protect
and (name
in c89_words | c99_words | c11_words | gcc_words
1561 | cpp_words | polluted_words
):
1565 eatspace
= '\033EATSPACE.'
1566 pointer_suffix
= ' *' + eatspace
1569 def genindent(count
):
1571 for _
in range(count
):
1578 def push_indent(indent_amount
=4):
1580 indent_level
+= indent_amount
1583 def pop_indent(indent_amount
=4):
1585 indent_level
-= indent_amount
1588 # Generate @code with @kwds interpolated.
1589 # Obey indent_level, and strip eatspace.
1590 def cgen(code
, **kwds
):
1593 indent
= genindent(indent_level
)
1594 # re.subn() lacks flags support before Python 2.7, use re.compile()
1595 raw
= re
.subn(re
.compile("^.", re
.MULTILINE
),
1596 indent
+ r
'\g<0>', raw
)
1598 return re
.sub(re
.escape(eatspace
) + ' *', '', raw
)
1601 def mcgen(code
, **kwds
):
1604 return cgen(code
, **kwds
)
1607 def guardname(filename
):
1608 return c_name(filename
, protect
=False).upper()
1611 def guardstart(name
):
1618 name
=guardname(name
))
1624 #endif /* %(name)s */
1627 name
=guardname(name
))
1630 def gen_enum_lookup(name
, values
, prefix
=None):
1633 const char *const %(c_name)s_lookup[] = {
1635 c_name
=c_name(name
))
1636 for value
in values
:
1637 index
= c_enum_const(name
, value
, prefix
)
1639 [%(index)s] = "%(value)s",
1641 index
=index
, value
=value
)
1643 max_index
= c_enum_const(name
, '_MAX', prefix
)
1645 [%(max_index)s] = NULL,
1648 max_index
=max_index
)
1652 def gen_enum(name
, values
, prefix
=None):
1653 # append automatically generated _MAX value
1654 enum_values
= values
+ ['_MAX']
1658 typedef enum %(c_name)s {
1660 c_name
=c_name(name
))
1663 for value
in enum_values
:
1667 c_enum
=c_enum_const(name
, value
, prefix
),
1674 c_name
=c_name(name
))
1678 extern const char *const %(c_name)s_lookup[];
1680 c_name
=c_name(name
))
1684 def gen_params(arg_type
, boxed
, extra
):
1691 ret
+= '%s arg' % arg_type
.c_param_type()
1694 assert not arg_type
.variants
1695 for memb
in arg_type
.members
:
1699 ret
+= 'bool has_%s, ' % c_name(memb
.name
)
1700 ret
+= '%s %s' % (memb
.type.c_param_type(),
1708 # Common command line parsing
1712 def parse_command_line(extra_options
="", extra_long_options
=[]):
1715 opts
, args
= getopt
.gnu_getopt(sys
.argv
[1:],
1716 "chp:o:" + extra_options
,
1717 ["source", "header", "prefix=",
1718 "output-dir="] + extra_long_options
)
1719 except getopt
.GetoptError
as err
:
1720 print >>sys
.stderr
, "%s: %s" % (sys
.argv
[0], str(err
))
1731 if o
in ("-p", "--prefix"):
1732 match
= re
.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a
)
1733 if match
.end() != len(a
):
1734 print >>sys
.stderr
, \
1735 "%s: 'funny character '%s' in argument of --prefix" \
1736 % (sys
.argv
[0], a
[match
.end()])
1739 elif o
in ("-o", "--output-dir"):
1740 output_dir
= a
+ "/"
1741 elif o
in ("-c", "--source"):
1743 elif o
in ("-h", "--header"):
1746 extra_opts
.append(oa
)
1748 if not do_c
and not do_h
:
1753 print >>sys
.stderr
, "%s: need exactly one argument" % sys
.argv
[0]
1757 return (fname
, output_dir
, do_c
, do_h
, prefix
, extra_opts
)
1760 # Generate output files with boilerplate
1764 def open_output(output_dir
, do_c
, do_h
, prefix
, c_file
, h_file
,
1765 c_comment
, h_comment
):
1766 guard
= guardname(prefix
+ h_file
)
1767 c_file
= output_dir
+ prefix
+ c_file
1768 h_file
= output_dir
+ prefix
+ h_file
1772 os
.makedirs(output_dir
)
1773 except os
.error
as e
:
1774 if e
.errno
!= errno
.EEXIST
:
1777 def maybe_open(really
, name
, opt
):
1779 return open(name
, opt
)
1782 return StringIO
.StringIO()
1784 fdef
= maybe_open(do_c
, c_file
, 'w')
1785 fdecl
= maybe_open(do_h
, h_file
, 'w')
1787 fdef
.write(mcgen('''
1788 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1793 fdecl
.write(mcgen('''
1794 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1800 comment
=h_comment
, guard
=guard
))
1802 return (fdef
, fdecl
)
1805 def close_output(fdef
, fdecl
):