qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

qapi: add a dictionary form for TYPE

Wherever a struct/union/alternate/command/event member with NAME: TYPE
form is accepted, desugar it to a NAME: { 'type': TYPE } form.

This will allow to add new member details, such as 'if' in the
following patch to introduce conditionals, or 'default' for default
values etc.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20181213123724.4866-13-marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>

authored by

Marc-André Lureau and committed by
Markus Armbruster
87adbbff 7bd26349

+99 -32
+46 -24
scripts/qapi/common.py
··· 588 588 if not base_members: 589 589 return None 590 590 591 - discriminator_type = base_members.get(discriminator) 592 - if not discriminator_type: 591 + discriminator_value = base_members.get(discriminator) 592 + if not discriminator_value: 593 593 return None 594 594 595 - return enum_types.get(discriminator_type) 595 + return enum_types.get(discriminator_value['type']) 596 596 597 597 598 598 # Names must be letters, numbers, -, and _. They must start with letter, ··· 704 704 % (source, key)) 705 705 # Todo: allow dictionaries to represent default values of 706 706 # an optional argument. 707 - check_type(info, "Member '%s' of %s" % (key, source), arg, 708 - allow_array=True, 707 + check_known_keys(info, "member '%s' of %s" % (key, source), 708 + arg, ['type'], []) 709 + check_type(info, "Member '%s' of %s" % (key, source), 710 + arg['type'], allow_array=True, 709 711 allow_metas=['built-in', 'union', 'alternate', 'struct', 710 712 'enum']) 711 713 ··· 776 778 # member of the base struct. 777 779 check_name(info, "Discriminator of flat union '%s'" % name, 778 780 discriminator) 779 - discriminator_type = base_members.get(discriminator) 780 - if not discriminator_type: 781 + discriminator_value = base_members.get(discriminator) 782 + if not discriminator_value: 781 783 raise QAPISemError(info, 782 784 "Discriminator '%s' is not a member of base " 783 785 "struct '%s'" 784 786 % (discriminator, base)) 785 - enum_define = enum_types.get(discriminator_type) 787 + enum_define = enum_types.get(discriminator_value['type']) 786 788 allow_metas = ['struct'] 787 789 # Do not allow string discriminator 788 790 if not enum_define: ··· 796 798 for (key, value) in members.items(): 797 799 check_name(info, "Member of union '%s'" % name, key) 798 800 801 + check_known_keys(info, "member '%s' of union '%s'" % (key, name), 802 + value, ['type'], []) 799 803 # Each value must name a known type 800 804 check_type(info, "Member '%s' of union '%s'" % (key, name), 801 - value, allow_array=not base, allow_metas=allow_metas) 805 + value['type'], 806 + allow_array=not base, allow_metas=allow_metas) 802 807 803 808 # If the discriminator names an enum type, then all members 804 809 # of 'data' must also be members of the enum type. ··· 822 827 "in 'data'" % name) 823 828 for (key, value) in members.items(): 824 829 check_name(info, "Member of alternate '%s'" % name, key) 830 + check_known_keys(info, 831 + "member '%s' of alternate '%s'" % (key, name), 832 + value, ['type'], []) 833 + typ = value['type'] 825 834 826 835 # Ensure alternates have no type conflicts. 827 - check_type(info, "Member '%s' of alternate '%s'" % (key, name), 828 - value, 836 + check_type(info, "Member '%s' of alternate '%s'" % (key, name), typ, 829 837 allow_metas=['built-in', 'union', 'struct', 'enum']) 830 - qtype = find_alternate_member_qtype(value) 838 + qtype = find_alternate_member_qtype(typ) 831 839 if not qtype: 832 840 raise QAPISemError(info, "Alternate '%s' member '%s' cannot use " 833 - "type '%s'" % (name, key, value)) 841 + "type '%s'" % (name, key, typ)) 834 842 conflicting = set([qtype]) 835 843 if qtype == 'QTYPE_QSTRING': 836 - enum_expr = enum_types.get(value) 844 + enum_expr = enum_types.get(typ) 837 845 if enum_expr: 838 846 for v in enum_get_names(enum_expr): 839 847 if v in ['on', 'off']: ··· 849 857 "be distinguished from member '%s'" 850 858 % (name, key, types_seen[qt])) 851 859 types_seen[qt] = key 852 - 853 - 854 - def normalize_enum(expr): 855 - if isinstance(expr['data'], list): 856 - expr['data'] = [m if isinstance(m, dict) else {'name': m} 857 - for m in expr['data']] 858 860 859 861 860 862 def check_enum(expr, info): ··· 928 930 check_if(expr, info) 929 931 930 932 933 + def normalize_enum(expr): 934 + if isinstance(expr['data'], list): 935 + expr['data'] = [m if isinstance(m, dict) else {'name': m} 936 + for m in expr['data']] 937 + 938 + 939 + def normalize_members(members): 940 + if isinstance(members, OrderedDict): 941 + for key, arg in members.items(): 942 + if isinstance(arg, dict): 943 + continue 944 + members[key] = {'type': arg} 945 + 946 + 931 947 def check_exprs(exprs): 932 948 global all_names 933 949 ··· 957 973 meta = 'union' 958 974 check_keys(expr_elem, 'union', ['data'], 959 975 ['base', 'discriminator', 'if']) 976 + normalize_members(expr.get('base')) 977 + normalize_members(expr['data']) 960 978 union_types[expr[meta]] = expr 961 979 elif 'alternate' in expr: 962 980 meta = 'alternate' 963 981 check_keys(expr_elem, 'alternate', ['data'], ['if']) 982 + normalize_members(expr['data']) 964 983 elif 'struct' in expr: 965 984 meta = 'struct' 966 985 check_keys(expr_elem, 'struct', ['data'], ['base', 'if']) 986 + normalize_members(expr['data']) 967 987 struct_types[expr[meta]] = expr 968 988 elif 'command' in expr: 969 989 meta = 'command' 970 990 check_keys(expr_elem, 'command', [], 971 991 ['data', 'returns', 'gen', 'success-response', 972 992 'boxed', 'allow-oob', 'allow-preconfig', 'if']) 993 + normalize_members(expr.get('data')) 973 994 elif 'event' in expr: 974 995 meta = 'event' 975 996 check_keys(expr_elem, 'event', [], ['data', 'boxed', 'if']) 997 + normalize_members(expr.get('data')) 976 998 else: 977 999 raise QAPISemError(expr_elem['info'], 978 1000 "Expression is missing metatype") ··· 1716 1738 return QAPISchemaObjectTypeMember(name, typ, optional) 1717 1739 1718 1740 def _make_members(self, data, info): 1719 - return [self._make_member(key, value, info) 1741 + return [self._make_member(key, value['type'], info) 1720 1742 for (key, value) in data.items()] 1721 1743 1722 1744 def _def_struct_type(self, expr, info, doc): ··· 1752 1774 name, info, doc, ifcond, 1753 1775 'base', self._make_members(base, info)) 1754 1776 if tag_name: 1755 - variants = [self._make_variant(key, value) 1777 + variants = [self._make_variant(key, value['type']) 1756 1778 for (key, value) in data.items()] 1757 1779 members = [] 1758 1780 else: 1759 - variants = [self._make_simple_variant(key, value, info) 1781 + variants = [self._make_simple_variant(key, value['type'], info) 1760 1782 for (key, value) in data.items()] 1761 1783 enum = [{'name': v.name} for v in variants] 1762 1784 typ = self._make_implicit_enum_type(name, info, ifcond, enum) ··· 1772 1794 name = expr['alternate'] 1773 1795 data = expr['data'] 1774 1796 ifcond = expr.get('if') 1775 - variants = [self._make_variant(key, value) 1797 + variants = [self._make_variant(key, value['type']) 1776 1798 for (key, value) in data.items()] 1777 1799 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False) 1778 1800 self._def_entity(
+6
tests/Makefile.include
··· 318 318 qapi-schema += alternate-conflict-bool-string.json 319 319 qapi-schema += alternate-conflict-num-string.json 320 320 qapi-schema += alternate-empty.json 321 + qapi-schema += alternate-invalid-dict.json 321 322 qapi-schema += alternate-nested.json 322 323 qapi-schema += alternate-unknown.json 323 324 qapi-schema += args-alternate.json ··· 394 395 qapi-schema += escape-too-short.json 395 396 qapi-schema += event-boxed-empty.json 396 397 qapi-schema += event-case.json 398 + qapi-schema += event-member-invalid-dict.json 397 399 qapi-schema += event-nest-struct.json 398 400 qapi-schema += flat-union-array-branch.json 399 401 qapi-schema += flat-union-bad-base.json ··· 403 405 qapi-schema += flat-union-clash-member.json 404 406 qapi-schema += flat-union-empty.json 405 407 qapi-schema += flat-union-inline.json 408 + qapi-schema += flat-union-inline-invalid-dict.json 406 409 qapi-schema += flat-union-int-branch.json 407 410 qapi-schema += flat-union-invalid-branch-key.json 408 411 qapi-schema += flat-union-invalid-discriminator.json ··· 430 433 qapi-schema += missing-comma-object.json 431 434 qapi-schema += missing-type.json 432 435 qapi-schema += nested-struct-data.json 436 + qapi-schema += nested-struct-data-invalid-dict.json 433 437 qapi-schema += non-objects.json 434 438 qapi-schema += oob-test.json 435 439 qapi-schema += allow-preconfig-test.json ··· 460 464 qapi-schema += struct-base-clash-deep.json 461 465 qapi-schema += struct-base-clash.json 462 466 qapi-schema += struct-data-invalid.json 467 + qapi-schema += struct-member-invalid-dict.json 463 468 qapi-schema += struct-member-invalid.json 464 469 qapi-schema += trailing-comma-list.json 465 470 qapi-schema += trailing-comma-object.json ··· 471 476 qapi-schema += union-base-empty.json 472 477 qapi-schema += union-base-no-discriminator.json 473 478 qapi-schema += union-branch-case.json 479 + qapi-schema += union-branch-invalid-dict.json 474 480 qapi-schema += union-clash-branches.json 475 481 qapi-schema += union-empty.json 476 482 qapi-schema += union-invalid-base.json
+1
tests/qapi-schema/alternate-invalid-dict.err
··· 1 + tests/qapi-schema/alternate-invalid-dict.json:2: Key 'type' is missing from member 'two' of alternate 'Alt'
+1
tests/qapi-schema/alternate-invalid-dict.exit
··· 1 + 1
+4
tests/qapi-schema/alternate-invalid-dict.json
··· 1 + # exploded member form must have a 'type' 2 + { 'alternate': 'Alt', 3 + 'data': { 'one': 'str', 4 + 'two': { 'if': 'foo' } } }
tests/qapi-schema/alternate-invalid-dict.out

