4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2015 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_code possible, actually
39 # Whitelist of commands allowed to return a non-dictionary
42 'human-monitor-command',
44 'query-migrate-cache-size',
51 'guest-fsfreeze-freeze',
52 'guest-fsfreeze-freeze-list',
53 'guest-fsfreeze-status',
54 'guest-fsfreeze-thaw',
58 'guest-sync-delimited',
68 # Parsing the schema into expressions
72 def error_path(parent
):
75 res
= ("In file included from %s:%d:\n" % (parent
['file'],
76 parent
['line'])) + res
77 parent
= parent
['parent']
81 class QAPISchemaError(Exception):
82 def __init__(self
, schema
, msg
):
83 Exception.__init
__(self
)
84 self
.fname
= schema
.fname
87 self
.line
= schema
.line
88 for ch
in schema
.src
[schema
.line_pos
:schema
.pos
]:
90 self
.col
= (self
.col
+ 7) % 8 + 1
93 self
.info
= schema
.incl_info
96 return error_path(self
.info
) + \
97 "%s:%d:%d: %s" % (self
.fname
, self
.line
, self
.col
, self
.msg
)
100 class QAPIExprError(Exception):
101 def __init__(self
, expr_info
, msg
):
102 Exception.__init
__(self
)
104 self
.info
= expr_info
108 return error_path(self
.info
['parent']) + \
109 "%s:%d: %s" % (self
.info
['file'], self
.info
['line'], self
.msg
)
112 class QAPISchemaParser(object):
114 def __init__(self
, fp
, previously_included
=[], incl_info
=None):
115 abs_fname
= os
.path
.abspath(fp
.name
)
118 previously_included
.append(abs_fname
)
119 self
.incl_info
= incl_info
121 if self
.src
== '' or self
.src
[-1] != '\n':
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
:
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
),
143 # catch inclusion cycle
146 if incl_abs_fname
== os
.path
.abspath(inf
['file']):
147 raise QAPIExprError(expr_info
, "Inclusion loop for %s"
150 # skip multiple include of the same file
151 if incl_abs_fname
in previously_included
:
154 fobj
= open(incl_abs_fname
, 'r')
156 raise QAPIExprError(expr_info
,
157 '%s: %s' % (e
.strerror
, include
))
158 exprs_include
= QAPISchemaParser(fobj
, previously_included
,
160 self
.exprs
.extend(exprs_include
.exprs
)
162 expr_elem
= {'expr': expr
,
164 self
.exprs
.append(expr_elem
)
168 self
.tok
= self
.src
[self
.cursor
]
169 self
.pos
= self
.cursor
174 self
.cursor
= self
.src
.find('\n', self
.cursor
)
175 elif self
.tok
in ['{', '}', ':', ',', '[', ']']:
177 elif self
.tok
== "'":
181 ch
= self
.src
[self
.cursor
]
184 raise QAPISchemaError(self
,
185 'Missing terminating "\'"')
199 for _
in range(0, 4):
200 ch
= self
.src
[self
.cursor
]
202 if ch
not in "0123456789abcdefABCDEF":
203 raise QAPISchemaError(self
,
204 '\\u escape needs 4 '
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')
220 raise QAPISchemaError(self
,
221 "Unknown escape \\%s" % ch
)
230 elif self
.src
.startswith("true", self
.pos
):
234 elif self
.src
.startswith("false", self
.pos
):
238 elif self
.src
.startswith("null", self
.pos
):
242 elif self
.tok
== '\n':
243 if self
.cursor
== len(self
.src
):
247 self
.line_pos
= self
.cursor
248 elif not self
.tok
.isspace():
249 raise QAPISchemaError(self
, 'Stray "%s"' % self
.tok
)
251 def get_members(self
):
257 raise QAPISchemaError(self
, 'Expected string or "}"')
262 raise QAPISchemaError(self
, 'Expected ":"')
265 raise QAPISchemaError(self
, 'Duplicate key "%s"' % key
)
266 expr
[key
] = self
.get_expr(True)
271 raise QAPISchemaError(self
, 'Expected "," or "}"')
274 raise QAPISchemaError(self
, 'Expected string')
276 def get_values(self
):
281 if self
.tok
not in "{['tfn":
282 raise QAPISchemaError(self
, 'Expected "{", "[", "]", string, '
285 expr
.append(self
.get_expr(True))
290 raise QAPISchemaError(self
, 'Expected "," or "]"')
293 def get_expr(self
, nested
):
294 if self
.tok
!= '{' and not nested
:
295 raise QAPISchemaError(self
, 'Expected "{"')
298 expr
= self
.get_members()
299 elif self
.tok
== '[':
301 expr
= self
.get_values()
302 elif self
.tok
in "'tfn":
306 raise QAPISchemaError(self
, 'Expected "{", "[" or string')
310 # Semantic analysis of schema expressions
311 # TODO fold into QAPISchema
312 # TODO catching name collisions in generated code would be nice
316 def find_base_fields(base
):
317 base_struct_define
= find_struct(base
)
318 if not base_struct_define
:
320 return base_struct_define
['data']
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
):
329 elif find_enum(qapi_type
):
330 return "QTYPE_QSTRING"
331 elif find_union(qapi_type
):
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')
342 if not (discriminator
and base
):
345 base_fields
= find_base_fields(base
)
349 discriminator_type
= base_fields
.get(discriminator
)
350 if not discriminator_type
:
353 return find_enum(discriminator_type
)
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_.-]*$')
361 def check_name(expr_info
, source
, name
, allow_optional
=False,
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'"
375 # Enum members can start with a digit, because the generated C
376 # code always prefixes it with the enum name
378 membername
= '_' + membername
379 if not valid_name
.match(membername
):
380 raise QAPIExprError(expr_info
,
381 "%s uses invalid name '%s'" % (source
, name
))
384 def add_name(name
, info
, meta
, implicit
=False):
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
[-4:] == 'Kind':
394 raise QAPIExprError(info
,
395 "%s '%s' should not end in 'Kind'"
397 all_names
[name
] = meta
400 def add_struct(definition
, info
):
402 name
= definition
['struct']
403 add_name(name
, info
, 'struct')
404 struct_types
.append(definition
)
407 def find_struct(name
):
409 for struct
in struct_types
:
410 if struct
['struct'] == name
:
415 def add_union(definition
, info
):
417 name
= definition
['union']
418 add_name(name
, info
, 'union')
419 union_types
.append(definition
)
422 def find_union(name
):
424 for union
in union_types
:
425 if union
['union'] == name
:
430 def add_enum(name
, info
, enum_values
=None, implicit
=False):
432 add_name(name
, info
, 'enum', implicit
)
433 enum_types
.append({"enum_name": name
, "enum_values": enum_values
})
438 for enum
in enum_types
:
439 if enum
['enum_name'] == name
:
445 return find_enum(name
) is not None
448 def check_type(expr_info
, source
, value
, allow_array
=False,
449 allow_dict
=False, allow_optional
=False,
456 # Check if array type for value is okay
457 if isinstance(value
, list):
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"
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'"
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
))
480 raise QAPIExprError(expr_info
,
481 "%s should be a type name" % source
)
483 if not isinstance(value
, OrderedDict
):
484 raise QAPIExprError(expr_info
,
485 "%s should be a dictionary or type name" % source
)
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
,
495 allow_metas
=['built-in', 'union', 'alternate', 'struct',
499 def check_member_clash(expr_info
, base_name
, data
, source
=""):
500 base
= find_struct(base_name
)
502 base_members
= base
['data']
503 for key
in data
.keys():
504 if key
.startswith('*'):
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
))
511 check_member_clash(expr_info
, base
['base'], data
, source
)
514 def check_command(expr
, expr_info
):
515 name
= expr
['command']
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
)
528 def check_event(expr
, expr_info
):
532 if name
.upper() == 'MAX':
533 raise QAPIExprError(expr_info
, "Event name 'MAX' cannot be created")
535 check_type(expr_info
, "'data' for event '%s'" % name
,
536 expr
.get('data'), allow_dict
=True, allow_optional
=True,
537 allow_metas
=['struct'])
540 def check_union(expr
, expr_info
):
542 base
= expr
.get('base')
543 discriminator
= expr
.get('discriminator')
544 members
= expr
['data']
545 values
= {'MAX': '(automatic)', 'KIND': '(automatic)'}
547 # Two types of unions, determined by discriminator.
549 # With no discriminator it is a simple union.
550 if discriminator
is None:
552 allow_metas
= ['built-in', 'union', 'alternate', 'struct', 'enum']
554 raise QAPIExprError(expr_info
,
555 "Simple union '%s' must not have a base"
558 # Else, it's a flat union.
560 # The object must have a string member 'base'.
561 check_type(expr_info
, "'base' for union '%s'" % name
,
562 base
, allow_metas
=['struct'])
564 raise QAPIExprError(expr_info
,
565 "Flat union '%s' must have a base"
567 base_fields
= find_base_fields(base
)
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
,
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 "
579 % (discriminator
, base
))
580 enum_define
= find_enum(discriminator_type
)
581 allow_metas
= ['struct']
582 # Do not allow string discriminator
584 raise QAPIExprError(expr_info
,
585 "Discriminator '%s' must be of enumeration "
586 "type" % discriminator
)
589 for (key
, value
) in members
.items():
590 check_name(expr_info
, "Member of union '%s'" % name
, key
)
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
)
597 branch_struct
= find_struct(value
)
599 check_member_clash(expr_info
, base
, branch_struct
['data'],
600 " of branch '%s'" % key
)
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.
606 if key
not in enum_define
['enum_values']:
607 raise QAPIExprError(expr_info
,
608 "Discriminator value '%s' is not found in "
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"]))
617 # Otherwise, check for conflicts in the generated enum
619 c_key
= camel_to_upper(key
)
621 raise QAPIExprError(expr_info
,
622 "Union '%s' member '%s' clashes with '%s'"
623 % (name
, key
, values
[c_key
]))
627 def check_alternate(expr
, expr_info
):
628 name
= expr
['alternate']
629 members
= expr
['data']
630 values
= {'MAX': '(automatic)'}
634 for (key
, value
) in members
.items():
635 check_name(expr_info
, "Member of alternate '%s'" % name
, key
)
637 # Check for conflicts in the generated enum
638 c_key
= camel_to_upper(key
)
640 raise QAPIExprError(expr_info
,
641 "Alternate '%s' member '%s' clashes with '%s'"
642 % (name
, key
, values
[c_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 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
659 def check_enum(expr
, expr_info
):
661 members
= expr
.get('data')
662 prefix
= expr
.get('prefix')
663 values
= {'MAX': '(automatic)'}
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
,
674 key
= camel_to_upper(member
)
676 raise QAPIExprError(expr_info
,
677 "Enum '%s' member '%s' clashes with '%s'"
678 % (name
, member
, values
[key
]))
682 def check_struct(expr
, expr_info
):
683 name
= expr
['struct']
684 members
= expr
['data']
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'])
691 check_member_clash(expr_info
, expr
['base'], expr
['data'])
694 def check_keys(expr_elem
, meta
, required
, optional
=[]):
695 expr
= expr_elem
['expr']
696 info
= expr_elem
['info']
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'"
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"
713 raise QAPIExprError(info
,
714 "Key '%s' is missing from %s '%s'"
718 def check_exprs(exprs
):
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']
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')
748 raise QAPIExprError(expr_elem
['info'],
749 "Expression is missing metatype")
751 # Try again for hidden UnionKind enum
752 for expr_elem
in exprs
:
753 expr
= expr_elem
['expr']
755 if not discriminator_find_enum_define(expr
):
756 add_enum('%sKind' % expr
['union'], expr_elem
['info'],
758 elif 'alternate' in expr
:
759 add_enum('%sKind' % expr
['alternate'], expr_elem
['info'],
762 # Validate that exprs make sense
763 for expr_elem
in exprs
:
764 expr
= expr_elem
['expr']
765 info
= expr_elem
['info']
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
)
780 assert False, 'unexpected meta type'
786 # Schema compiler frontend
789 class QAPISchemaEntity(object):
790 def __init__(self
, name
, info
):
791 assert isinstance(name
, str)
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
801 return c_name(self
.name
)
803 def check(self
, schema
):
806 def is_implicit(self
):
809 def visit(self
, visitor
):
813 class QAPISchemaVisitor(object):
814 def visit_begin(self
, schema
):
820 def visit_needed(self
, entity
):
821 # Default to visiting everything
824 def visit_builtin_type(self
, name
, info
, json_type
):
827 def visit_enum_type(self
, name
, info
, values
, prefix
):
830 def visit_array_type(self
, name
, info
, element_type
):
833 def visit_object_type(self
, name
, info
, base
, members
, variants
):
836 def visit_object_type_flat(self
, name
, info
, members
, variants
):
839 def visit_alternate_type(self
, name
, info
, variants
):
842 def visit_command(self
, name
, info
, arg_type
, ret_type
,
843 gen
, success_response
):
846 def visit_event(self
, name
, info
, arg_type
):
850 class QAPISchemaType(QAPISchemaEntity
):
851 def c_type(self
, is_param
=False):
852 return c_name(self
.name
) + pointer_suffix
860 def alternate_qtype(self
):
862 'string': 'QTYPE_QSTRING',
863 'number': 'QTYPE_QFLOAT',
865 'boolean': 'QTYPE_QBOOL',
866 'object': 'QTYPE_QDICT'
868 return json2qtype
.get(self
.json_type())
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',
877 self
._json
_type
_name
= json_type
878 self
._c
_type
_name
= c_type
879 self
._c
_null
_val
= c_null
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
890 return self
._c
_null
_val
893 return self
._json
_type
_name
895 def visit(self
, visitor
):
896 visitor
.visit_builtin_type(self
.name
, self
.info
, self
.json_type())
899 class QAPISchemaEnumType(QAPISchemaType
):
900 def __init__(self
, name
, info
, values
, prefix
):
901 QAPISchemaType
.__init
__(self
, name
, info
)
903 assert isinstance(v
, str)
904 assert prefix
is None or isinstance(prefix
, str)
908 def check(self
, schema
):
909 assert len(set(self
.values
)) == len(self
.values
)
911 def is_implicit(self
):
912 # See QAPISchema._make_implicit_enum_type()
913 return self
.name
[-4:] == 'Kind'
915 def c_type(self
, is_param
=False):
916 return c_name(self
.name
)
919 return c_enum_const(self
.name
, (self
.values
+ ['MAX'])[0],
925 def visit(self
, visitor
):
926 visitor
.visit_enum_type(self
.name
, self
.info
,
927 self
.values
, self
.prefix
)
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
937 def check(self
, schema
):
938 self
.element_type
= schema
.lookup_type(self
._element
_type
_name
)
939 assert self
.element_type
941 def is_implicit(self
):
947 def visit(self
, visitor
):
948 visitor
.visit_array_type(self
.name
, self
.info
, self
.element_type
)
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
961 self
.local_members
= local_members
962 self
.variants
= variants
965 def check(self
, schema
):
966 assert self
.members
is not False # not running in cycles
969 self
.members
= False # mark as being checked
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
)
980 assert c_name(m
.name
) not in seen
982 for m
in self
.local_members
:
983 m
.check(schema
, members
, seen
)
985 self
.variants
.check(schema
, members
, seen
)
986 self
.members
= members
988 def is_implicit(self
):
989 # See QAPISchema._make_implicit_object_type()
990 return self
.name
[0] == ':'
993 assert not self
.is_implicit()
994 return QAPISchemaType
.c_name(self
)
996 def c_type(self
, is_param
=False):
997 assert not self
.is_implicit()
998 return QAPISchemaType
.c_type(self
)
1000 def json_type(self
):
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
)
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)
1016 self
._type
_name
= typ
1018 self
.optional
= optional
1020 def check(self
, schema
, all_members
, seen
):
1021 assert self
.name
not in seen
1022 self
.type = schema
.lookup_type(self
._type
_name
)
1024 all_members
.append(self
)
1025 seen
[self
.name
] = self
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
))
1038 assert isinstance(v
, QAPISchemaObjectTypeVariant
)
1039 self
.tag_name
= tag_name
1040 self
.tag_member
= tag_member
1041 self
.variants
= variants
1043 def check(self
, schema
, members
, seen
):
1045 self
.tag_member
= seen
[self
.tag_name
]
1047 self
.tag_member
.check(schema
, members
, seen
)
1048 assert isinstance(self
.tag_member
.type, QAPISchemaEnumType
)
1049 for v
in self
.variants
:
1051 v
.check(schema
, self
.tag_member
.type, vseen
)
1054 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember
):
1055 def __init__(self
, name
, typ
):
1056 QAPISchemaObjectTypeMember
.__init
__(self
, name
, typ
, False)
1058 def check(self
, schema
, tag_type
, seen
):
1059 QAPISchemaObjectTypeMember
.check(self
, schema
, [], seen
)
1060 assert self
.name
in tag_type
.values
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
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
1080 def check(self
, schema
):
1081 self
.variants
.check(schema
, [], {})
1083 def json_type(self
):
1086 def visit(self
, visitor
):
1087 visitor
.visit_alternate_type(self
.name
, self
.info
, self
.variants
)
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
1100 self
.success_response
= success_response
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
)
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
)
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
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
1130 def visit(self
, visitor
):
1131 visitor
.visit_event(self
.name
, self
.info
, self
.arg_type
)
1134 class QAPISchema(object):
1135 def __init__(self
, fname
):
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
1144 except (QAPISchemaError
, QAPIExprError
), err
:
1145 print >>sys
.stderr
, err
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
1154 def lookup_entity(self
, name
, typ
=None):
1155 ent
= self
._entity
_dict
.get(name
)
1156 if typ
and not isinstance(ent
, typ
):
1160 def lookup_type(self
, name
):
1161 return self
.lookup_entity(name
, QAPISchemaType
)
1163 def _def_builtin_type(self
, name
, json_type
, c_type
, c_null
):
1164 self
._def
_entity
(QAPISchemaBuiltinType(name
, json_type
,
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)
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,
1191 self
._def
_entity
(self
.the_empty_object_type
)
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))
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
))
1206 def _make_implicit_object_type(self
, name
, info
, role
, members
):
1209 name
= ':obj-%s-%s' % (name
, role
)
1210 if not self
.lookup_entity(name
, QAPISchemaObjectType
):
1211 self
._def
_entity
(QAPISchemaObjectType(name
, info
, None,
1215 def _def_enum_type(self
, expr
, info
):
1218 prefix
= expr
.get('prefix')
1219 self
._def
_entity
(QAPISchemaEnumType(name
, info
, data
, prefix
))
1221 def _make_member(self
, name
, typ
, info
):
1223 if name
.startswith('*'):
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
)
1231 def _make_members(self
, data
, info
):
1232 return [self
._make
_member
(key
, value
, info
)
1233 for (key
, value
) in data
.iteritems()]
1235 def _def_struct_type(self
, expr
, info
):
1236 name
= expr
['struct']
1237 base
= expr
.get('base')
1239 self
._def
_entity
(QAPISchemaObjectType(name
, info
, base
,
1240 self
._make
_members
(data
, info
),
1243 def _make_variant(self
, case
, typ
):
1244 return QAPISchemaObjectTypeVariant(case
, typ
)
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
)
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)
1259 def _def_union_type(self
, expr
, info
):
1260 name
= expr
['union']
1262 base
= expr
.get('base')
1263 tag_name
= expr
.get('discriminator')
1266 variants
= [self
._make
_variant
(key
, value
)
1267 for (key
, value
) in data
.iteritems()]
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
)
1273 QAPISchemaObjectType(name
, info
, base
,
1274 self
._make
_members
(OrderedDict(), info
),
1275 QAPISchemaObjectTypeVariants(tag_name
,
1279 def _def_alternate_type(self
, expr
, info
):
1280 name
= expr
['alternate']
1282 variants
= [self
._make
_variant
(key
, value
)
1283 for (key
, value
) in data
.iteritems()]
1284 tag_member
= self
._make
_implicit
_tag
(name
, info
, variants
)
1286 QAPISchemaAlternateType(name
, info
,
1287 QAPISchemaObjectTypeVariants(None,
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
,
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
))
1314 def _def_exprs(self
):
1315 for expr_elem
in self
.exprs
:
1316 expr
= expr_elem
['expr']
1317 info
= expr_elem
['info']
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
)
1334 for ent
in self
._entity
_dict
.values():
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
)
1346 # Code generation helpers
1349 def camel_case(name
):
1353 if ch
in ['_', '-']:
1356 new_name
+= ch
.upper()
1359 new_name
+= ch
.lower()
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)
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():
1379 elif c_fun_str
[i
- 1].isdigit():
1382 return new_name
.lstrip('_').upper()
1385 def c_enum_const(type_name
, const_name
, prefix
=None):
1386 if prefix
is not None:
1388 return camel_to_upper(type_name
+ '_' + const_name
)
1390 c_name_trans
= string
.maketrans('.-', '__')
1393 # Map @name to a valid C identifier.
1394 # If @protect, avoid returning certain ticklish identifiers (like
1395 # C keywords) by prepending "q_".
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
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
):
1433 return name
.translate(c_name_trans
)
1435 eatspace
= '\033EATSPACE.'
1436 pointer_suffix
= ' *' + eatspace
1439 def genindent(count
):
1441 for _
in range(count
):
1448 def push_indent(indent_amount
=4):
1450 indent_level
+= indent_amount
1453 def pop_indent(indent_amount
=4):
1455 indent_level
-= indent_amount
1458 # Generate @code with @kwds interpolated.
1459 # Obey indent_level, and strip eatspace.
1460 def cgen(code
, **kwds
):
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
)
1468 return re
.sub(re
.escape(eatspace
) + ' *', '', raw
)
1471 def mcgen(code
, **kwds
):
1474 return cgen(code
, **kwds
)
1477 def guardname(filename
):
1478 return c_name(filename
, protect
=False).upper()
1481 def guardstart(name
):
1488 name
=guardname(name
))
1494 #endif /* %(name)s */
1497 name
=guardname(name
))
1500 def gen_enum_lookup(name
, values
, prefix
=None):
1503 const char *const %(c_name)s_lookup[] = {
1505 c_name
=c_name(name
))
1506 for value
in values
:
1507 index
= c_enum_const(name
, value
, prefix
)
1509 [%(index)s] = "%(value)s",
1511 index
=index
, value
=value
)
1513 max_index
= c_enum_const(name
, 'MAX', prefix
)
1515 [%(max_index)s] = NULL,
1518 max_index
=max_index
)
1522 def gen_enum(name
, values
, prefix
=None):
1523 # append automatically generated _MAX value
1524 enum_values
= values
+ ['MAX']
1528 typedef enum %(c_name)s {
1530 c_name
=c_name(name
))
1533 for value
in enum_values
:
1537 c_enum
=c_enum_const(name
, value
, prefix
),
1544 c_name
=c_name(name
))
1548 extern const char *const %(c_name)s_lookup[];
1550 c_name
=c_name(name
))
1554 def gen_params(arg_type
, extra
):
1557 assert not arg_type
.variants
1560 for memb
in arg_type
.members
:
1564 ret
+= 'bool has_%s, ' % c_name(memb
.name
)
1565 ret
+= '%s %s' % (memb
.type.c_type(is_param
=True), c_name(memb
.name
))
1571 def gen_err_check(label
='out', skiperr
=False):
1582 def gen_visit_fields(members
, prefix
='', need_cast
=False, skiperr
=False):
1589 for memb
in members
:
1592 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1594 prefix
=prefix
, c_name
=c_name(memb
.name
),
1595 name
=memb
.name
, errp
=errparg
)
1596 ret
+= gen_err_check(skiperr
=skiperr
)
1598 if (%(prefix)shas_%(c_name)s) {
1600 prefix
=prefix
, c_name
=c_name(memb
.name
))
1603 # Ugly: sometimes we need to cast away const
1604 if need_cast
and memb
.type.name
== 'str':
1610 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1612 c_type
=memb
.type.c_name(), prefix
=prefix
, cast
=cast
,
1613 c_name
=c_name(memb
.name
), name
=memb
.name
,
1615 ret
+= gen_err_check(skiperr
=skiperr
)
1626 # Common command line parsing
1630 def parse_command_line(extra_options
="", extra_long_options
=[]):
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
))
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()])
1657 elif o
in ("-o", "--output-dir"):
1658 output_dir
= a
+ "/"
1659 elif o
in ("-c", "--source"):
1661 elif o
in ("-h", "--header"):
1664 extra_opts
.append(oa
)
1666 if not do_c
and not do_h
:
1671 print >>sys
.stderr
, "%s: need exactly one argument" % sys
.argv
[0]
1675 return (fname
, output_dir
, do_c
, do_h
, prefix
, extra_opts
)
1678 # Generate output files with boilerplate
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
1690 os
.makedirs(output_dir
)
1692 if e
.errno
!= errno
.EEXIST
:
1695 def maybe_open(really
, name
, opt
):
1697 return open(name
, opt
)
1700 return StringIO
.StringIO()
1702 fdef
= maybe_open(do_c
, c_file
, 'w')
1703 fdecl
= maybe_open(do_h
, h_file
, 'w')
1705 fdef
.write(mcgen('''
1706 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1711 fdecl
.write(mcgen('''
1712 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1718 comment
=h_comment
, guard
=guard
))
1720 return (fdef
, fdecl
)
1723 def close_output(fdef
, fdecl
):