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',
60 # From qapi-schema-test:
71 # Parsing the schema into expressions
75 def error_path(parent
):
78 res
= ("In file included from %s:%d:\n" % (parent
['file'],
79 parent
['line'])) + res
80 parent
= parent
['parent']
84 class QAPISchemaError(Exception):
85 def __init__(self
, schema
, msg
):
86 Exception.__init
__(self
)
87 self
.fname
= schema
.fname
90 self
.line
= schema
.line
91 for ch
in schema
.src
[schema
.line_pos
:schema
.pos
]:
93 self
.col
= (self
.col
+ 7) % 8 + 1
96 self
.info
= schema
.incl_info
99 return error_path(self
.info
) + \
100 "%s:%d:%d: %s" % (self
.fname
, self
.line
, self
.col
, self
.msg
)
103 class QAPIExprError(Exception):
104 def __init__(self
, expr_info
, msg
):
105 Exception.__init
__(self
)
107 self
.info
= expr_info
111 return error_path(self
.info
['parent']) + \
112 "%s:%d: %s" % (self
.info
['file'], self
.info
['line'], self
.msg
)
115 class QAPISchemaParser(object):
117 def __init__(self
, fp
, previously_included
=[], incl_info
=None):
118 abs_fname
= os
.path
.abspath(fp
.name
)
121 previously_included
.append(abs_fname
)
122 self
.incl_info
= incl_info
124 if self
.src
== '' or self
.src
[-1] != '\n':
132 while self
.tok
is not None:
133 expr_info
= {'file': fname
, 'line': self
.line
,
134 'parent': self
.incl_info
}
135 expr
= self
.get_expr(False)
136 if isinstance(expr
, dict) and "include" in expr
:
138 raise QAPIExprError(expr_info
,
139 "Invalid 'include' directive")
140 include
= expr
["include"]
141 if not isinstance(include
, str):
142 raise QAPIExprError(expr_info
,
143 "Value of 'include' must be a string")
144 incl_abs_fname
= os
.path
.join(os
.path
.dirname(abs_fname
),
146 # catch inclusion cycle
149 if incl_abs_fname
== os
.path
.abspath(inf
['file']):
150 raise QAPIExprError(expr_info
, "Inclusion loop for %s"
153 # skip multiple include of the same file
154 if incl_abs_fname
in previously_included
:
157 fobj
= open(incl_abs_fname
, 'r')
159 raise QAPIExprError(expr_info
,
160 '%s: %s' % (e
.strerror
, include
))
161 exprs_include
= QAPISchemaParser(fobj
, previously_included
,
163 self
.exprs
.extend(exprs_include
.exprs
)
165 expr_elem
= {'expr': expr
,
167 self
.exprs
.append(expr_elem
)
171 self
.tok
= self
.src
[self
.cursor
]
172 self
.pos
= self
.cursor
177 self
.cursor
= self
.src
.find('\n', self
.cursor
)
178 elif self
.tok
in ['{', '}', ':', ',', '[', ']']:
180 elif self
.tok
== "'":
184 ch
= self
.src
[self
.cursor
]
187 raise QAPISchemaError(self
,
188 'Missing terminating "\'"')
202 for _
in range(0, 4):
203 ch
= self
.src
[self
.cursor
]
205 if ch
not in "0123456789abcdefABCDEF":
206 raise QAPISchemaError(self
,
207 '\\u escape needs 4 '
209 value
= (value
<< 4) + int(ch
, 16)
210 # If Python 2 and 3 didn't disagree so much on
211 # how to handle Unicode, then we could allow
212 # Unicode string defaults. But most of QAPI is
213 # ASCII-only, so we aren't losing much for now.
214 if not value
or value
> 0x7f:
215 raise QAPISchemaError(self
,
216 'For now, \\u escape '
217 'only supports non-zero '
218 'values up to \\u007f')
223 raise QAPISchemaError(self
,
224 "Unknown escape \\%s" % ch
)
233 elif self
.src
.startswith("true", self
.pos
):
237 elif self
.src
.startswith("false", self
.pos
):
241 elif self
.src
.startswith("null", self
.pos
):
245 elif self
.tok
== '\n':
246 if self
.cursor
== len(self
.src
):
250 self
.line_pos
= self
.cursor
251 elif not self
.tok
.isspace():
252 raise QAPISchemaError(self
, 'Stray "%s"' % self
.tok
)
254 def get_members(self
):
260 raise QAPISchemaError(self
, 'Expected string or "}"')
265 raise QAPISchemaError(self
, 'Expected ":"')
268 raise QAPISchemaError(self
, 'Duplicate key "%s"' % key
)
269 expr
[key
] = self
.get_expr(True)
274 raise QAPISchemaError(self
, 'Expected "," or "}"')
277 raise QAPISchemaError(self
, 'Expected string')
279 def get_values(self
):
284 if self
.tok
not in "{['tfn":
285 raise QAPISchemaError(self
, 'Expected "{", "[", "]", string, '
288 expr
.append(self
.get_expr(True))
293 raise QAPISchemaError(self
, 'Expected "," or "]"')
296 def get_expr(self
, nested
):
297 if self
.tok
!= '{' and not nested
:
298 raise QAPISchemaError(self
, 'Expected "{"')
301 expr
= self
.get_members()
302 elif self
.tok
== '[':
304 expr
= self
.get_values()
305 elif self
.tok
in "'tfn":
309 raise QAPISchemaError(self
, 'Expected "{", "[" or string')
313 # Semantic analysis of schema expressions
314 # TODO fold into QAPISchema
315 # TODO catching name collisions in generated code would be nice
319 def find_base_fields(base
):
320 base_struct_define
= find_struct(base
)
321 if not base_struct_define
:
323 return base_struct_define
['data']
326 # Return the qtype of an alternate branch, or None on error.
327 def find_alternate_member_qtype(qapi_type
):
328 if qapi_type
in builtin_types
:
329 return builtin_types
[qapi_type
]
330 elif find_struct(qapi_type
):
332 elif find_enum(qapi_type
):
333 return "QTYPE_QSTRING"
334 elif find_union(qapi_type
):
339 # Return the discriminator enum define if discriminator is specified as an
340 # enum type, otherwise return None.
341 def discriminator_find_enum_define(expr
):
342 base
= expr
.get('base')
343 discriminator
= expr
.get('discriminator')
345 if not (discriminator
and base
):
348 base_fields
= find_base_fields(base
)
352 discriminator_type
= base_fields
.get(discriminator
)
353 if not discriminator_type
:
356 return find_enum(discriminator_type
)
359 # FIXME should enforce "other than downstream extensions [...], all
360 # names should begin with a letter".
361 valid_name
= re
.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
364 def check_name(expr_info
, source
, name
, allow_optional
=False,
369 if not isinstance(name
, str):
370 raise QAPIExprError(expr_info
,
371 "%s requires a string name" % source
)
372 if name
.startswith('*'):
373 membername
= name
[1:]
374 if not allow_optional
:
375 raise QAPIExprError(expr_info
,
376 "%s does not allow optional name '%s'"
378 # Enum members can start with a digit, because the generated C
379 # code always prefixes it with the enum name
381 membername
= '_' + membername
382 if not valid_name
.match(membername
):
383 raise QAPIExprError(expr_info
,
384 "%s uses invalid name '%s'" % (source
, name
))
387 def add_name(name
, info
, meta
, implicit
=False):
389 check_name(info
, "'%s'" % meta
, name
)
390 # FIXME should reject names that differ only in '_' vs. '.'
391 # vs. '-', because they're liable to clash in generated C.
392 if name
in all_names
:
393 raise QAPIExprError(info
,
394 "%s '%s' is already defined"
395 % (all_names
[name
], name
))
396 if not implicit
and name
[-4:] == 'Kind':
397 raise QAPIExprError(info
,
398 "%s '%s' should not end in 'Kind'"
400 all_names
[name
] = meta
403 def add_struct(definition
, info
):
405 name
= definition
['struct']
406 add_name(name
, info
, 'struct')
407 struct_types
.append(definition
)
410 def find_struct(name
):
412 for struct
in struct_types
:
413 if struct
['struct'] == name
:
418 def add_union(definition
, info
):
420 name
= definition
['union']
421 add_name(name
, info
, 'union')
422 union_types
.append(definition
)
425 def find_union(name
):
427 for union
in union_types
:
428 if union
['union'] == name
:
433 def add_enum(name
, info
, enum_values
=None, implicit
=False):
435 add_name(name
, info
, 'enum', implicit
)
436 enum_types
.append({"enum_name": name
, "enum_values": enum_values
})
441 for enum
in enum_types
:
442 if enum
['enum_name'] == name
:
448 return find_enum(name
) is not None
451 def check_type(expr_info
, source
, value
, allow_array
=False,
452 allow_dict
=False, allow_optional
=False,
459 # Check if array type for value is okay
460 if isinstance(value
, list):
462 raise QAPIExprError(expr_info
,
463 "%s cannot be an array" % source
)
464 if len(value
) != 1 or not isinstance(value
[0], str):
465 raise QAPIExprError(expr_info
,
466 "%s: array type must contain single type name"
470 # Check if type name for value is okay
471 if isinstance(value
, str):
472 if value
not in all_names
:
473 raise QAPIExprError(expr_info
,
474 "%s uses unknown type '%s'"
476 if not all_names
[value
] in allow_metas
:
477 raise QAPIExprError(expr_info
,
478 "%s cannot use %s type '%s'"
479 % (source
, all_names
[value
], value
))
483 raise QAPIExprError(expr_info
,
484 "%s should be a type name" % source
)
486 if not isinstance(value
, OrderedDict
):
487 raise QAPIExprError(expr_info
,
488 "%s should be a dictionary or type name" % source
)
490 # value is a dictionary, check that each member is okay
491 for (key
, arg
) in value
.items():
492 check_name(expr_info
, "Member of %s" % source
, key
,
493 allow_optional
=allow_optional
)
494 # Todo: allow dictionaries to represent default values of
495 # an optional argument.
496 check_type(expr_info
, "Member '%s' of %s" % (key
, source
), arg
,
498 allow_metas
=['built-in', 'union', 'alternate', 'struct',
502 def check_member_clash(expr_info
, base_name
, data
, source
=""):
503 base
= find_struct(base_name
)
505 base_members
= base
['data']
506 for key
in data
.keys():
507 if key
.startswith('*'):
509 if key
in base_members
or "*" + key
in base_members
:
510 raise QAPIExprError(expr_info
,
511 "Member name '%s'%s clashes with base '%s'"
512 % (key
, source
, base_name
))
514 check_member_clash(expr_info
, base
['base'], data
, source
)
517 def check_command(expr
, expr_info
):
518 name
= expr
['command']
520 check_type(expr_info
, "'data' for command '%s'" % name
,
521 expr
.get('data'), allow_dict
=True, allow_optional
=True,
522 allow_metas
=['struct'])
523 returns_meta
= ['union', 'struct']
524 if name
in returns_whitelist
:
525 returns_meta
+= ['built-in', 'alternate', 'enum']
526 check_type(expr_info
, "'returns' for command '%s'" % name
,
527 expr
.get('returns'), allow_array
=True,
528 allow_optional
=True, allow_metas
=returns_meta
)
531 def check_event(expr
, expr_info
):
535 if name
.upper() == 'MAX':
536 raise QAPIExprError(expr_info
, "Event name 'MAX' cannot be created")
538 check_type(expr_info
, "'data' for event '%s'" % name
,
539 expr
.get('data'), allow_dict
=True, allow_optional
=True,
540 allow_metas
=['struct'])
543 def check_union(expr
, expr_info
):
545 base
= expr
.get('base')
546 discriminator
= expr
.get('discriminator')
547 members
= expr
['data']
548 values
= {'MAX': '(automatic)', 'KIND': '(automatic)'}
550 # Two types of unions, determined by discriminator.
552 # With no discriminator it is a simple union.
553 if discriminator
is None:
555 allow_metas
= ['built-in', 'union', 'alternate', 'struct', 'enum']
557 raise QAPIExprError(expr_info
,
558 "Simple union '%s' must not have a base"
561 # Else, it's a flat union.
563 # The object must have a string member 'base'.
564 check_type(expr_info
, "'base' for union '%s'" % name
,
565 base
, allow_metas
=['struct'])
567 raise QAPIExprError(expr_info
,
568 "Flat union '%s' must have a base"
570 base_fields
= find_base_fields(base
)
573 # The value of member 'discriminator' must name a non-optional
574 # member of the base struct.
575 check_name(expr_info
, "Discriminator of flat union '%s'" % name
,
577 discriminator_type
= base_fields
.get(discriminator
)
578 if not discriminator_type
:
579 raise QAPIExprError(expr_info
,
580 "Discriminator '%s' is not a member of base "
582 % (discriminator
, base
))
583 enum_define
= find_enum(discriminator_type
)
584 allow_metas
= ['struct']
585 # Do not allow string discriminator
587 raise QAPIExprError(expr_info
,
588 "Discriminator '%s' must be of enumeration "
589 "type" % discriminator
)
592 for (key
, value
) in members
.items():
593 check_name(expr_info
, "Member of union '%s'" % name
, key
)
595 # Each value must name a known type; furthermore, in flat unions,
596 # branches must be a struct with no overlapping member names
597 check_type(expr_info
, "Member '%s' of union '%s'" % (key
, name
),
598 value
, allow_array
=not base
, allow_metas
=allow_metas
)
600 branch_struct
= find_struct(value
)
602 check_member_clash(expr_info
, base
, branch_struct
['data'],
603 " of branch '%s'" % key
)
605 # If the discriminator names an enum type, then all members
606 # of 'data' must also be members of the enum type, which in turn
607 # must not collide with the discriminator name.
609 if key
not in enum_define
['enum_values']:
610 raise QAPIExprError(expr_info
,
611 "Discriminator value '%s' is not found in "
613 (key
, enum_define
["enum_name"]))
614 if discriminator
in enum_define
['enum_values']:
615 raise QAPIExprError(expr_info
,
616 "Discriminator name '%s' collides with "
617 "enum value in '%s'" %
618 (discriminator
, enum_define
["enum_name"]))
620 # Otherwise, check for conflicts in the generated enum
622 c_key
= camel_to_upper(key
)
624 raise QAPIExprError(expr_info
,
625 "Union '%s' member '%s' clashes with '%s'"
626 % (name
, key
, values
[c_key
]))
630 def check_alternate(expr
, expr_info
):
631 name
= expr
['alternate']
632 members
= expr
['data']
633 values
= {'MAX': '(automatic)'}
637 for (key
, value
) in members
.items():
638 check_name(expr_info
, "Member of alternate '%s'" % name
, key
)
640 # Check for conflicts in the generated enum
641 c_key
= camel_to_upper(key
)
643 raise QAPIExprError(expr_info
,
644 "Alternate '%s' member '%s' clashes with '%s'"
645 % (name
, key
, values
[c_key
]))
648 # Ensure alternates have no type conflicts.
649 check_type(expr_info
, "Member '%s' of alternate '%s'" % (key
, name
),
651 allow_metas
=['built-in', 'union', 'struct', 'enum'])
652 qtype
= find_alternate_member_qtype(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')
666 values
= {'MAX': '(automatic)'}
668 if not isinstance(members
, list):
669 raise QAPIExprError(expr_info
,
670 "Enum '%s' requires an array for 'data'" % name
)
671 if prefix
is not None and not isinstance(prefix
, str):
672 raise QAPIExprError(expr_info
,
673 "Enum '%s' requires a string for 'prefix'" % name
)
674 for member
in members
:
675 check_name(expr_info
, "Member of enum '%s'" % name
, member
,
677 key
= camel_to_upper(member
)
679 raise QAPIExprError(expr_info
,
680 "Enum '%s' member '%s' clashes with '%s'"
681 % (name
, member
, values
[key
]))
685 def check_struct(expr
, expr_info
):
686 name
= expr
['struct']
687 members
= expr
['data']
689 check_type(expr_info
, "'data' for struct '%s'" % name
, members
,
690 allow_dict
=True, allow_optional
=True)
691 check_type(expr_info
, "'base' for struct '%s'" % name
, expr
.get('base'),
692 allow_metas
=['struct'])
694 check_member_clash(expr_info
, expr
['base'], expr
['data'])
697 def check_keys(expr_elem
, meta
, required
, optional
=[]):
698 expr
= expr_elem
['expr']
699 info
= expr_elem
['info']
701 if not isinstance(name
, str):
702 raise QAPIExprError(info
,
703 "'%s' key must have a string value" % meta
)
704 required
= required
+ [meta
]
705 for (key
, value
) in expr
.items():
706 if key
not in required
and key
not in optional
:
707 raise QAPIExprError(info
,
708 "Unknown key '%s' in %s '%s'"
710 if (key
== 'gen' or key
== 'success-response') and value
is not False:
711 raise QAPIExprError(info
,
712 "'%s' of %s '%s' should only use false value"
716 raise QAPIExprError(info
,
717 "Key '%s' is missing from %s '%s'"
721 def check_exprs(exprs
):
724 # Learn the types and check for valid expression keys
725 for builtin
in builtin_types
.keys():
726 all_names
[builtin
] = 'built-in'
727 for expr_elem
in exprs
:
728 expr
= expr_elem
['expr']
729 info
= expr_elem
['info']
731 check_keys(expr_elem
, 'enum', ['data'], ['prefix'])
732 add_enum(expr
['enum'], info
, expr
['data'])
733 elif 'union' in expr
:
734 check_keys(expr_elem
, 'union', ['data'],
735 ['base', 'discriminator'])
736 add_union(expr
, info
)
737 elif 'alternate' in expr
:
738 check_keys(expr_elem
, 'alternate', ['data'])
739 add_name(expr
['alternate'], info
, 'alternate')
740 elif 'struct' in expr
:
741 check_keys(expr_elem
, 'struct', ['data'], ['base'])
742 add_struct(expr
, info
)
743 elif 'command' in expr
:
744 check_keys(expr_elem
, 'command', [],
745 ['data', 'returns', 'gen', 'success-response'])
746 add_name(expr
['command'], info
, 'command')
747 elif 'event' in expr
:
748 check_keys(expr_elem
, 'event', [], ['data'])
749 add_name(expr
['event'], info
, 'event')
751 raise QAPIExprError(expr_elem
['info'],
752 "Expression is missing metatype")
754 # Try again for hidden UnionKind enum
755 for expr_elem
in exprs
:
756 expr
= expr_elem
['expr']
758 if not discriminator_find_enum_define(expr
):
759 add_enum('%sKind' % expr
['union'], expr_elem
['info'],
761 elif 'alternate' in expr
:
762 add_enum('%sKind' % expr
['alternate'], expr_elem
['info'],
765 # Validate that exprs make sense
766 for expr_elem
in exprs
:
767 expr
= expr_elem
['expr']
768 info
= expr_elem
['info']
771 check_enum(expr
, info
)
772 elif 'union' in expr
:
773 check_union(expr
, info
)
774 elif 'alternate' in expr
:
775 check_alternate(expr
, info
)
776 elif 'struct' in expr
:
777 check_struct(expr
, info
)
778 elif 'command' in expr
:
779 check_command(expr
, info
)
780 elif 'event' in expr
:
781 check_event(expr
, info
)
783 assert False, 'unexpected meta type'
789 # Schema compiler frontend
792 class QAPISchemaEntity(object):
793 def __init__(self
, name
, info
):
794 assert isinstance(name
, str)
799 return c_name(self
.name
)
801 def check(self
, schema
):
804 def visit(self
, visitor
):
808 class QAPISchemaVisitor(object):
809 def visit_begin(self
, schema
):
815 def visit_needed(self
, entity
):
816 # Default to visiting everything
819 def visit_builtin_type(self
, name
, info
, json_type
):
822 def visit_enum_type(self
, name
, info
, values
, prefix
):
825 def visit_array_type(self
, name
, info
, element_type
):
828 def visit_object_type(self
, name
, info
, base
, members
, variants
):
831 def visit_object_type_flat(self
, name
, info
, members
, variants
):
834 def visit_alternate_type(self
, name
, info
, variants
):
837 def visit_command(self
, name
, info
, arg_type
, ret_type
,
838 gen
, success_response
):
841 def visit_event(self
, name
, info
, arg_type
):
845 class QAPISchemaType(QAPISchemaEntity
):
846 def c_type(self
, is_param
=False):
847 return c_name(self
.name
) + pointer_suffix
855 def alternate_qtype(self
):
857 'string': 'QTYPE_QSTRING',
858 'number': 'QTYPE_QFLOAT',
860 'boolean': 'QTYPE_QBOOL',
861 'object': 'QTYPE_QDICT'
863 return json2qtype
.get(self
.json_type())
866 class QAPISchemaBuiltinType(QAPISchemaType
):
867 def __init__(self
, name
, json_type
, c_type
, c_null
):
868 QAPISchemaType
.__init
__(self
, name
, None)
869 assert not c_type
or isinstance(c_type
, str)
870 assert json_type
in ('string', 'number', 'int', 'boolean', 'null',
872 self
._json
_type
_name
= json_type
873 self
._c
_type
_name
= c_type
874 self
._c
_null
_val
= c_null
879 def c_type(self
, is_param
=False):
880 if is_param
and self
.name
== 'str':
881 return 'const ' + self
._c
_type
_name
882 return self
._c
_type
_name
885 return self
._c
_null
_val
888 return self
._json
_type
_name
890 def visit(self
, visitor
):
891 visitor
.visit_builtin_type(self
.name
, self
.info
, self
.json_type())
894 class QAPISchemaEnumType(QAPISchemaType
):
895 def __init__(self
, name
, info
, values
, prefix
):
896 QAPISchemaType
.__init
__(self
, name
, info
)
898 assert isinstance(v
, str)
899 assert prefix
is None or isinstance(prefix
, str)
903 def check(self
, schema
):
904 assert len(set(self
.values
)) == len(self
.values
)
906 def c_type(self
, is_param
=False):
907 return c_name(self
.name
)
910 return c_enum_const(self
.name
, (self
.values
+ ['MAX'])[0],
916 def visit(self
, visitor
):
917 visitor
.visit_enum_type(self
.name
, self
.info
,
918 self
.values
, self
.prefix
)
921 class QAPISchemaArrayType(QAPISchemaType
):
922 def __init__(self
, name
, info
, element_type
):
923 QAPISchemaType
.__init
__(self
, name
, info
)
924 assert isinstance(element_type
, str)
925 self
._element
_type
_name
= element_type
926 self
.element_type
= None
928 def check(self
, schema
):
929 self
.element_type
= schema
.lookup_type(self
._element
_type
_name
)
930 assert self
.element_type
935 def visit(self
, visitor
):
936 visitor
.visit_array_type(self
.name
, self
.info
, self
.element_type
)
939 class QAPISchemaObjectType(QAPISchemaType
):
940 def __init__(self
, name
, info
, base
, local_members
, variants
):
941 QAPISchemaType
.__init
__(self
, name
, info
)
942 assert base
is None or isinstance(base
, str)
943 for m
in local_members
:
944 assert isinstance(m
, QAPISchemaObjectTypeMember
)
945 assert (variants
is None or
946 isinstance(variants
, QAPISchemaObjectTypeVariants
))
947 self
._base
_name
= base
949 self
.local_members
= local_members
950 self
.variants
= variants
953 def check(self
, schema
):
954 assert self
.members
is not False # not running in cycles
957 self
.members
= False # mark as being checked
959 self
.base
= schema
.lookup_type(self
._base
_name
)
960 assert isinstance(self
.base
, QAPISchemaObjectType
)
961 assert not self
.base
.variants
# not implemented
962 self
.base
.check(schema
)
963 members
= list(self
.base
.members
)
968 assert c_name(m
.name
) not in seen
970 for m
in self
.local_members
:
971 m
.check(schema
, members
, seen
)
973 self
.variants
.check(schema
, members
, seen
)
974 self
.members
= members
978 return QAPISchemaType
.c_name(self
)
980 def c_type(self
, is_param
=False):
982 return QAPISchemaType
.c_type(self
)
987 def visit(self
, visitor
):
988 visitor
.visit_object_type(self
.name
, self
.info
,
989 self
.base
, self
.local_members
, self
.variants
)
990 visitor
.visit_object_type_flat(self
.name
, self
.info
,
991 self
.members
, self
.variants
)
994 class QAPISchemaObjectTypeMember(object):
995 def __init__(self
, name
, typ
, optional
):
996 assert isinstance(name
, str)
997 assert isinstance(typ
, str)
998 assert isinstance(optional
, bool)
1000 self
._type
_name
= typ
1002 self
.optional
= optional
1004 def check(self
, schema
, all_members
, seen
):
1005 assert self
.name
not in seen
1006 self
.type = schema
.lookup_type(self
._type
_name
)
1008 all_members
.append(self
)
1009 seen
[self
.name
] = self
1012 class QAPISchemaObjectTypeVariants(object):
1013 def __init__(self
, tag_name
, tag_enum
, variants
):
1014 assert tag_name
is None or isinstance(tag_name
, str)
1015 assert tag_enum
is None or isinstance(tag_enum
, str)
1017 assert isinstance(v
, QAPISchemaObjectTypeVariant
)
1018 self
.tag_name
= tag_name
1021 self
.tag_member
= None
1023 self
.tag_member
= QAPISchemaObjectTypeMember('type', tag_enum
,
1025 self
.variants
= variants
1027 def check(self
, schema
, members
, seen
):
1029 self
.tag_member
= seen
[self
.tag_name
]
1031 self
.tag_member
.check(schema
, members
, seen
)
1032 assert isinstance(self
.tag_member
.type, QAPISchemaEnumType
)
1033 for v
in self
.variants
:
1035 v
.check(schema
, self
.tag_member
.type, vseen
)
1038 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember
):
1039 def __init__(self
, name
, typ
):
1040 QAPISchemaObjectTypeMember
.__init
__(self
, name
, typ
, False)
1042 def check(self
, schema
, tag_type
, seen
):
1043 QAPISchemaObjectTypeMember
.check(self
, schema
, [], seen
)
1044 assert self
.name
in tag_type
.values
1046 # This function exists to support ugly simple union special cases
1047 # TODO get rid of them, and drop the function
1048 def simple_union_type(self
):
1049 if isinstance(self
.type, QAPISchemaObjectType
) and not self
.type.info
:
1050 assert len(self
.type.members
) == 1
1051 assert not self
.type.variants
1052 return self
.type.members
[0].type
1056 class QAPISchemaAlternateType(QAPISchemaType
):
1057 def __init__(self
, name
, info
, variants
):
1058 QAPISchemaType
.__init
__(self
, name
, info
)
1059 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
1060 assert not variants
.tag_name
1061 self
.variants
= variants
1063 def check(self
, schema
):
1064 self
.variants
.check(schema
, [], {})
1066 def json_type(self
):
1069 def visit(self
, visitor
):
1070 visitor
.visit_alternate_type(self
.name
, self
.info
, self
.variants
)
1073 class QAPISchemaCommand(QAPISchemaEntity
):
1074 def __init__(self
, name
, info
, arg_type
, ret_type
, gen
, success_response
):
1075 QAPISchemaEntity
.__init
__(self
, name
, info
)
1076 assert not arg_type
or isinstance(arg_type
, str)
1077 assert not ret_type
or isinstance(ret_type
, str)
1078 self
._arg
_type
_name
= arg_type
1079 self
.arg_type
= None
1080 self
._ret
_type
_name
= ret_type
1081 self
.ret_type
= None
1083 self
.success_response
= success_response
1085 def check(self
, schema
):
1086 if self
._arg
_type
_name
:
1087 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1088 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1089 assert not self
.arg_type
.variants
# not implemented
1090 if self
._ret
_type
_name
:
1091 self
.ret_type
= schema
.lookup_type(self
._ret
_type
_name
)
1092 assert isinstance(self
.ret_type
, QAPISchemaType
)
1094 def visit(self
, visitor
):
1095 visitor
.visit_command(self
.name
, self
.info
,
1096 self
.arg_type
, self
.ret_type
,
1097 self
.gen
, self
.success_response
)
1100 class QAPISchemaEvent(QAPISchemaEntity
):
1101 def __init__(self
, name
, info
, arg_type
):
1102 QAPISchemaEntity
.__init
__(self
, name
, info
)
1103 assert not arg_type
or isinstance(arg_type
, str)
1104 self
._arg
_type
_name
= arg_type
1105 self
.arg_type
= None
1107 def check(self
, schema
):
1108 if self
._arg
_type
_name
:
1109 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1110 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1111 assert not self
.arg_type
.variants
# not implemented
1113 def visit(self
, visitor
):
1114 visitor
.visit_event(self
.name
, self
.info
, self
.arg_type
)
1117 class QAPISchema(object):
1118 def __init__(self
, fname
):
1120 self
.exprs
= check_exprs(QAPISchemaParser(open(fname
, "r")).exprs
)
1121 self
._entity
_dict
= {}
1122 self
._def
_predefineds
()
1125 except (QAPISchemaError
, QAPIExprError
), err
:
1126 print >>sys
.stderr
, err
1129 def _def_entity(self
, ent
):
1130 assert ent
.name
not in self
._entity
_dict
1131 self
._entity
_dict
[ent
.name
] = ent
1133 def lookup_entity(self
, name
, typ
=None):
1134 ent
= self
._entity
_dict
.get(name
)
1135 if typ
and not isinstance(ent
, typ
):
1139 def lookup_type(self
, name
):
1140 return self
.lookup_entity(name
, QAPISchemaType
)
1142 def _def_builtin_type(self
, name
, json_type
, c_type
, c_null
):
1143 self
._def
_entity
(QAPISchemaBuiltinType(name
, json_type
,
1145 self
._make
_array
_type
(name
) # TODO really needed?
1147 def _def_predefineds(self
):
1148 for t
in [('str', 'string', 'char' + pointer_suffix
, 'NULL'),
1149 ('number', 'number', 'double', '0'),
1150 ('int', 'int', 'int64_t', '0'),
1151 ('int8', 'int', 'int8_t', '0'),
1152 ('int16', 'int', 'int16_t', '0'),
1153 ('int32', 'int', 'int32_t', '0'),
1154 ('int64', 'int', 'int64_t', '0'),
1155 ('uint8', 'int', 'uint8_t', '0'),
1156 ('uint16', 'int', 'uint16_t', '0'),
1157 ('uint32', 'int', 'uint32_t', '0'),
1158 ('uint64', 'int', 'uint64_t', '0'),
1159 ('size', 'int', 'uint64_t', '0'),
1160 ('bool', 'boolean', 'bool', 'false'),
1161 ('any', 'value', 'QObject' + pointer_suffix
, 'NULL')]:
1162 self
._def
_builtin
_type
(*t
)
1163 self
.the_empty_object_type
= QAPISchemaObjectType(':empty', None, None,
1165 self
._def
_entity
(self
.the_empty_object_type
)
1167 def _make_implicit_enum_type(self
, name
, values
):
1168 name
= name
+ 'Kind'
1169 self
._def
_entity
(QAPISchemaEnumType(name
, None, values
, None))
1172 def _make_array_type(self
, element_type
):
1173 name
= element_type
+ 'List'
1174 if not self
.lookup_type(name
):
1175 self
._def
_entity
(QAPISchemaArrayType(name
, None, element_type
))
1178 def _make_implicit_object_type(self
, name
, role
, members
):
1181 name
= ':obj-%s-%s' % (name
, role
)
1182 if not self
.lookup_entity(name
, QAPISchemaObjectType
):
1183 self
._def
_entity
(QAPISchemaObjectType(name
, None, None,
1187 def _def_enum_type(self
, expr
, info
):
1190 prefix
= expr
.get('prefix')
1191 self
._def
_entity
(QAPISchemaEnumType(name
, info
, data
, prefix
))
1192 self
._make
_array
_type
(name
) # TODO really needed?
1194 def _make_member(self
, name
, typ
):
1196 if name
.startswith('*'):
1199 if isinstance(typ
, list):
1200 assert len(typ
) == 1
1201 typ
= self
._make
_array
_type
(typ
[0])
1202 return QAPISchemaObjectTypeMember(name
, typ
, optional
)
1204 def _make_members(self
, data
):
1205 return [self
._make
_member
(key
, value
)
1206 for (key
, value
) in data
.iteritems()]
1208 def _def_struct_type(self
, expr
, info
):
1209 name
= expr
['struct']
1210 base
= expr
.get('base')
1212 self
._def
_entity
(QAPISchemaObjectType(name
, info
, base
,
1213 self
._make
_members
(data
),
1215 self
._make
_array
_type
(name
) # TODO really needed?
1217 def _make_variant(self
, case
, typ
):
1218 return QAPISchemaObjectTypeVariant(case
, typ
)
1220 def _make_simple_variant(self
, case
, typ
):
1221 if isinstance(typ
, list):
1222 assert len(typ
) == 1
1223 typ
= self
._make
_array
_type
(typ
[0])
1224 typ
= self
._make
_implicit
_object
_type
(typ
, 'wrapper',
1225 [self
._make
_member
('data', typ
)])
1226 return QAPISchemaObjectTypeVariant(case
, typ
)
1228 def _make_tag_enum(self
, type_name
, variants
):
1229 return self
._make
_implicit
_enum
_type
(type_name
,
1230 [v
.name
for v
in variants
])
1232 def _def_union_type(self
, expr
, info
):
1233 name
= expr
['union']
1235 base
= expr
.get('base')
1236 tag_name
= expr
.get('discriminator')
1239 variants
= [self
._make
_variant
(key
, value
)
1240 for (key
, value
) in data
.iteritems()]
1242 variants
= [self
._make
_simple
_variant
(key
, value
)
1243 for (key
, value
) in data
.iteritems()]
1244 tag_enum
= self
._make
_tag
_enum
(name
, variants
)
1246 QAPISchemaObjectType(name
, info
, base
,
1247 self
._make
_members
(OrderedDict()),
1248 QAPISchemaObjectTypeVariants(tag_name
,
1251 self
._make
_array
_type
(name
) # TODO really needed?
1253 def _def_alternate_type(self
, expr
, info
):
1254 name
= expr
['alternate']
1256 variants
= [self
._make
_variant
(key
, value
)
1257 for (key
, value
) in data
.iteritems()]
1258 tag_enum
= self
._make
_tag
_enum
(name
, variants
)
1260 QAPISchemaAlternateType(name
, info
,
1261 QAPISchemaObjectTypeVariants(None,
1264 self
._make
_array
_type
(name
) # TODO really needed?
1266 def _def_command(self
, expr
, info
):
1267 name
= expr
['command']
1268 data
= expr
.get('data')
1269 rets
= expr
.get('returns')
1270 gen
= expr
.get('gen', True)
1271 success_response
= expr
.get('success-response', True)
1272 if isinstance(data
, OrderedDict
):
1273 data
= self
._make
_implicit
_object
_type
(name
, 'arg',
1274 self
._make
_members
(data
))
1275 if isinstance(rets
, list):
1276 assert len(rets
) == 1
1277 rets
= self
._make
_array
_type
(rets
[0])
1278 self
._def
_entity
(QAPISchemaCommand(name
, info
, data
, rets
, gen
,
1281 def _def_event(self
, expr
, info
):
1282 name
= expr
['event']
1283 data
= expr
.get('data')
1284 if isinstance(data
, OrderedDict
):
1285 data
= self
._make
_implicit
_object
_type
(name
, 'arg',
1286 self
._make
_members
(data
))
1287 self
._def
_entity
(QAPISchemaEvent(name
, info
, data
))
1289 def _def_exprs(self
):
1290 for expr_elem
in self
.exprs
:
1291 expr
= expr_elem
['expr']
1292 info
= expr_elem
['info']
1294 self
._def
_enum
_type
(expr
, info
)
1295 elif 'struct' in expr
:
1296 self
._def
_struct
_type
(expr
, info
)
1297 elif 'union' in expr
:
1298 self
._def
_union
_type
(expr
, info
)
1299 elif 'alternate' in expr
:
1300 self
._def
_alternate
_type
(expr
, info
)
1301 elif 'command' in expr
:
1302 self
._def
_command
(expr
, info
)
1303 elif 'event' in expr
:
1304 self
._def
_event
(expr
, info
)
1309 for ent
in self
._entity
_dict
.values():
1312 def visit(self
, visitor
):
1313 visitor
.visit_begin(self
)
1314 for (name
, entity
) in sorted(self
._entity
_dict
.items()):
1315 if visitor
.visit_needed(entity
):
1316 entity
.visit(visitor
)
1321 # Code generation helpers
1324 def camel_case(name
):
1328 if ch
in ['_', '-']:
1331 new_name
+= ch
.upper()
1334 new_name
+= ch
.lower()
1338 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1339 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1340 # ENUM24_Name -> ENUM24_NAME
1341 def camel_to_upper(value
):
1342 c_fun_str
= c_name(value
, False)
1350 # When c is upper and no "_" appears before, do more checks
1351 if c
.isupper() and (i
> 0) and c_fun_str
[i
- 1] != "_":
1352 if i
< l
- 1 and c_fun_str
[i
+ 1].islower():
1354 elif c_fun_str
[i
- 1].isdigit():
1357 return new_name
.lstrip('_').upper()
1360 def c_enum_const(type_name
, const_name
, prefix
=None):
1361 if prefix
is not None:
1363 return camel_to_upper(type_name
+ '_' + const_name
)
1365 c_name_trans
= string
.maketrans('.-', '__')
1368 # Map @name to a valid C identifier.
1369 # If @protect, avoid returning certain ticklish identifiers (like
1370 # C keywords) by prepending "q_".
1372 # Used for converting 'name' from a 'name':'type' qapi definition
1373 # into a generated struct member, as well as converting type names
1374 # into substrings of a generated C function name.
1375 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1376 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1377 def c_name(name
, protect
=True):
1378 # ANSI X3J11/88-090, 3.1.1
1379 c89_words
= set(['auto', 'break', 'case', 'char', 'const', 'continue',
1380 'default', 'do', 'double', 'else', 'enum', 'extern',
1381 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1382 'return', 'short', 'signed', 'sizeof', 'static',
1383 'struct', 'switch', 'typedef', 'union', 'unsigned',
1384 'void', 'volatile', 'while'])
1385 # ISO/IEC 9899:1999, 6.4.1
1386 c99_words
= set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1387 # ISO/IEC 9899:2011, 6.4.1
1388 c11_words
= set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1389 '_Noreturn', '_Static_assert', '_Thread_local'])
1390 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1392 gcc_words
= set(['asm', 'typeof'])
1393 # C++ ISO/IEC 14882:2003 2.11
1394 cpp_words
= set(['bool', 'catch', 'class', 'const_cast', 'delete',
1395 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1396 'namespace', 'new', 'operator', 'private', 'protected',
1397 'public', 'reinterpret_cast', 'static_cast', 'template',
1398 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1399 'using', 'virtual', 'wchar_t',
1400 # alternative representations
1401 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1402 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1403 # namespace pollution:
1404 polluted_words
= set(['unix', 'errno'])
1405 if protect
and (name
in c89_words | c99_words | c11_words | gcc_words
1406 | cpp_words | polluted_words
):
1408 return name
.translate(c_name_trans
)
1410 eatspace
= '\033EATSPACE.'
1411 pointer_suffix
= ' *' + eatspace
1414 def genindent(count
):
1416 for _
in range(count
):
1423 def push_indent(indent_amount
=4):
1425 indent_level
+= indent_amount
1428 def pop_indent(indent_amount
=4):
1430 indent_level
-= indent_amount
1433 # Generate @code with @kwds interpolated.
1434 # Obey indent_level, and strip eatspace.
1435 def cgen(code
, **kwds
):
1438 indent
= genindent(indent_level
)
1439 # re.subn() lacks flags support before Python 2.7, use re.compile()
1440 raw
= re
.subn(re
.compile("^.", re
.MULTILINE
),
1441 indent
+ r
'\g<0>', raw
)
1443 return re
.sub(re
.escape(eatspace
) + ' *', '', raw
)
1446 def mcgen(code
, **kwds
):
1449 return cgen(code
, **kwds
)
1452 def guardname(filename
):
1453 return c_name(filename
, protect
=False).upper()
1456 def guardstart(name
):
1463 name
=guardname(name
))
1469 #endif /* %(name)s */
1472 name
=guardname(name
))
1475 def gen_enum_lookup(name
, values
, prefix
=None):
1478 const char *const %(c_name)s_lookup[] = {
1480 c_name
=c_name(name
))
1481 for value
in values
:
1482 index
= c_enum_const(name
, value
, prefix
)
1484 [%(index)s] = "%(value)s",
1486 index
=index
, value
=value
)
1488 max_index
= c_enum_const(name
, 'MAX', prefix
)
1490 [%(max_index)s] = NULL,
1493 max_index
=max_index
)
1497 def gen_enum(name
, values
, prefix
=None):
1498 # append automatically generated _MAX value
1499 enum_values
= values
+ ['MAX']
1503 typedef enum %(c_name)s {
1505 c_name
=c_name(name
))
1508 for value
in enum_values
:
1512 c_enum
=c_enum_const(name
, value
, prefix
),
1519 c_name
=c_name(name
))
1523 extern const char *const %(c_name)s_lookup[];
1525 c_name
=c_name(name
))
1529 def gen_params(arg_type
, extra
):
1532 assert not arg_type
.variants
1535 for memb
in arg_type
.members
:
1539 ret
+= 'bool has_%s, ' % c_name(memb
.name
)
1540 ret
+= '%s %s' % (memb
.type.c_type(is_param
=True), c_name(memb
.name
))
1546 def gen_err_check(label
='out', skiperr
=False):
1557 def gen_visit_fields(members
, prefix
='', need_cast
=False, skiperr
=False):
1564 for memb
in members
:
1567 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1569 prefix
=prefix
, c_name
=c_name(memb
.name
),
1570 name
=memb
.name
, errp
=errparg
)
1571 ret
+= gen_err_check(skiperr
=skiperr
)
1573 if (%(prefix)shas_%(c_name)s) {
1575 prefix
=prefix
, c_name
=c_name(memb
.name
))
1578 # Ugly: sometimes we need to cast away const
1579 if need_cast
and memb
.type.name
== 'str':
1585 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1587 c_type
=memb
.type.c_name(), prefix
=prefix
, cast
=cast
,
1588 c_name
=c_name(memb
.name
), name
=memb
.name
,
1590 ret
+= gen_err_check(skiperr
=skiperr
)
1601 # Common command line parsing
1605 def parse_command_line(extra_options
="", extra_long_options
=[]):
1608 opts
, args
= getopt
.gnu_getopt(sys
.argv
[1:],
1609 "chp:o:" + extra_options
,
1610 ["source", "header", "prefix=",
1611 "output-dir="] + extra_long_options
)
1612 except getopt
.GetoptError
, err
:
1613 print >>sys
.stderr
, "%s: %s" % (sys
.argv
[0], str(err
))
1624 if o
in ("-p", "--prefix"):
1625 match
= re
.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a
)
1626 if match
.end() != len(a
):
1627 print >>sys
.stderr
, \
1628 "%s: 'funny character '%s' in argument of --prefix" \
1629 % (sys
.argv
[0], a
[match
.end()])
1632 elif o
in ("-o", "--output-dir"):
1633 output_dir
= a
+ "/"
1634 elif o
in ("-c", "--source"):
1636 elif o
in ("-h", "--header"):
1639 extra_opts
.append(oa
)
1641 if not do_c
and not do_h
:
1646 print >>sys
.stderr
, "%s: need exactly one argument" % sys
.argv
[0]
1650 return (fname
, output_dir
, do_c
, do_h
, prefix
, extra_opts
)
1653 # Generate output files with boilerplate
1657 def open_output(output_dir
, do_c
, do_h
, prefix
, c_file
, h_file
,
1658 c_comment
, h_comment
):
1659 guard
= guardname(prefix
+ h_file
)
1660 c_file
= output_dir
+ prefix
+ c_file
1661 h_file
= output_dir
+ prefix
+ h_file
1665 os
.makedirs(output_dir
)
1667 if e
.errno
!= errno
.EEXIST
:
1670 def maybe_open(really
, name
, opt
):
1672 return open(name
, opt
)
1675 return StringIO
.StringIO()
1677 fdef
= maybe_open(do_c
, c_file
, 'w')
1678 fdecl
= maybe_open(do_h
, h_file
, 'w')
1680 fdef
.write(mcgen('''
1681 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1686 fdecl
.write(mcgen('''
1687 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1693 comment
=h_comment
, guard
=guard
))
1695 return (fdef
, fdecl
)
1698 def close_output(fdef
, fdecl
):