This is a binary file and will not be displayed.

+1
tests/qapi-schema/event-member-invalid-dict.err
··· 1 + tests/qapi-schema/event-member-invalid-dict.json:1: Key 'type' is missing from member 'a' of 'data' for event 'EVENT_A'
+1
tests/qapi-schema/event-member-invalid-dict.exit
··· 1 + 1
+2
tests/qapi-schema/event-member-invalid-dict.json
··· 1 + { 'event': 'EVENT_A', 2 + 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
tests/qapi-schema/event-member-invalid-dict.out

This is a binary file and will not be displayed.

+1 -1
tests/qapi-schema/event-nest-struct.json
··· 1 1 { 'event': 'EVENT_A', 2 - 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } } 2 + 'data': { 'a' : { 'type' : { 'integer': 'int' } }, 'b' : 'str' } }
+1
tests/qapi-schema/flat-union-inline-invalid-dict.err
··· 1 + tests/qapi-schema/flat-union-inline-invalid-dict.json:7: Key 'type' is missing from member 'value1' of union 'TestUnion'
+1
tests/qapi-schema/flat-union-inline-invalid-dict.exit
··· 1 + 1
+11
tests/qapi-schema/flat-union-inline-invalid-dict.json
··· 1 + # we require branches to be a struct name 2 + # TODO: should we allow anonymous inline branch types? 3 + { 'enum': 'TestEnum', 4 + 'data': [ 'value1', 'value2' ] } 5 + { 'struct': 'Base', 6 + 'data': { 'enum1': 'TestEnum', 'kind': 'str' } } 7 + { 'union': 'TestUnion', 8 + 'base': 'Base', 9 + 'discriminator': 'enum1', 10 + 'data': { 'value1': { 'string': 'str' }, 11 + 'value2': { 'integer': 'int' } } }
tests/qapi-schema/flat-union-inline-invalid-dict.out

This is a binary file and will not be displayed.

+1 -1
tests/qapi-schema/flat-union-inline.json
··· 7 7 { 'union': 'TestUnion', 8 8 'base': 'Base', 9 9 'discriminator': 'enum1', 10 - 'data': { 'value1': { 'string': 'str' }, 10 + 'data': { 'value1': { 'type': {} }, 11 11 'value2': { 'integer': 'int' } } }
+1
tests/qapi-schema/nested-struct-data-invalid-dict.err
··· 1 + tests/qapi-schema/nested-struct-data-invalid-dict.json:2: Key 'type' is missing from member 'a' of 'data' for command 'foo'
+1
tests/qapi-schema/nested-struct-data-invalid-dict.exit
··· 1 + 1
+3
tests/qapi-schema/nested-struct-data-invalid-dict.json
··· 1 + # inline subtypes collide with our desired future use of defaults 2 + { 'command': 'foo', 3 + 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
tests/qapi-schema/nested-struct-data-invalid-dict.out

This is a binary file and will not be displayed.

+1 -1
tests/qapi-schema/nested-struct-data.json
··· 1 1 # inline subtypes collide with our desired future use of defaults 2 2 { 'command': 'foo', 3 - 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } } 3 + 'data': { 'a' : { 'type': {} }, 'b' : 'str' } }
+5 -5
tests/qapi-schema/qapi-schema-test.json
··· 11 11 'guest-sync' ] } } 12 12 13 13 { 'struct': 'TestStruct', 14 - 'data': { 'integer': 'int', 'boolean': 'bool', 'string': 'str' } } 14 + 'data': { 'integer': {'type': 'int'}, 'boolean': 'bool', 'string': 'str' } } 15 15 16 16 # for testing enums 17 17 { 'struct': 'NestedEnumsOne', ··· 77 77 { 'union': 'UserDefFlatUnion', 78 78 'base': 'UserDefUnionBase', # intentional forward reference 79 79 'discriminator': 'enum1', 80 - 'data': { 'value1' : 'UserDefA', 80 + 'data': { 'value1' : {'type': 'UserDefA'}, 81 81 'value2' : 'UserDefB', 82 82 'value3' : 'UserDefB' 83 83 # 'value4' defaults to empty ··· 98 98 { 'struct': 'WrapAlternate', 99 99 'data': { 'alt': 'UserDefAlternate' } } 100 100 { 'alternate': 'UserDefAlternate', 101 - 'data': { 'udfu': 'UserDefFlatUnion', 'e': 'EnumOne', 'i': 'int', 101 + 'data': { 'udfu': {'type': 'UserDefFlatUnion'}, 'e': 'EnumOne', 'i': 'int', 102 102 'n': 'null' } } 103 103 104 104 { 'struct': 'UserDefC', ··· 134 134 { 'command': 'user_def_cmd', 'data': {} } 135 135 { 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} } 136 136 { 'command': 'user_def_cmd2', 137 - 'data': {'ud1a': 'UserDefOne', '*ud1b': 'UserDefOne'}, 137 + 'data': {'ud1a': {'type': 'UserDefOne'}, '*ud1b': 'UserDefOne'}, 138 138 'returns': 'UserDefTwo' } 139 139 140 140 { 'command': 'cmd-success-response', 'data': {}, 'success-response': false } ··· 166 166 167 167 # testing event 168 168 { 'struct': 'EventStructOne', 169 - 'data': { 'struct1': 'UserDefOne', 'string': 'str', '*enum2': 'EnumOne' } } 169 + 'data': { 'struct1': {'type': 'UserDefOne'}, 'string': 'str', '*enum2': 'EnumOne' } } 170 170 171 171 { 'event': 'EVENT_A' } 172 172 { 'event': 'EVENT_B',
+1
tests/qapi-schema/struct-member-invalid-dict.err
··· 1 + tests/qapi-schema/struct-member-invalid-dict.json:2: Key 'type' is missing from member '*a' of 'data' for struct 'foo'
+1
tests/qapi-schema/struct-member-invalid-dict.exit
··· 1 + 1
+3
tests/qapi-schema/struct-member-invalid-dict.json
··· 1 + # Long form of member must have a value member 'type' 2 + { 'struct': 'foo', 3 + 'data': { '*a': { 'case': 'foo' } } }
tests/qapi-schema/struct-member-invalid-dict.out

This is a binary file and will not be displayed.

+1
tests/qapi-schema/union-branch-invalid-dict.err
··· 1 + tests/qapi-schema/union-branch-invalid-dict.json:2: Key 'type' is missing from member 'integer' of union 'UnionInvalidBranch'
+1
tests/qapi-schema/union-branch-invalid-dict.exit
··· 1 + 1
+4
tests/qapi-schema/union-branch-invalid-dict.json
··· 1 + # Long form of member must have a value member 'type' 2 + { 'union': 'UnionInvalidBranch', 3 + 'data': { 'integer': { 'if': 'foo'}, 4 + 's8': 'int8' } }
tests/qapi-schema/union-branch-invalid-dict.out

This is a binary file and will not be displayed.