mirror of
https://github.com/qemu/qemu.git
synced 2024-12-12 21:23:36 +08:00
QAPI patches for 2019-09-24
-----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAl2KB7wSHGFybWJydUBy ZWRoYXQuY29tAAoJEDhwtADrkYZTHAYP+gJ0rd9PH1rLcUA0UvxIy10sPAw+Oghn GtsTlKGZzyD1xLLKSLP+zcsJAAxAW0ixGl41vNnPzYQ7iHtNgZQeZKXErbpSz3/S 4ubmgAHaEVQ2Jo3wzyqCk+21RtsLDi+i4NLBSwUyIlqHCbHecBuOFzHClzeJldxi qws+jFKMQtvOM7ShpM0QC2GSpMeUy4pIEqGG4cJ+IdBuya+qXlc1FDkRgzmUEQI7 otQ79AAkVBfw9rwQrAKGMZHmJWAWQWPRAf3MwDhJuutgIZn26Vv4DfpsjUz/07WR ZTYaMKGY3KqVUDkQIBmZEjJ32Ho529DqkDa24vnvqYIYcfd8FiNMGXzXPfb/2/cU gX4Ao7B8G1svMtbRJpSIVgfdQqHGMRDl+OFPTn/r78NKKcwTmmhOCwEIH8+fAyQL mqUIABVX/RXSvmeGuhCrUqCCt+23VipIcXUUFFIOvtbpHXjaVKP+RDMjiQwgjYrj wYPa+dK1RwKVSH2yxGvLBm2qhkl3XFVsoDiZ2jgOK4vZw1L8ObM9fn04eLvonvXz oalfKA28k2ux2FpwYU9Xpc/T4EyRWxhoUKnV6pjZ2Y08jWb1QN+v3T/q8ehxRXJd /iVaCaBpIW7fMwC+TceOIWM/iBILgJL5H1IRnPmcs0NExo7RCOtkNEPY0n3WGWKq +RRAlYx2I5yk =1oxz -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2019-09-24' into staging QAPI patches for 2019-09-24 # gpg: Signature made Tue 24 Sep 2019 13:10:36 BST # gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653 # gpg: issuer "armbru@redhat.com" # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full] # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full] # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-qapi-2019-09-24: (37 commits) qapi: Assert .visit() and .check_clash() run only after .check() qapi: Fix excessive QAPISchemaEntity.check() recursion qapi: Fix to .check() empty structs just once qapi: Delete useless check_exprs() code for simple union kind qapi: Clean up around check_known_keys() qapi: Simplify check_keys() qapi: Normalize 'if' in check_exprs(), like other sugar qapi: Fix missing 'if' checks in struct, union, alternate 'data' qapi: Reject blank 'if' conditions in addition to empty ones qapi: Fix broken discriminator error messages qapi: Remove null from schema language qapi: Improve reporting of lexical errors qapi: Use quotes more consistently in frontend error messages tests/qapi-schema: Demonstrate suboptimal lexical errors tests/qapi-schema: Demonstrate insufficient 'if' checking tests/qapi-schema: Demonstrate broken discriminator errors tests/qapi-schema: Demonstrate misleading optional tag error tests/qapi-schema: Delete two redundant tests tests/qapi-schema: Cover unknown pragma qapi: Tweak code to match docs/devel/qapi-code-gen.txt ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
4142b011ca
File diff suppressed because it is too large
Load Diff
@ -364,10 +364,10 @@ void visit_start_list(Visitor *v, const char *name, GenericList **list,
|
||||
* @tail must not be NULL; on the first call, @tail is the value of
|
||||
* *list after visit_start_list(), and on subsequent calls @tail must
|
||||
* be the previously returned value. Should be called in a loop until
|
||||
* a NULL return or error occurs; for each non-NULL return, the caller
|
||||
* then calls the appropriate visit_type_*() for the element type of
|
||||
* the list, with that function's name parameter set to NULL and obj
|
||||
* set to the address of @tail->value.
|
||||
* a NULL return; for each non-NULL return, the caller then calls the
|
||||
* appropriate visit_type_*() for the element type of the list, with
|
||||
* that function's name parameter set to NULL and obj set to the
|
||||
* address of @tail->value.
|
||||
*/
|
||||
GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size);
|
||||
|
||||
|
@ -24,7 +24,8 @@ enum ListMode
|
||||
{
|
||||
LM_NONE, /* not traversing a list of repeated options */
|
||||
|
||||
LM_IN_PROGRESS, /* opts_next_list() ready to be called.
|
||||
LM_IN_PROGRESS, /*
|
||||
* opts_next_list() ready to be called.
|
||||
*
|
||||
* Generating the next list link will consume the most
|
||||
* recently parsed QemuOpt instance of the repeated
|
||||
@ -36,7 +37,8 @@ enum ListMode
|
||||
* LM_UNSIGNED_INTERVAL.
|
||||
*/
|
||||
|
||||
LM_SIGNED_INTERVAL, /* opts_next_list() has been called.
|
||||
LM_SIGNED_INTERVAL, /*
|
||||
* opts_next_list() has been called.
|
||||
*
|
||||
* Generating the next list link will consume the most
|
||||
* recently stored element from the signed interval,
|
||||
@ -48,7 +50,14 @@ enum ListMode
|
||||
* next element of the signed interval.
|
||||
*/
|
||||
|
||||
LM_UNSIGNED_INTERVAL /* Same as above, only for an unsigned interval. */
|
||||
LM_UNSIGNED_INTERVAL, /* Same as above, only for an unsigned interval. */
|
||||
|
||||
LM_TRAVERSED /*
|
||||
* opts_next_list() has been called.
|
||||
*
|
||||
* No more QemuOpt instance in the list.
|
||||
* The traversal has been completed.
|
||||
*/
|
||||
};
|
||||
|
||||
typedef enum ListMode ListMode;
|
||||
@ -238,6 +247,8 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size)
|
||||
OptsVisitor *ov = to_ov(v);
|
||||
|
||||
switch (ov->list_mode) {
|
||||
case LM_TRAVERSED:
|
||||
return NULL;
|
||||
case LM_SIGNED_INTERVAL:
|
||||
case LM_UNSIGNED_INTERVAL:
|
||||
if (ov->list_mode == LM_SIGNED_INTERVAL) {
|
||||
@ -258,6 +269,8 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size)
|
||||
opt = g_queue_pop_head(ov->repeated_opts);
|
||||
if (g_queue_is_empty(ov->repeated_opts)) {
|
||||
g_hash_table_remove(ov->unprocessed_opts, opt->name);
|
||||
ov->repeated_opts = NULL;
|
||||
ov->list_mode = LM_TRAVERSED;
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
@ -289,7 +302,8 @@ opts_end_list(Visitor *v, void **obj)
|
||||
|
||||
assert(ov->list_mode == LM_IN_PROGRESS ||
|
||||
ov->list_mode == LM_SIGNED_INTERVAL ||
|
||||
ov->list_mode == LM_UNSIGNED_INTERVAL);
|
||||
ov->list_mode == LM_UNSIGNED_INTERVAL ||
|
||||
ov->list_mode == LM_TRAVERSED);
|
||||
ov->repeated_opts = NULL;
|
||||
ov->list_mode = LM_NONE;
|
||||
}
|
||||
@ -306,6 +320,10 @@ lookup_scalar(const OptsVisitor *ov, const char *name, Error **errp)
|
||||
list = lookup_distinct(ov, name, errp);
|
||||
return list ? g_queue_peek_tail(list) : NULL;
|
||||
}
|
||||
if (ov->list_mode == LM_TRAVERSED) {
|
||||
error_setg(errp, "Fewer list elements than expected");
|
||||
return NULL;
|
||||
}
|
||||
assert(ov->list_mode == LM_IN_PROGRESS);
|
||||
return g_queue_peek_head(ov->repeated_opts);
|
||||
}
|
||||
|
@ -19,11 +19,11 @@ Makefile*
|
||||
*.mak
|
||||
|
||||
# qapi schema
|
||||
*.json
|
||||
qapi/*.json
|
||||
qga/*.json
|
||||
|
||||
# headers
|
||||
*.h
|
||||
|
||||
# code
|
||||
*.c
|
||||
|
||||
|
@ -30,7 +30,7 @@ def gen_call(name, arg_type, boxed, ret_type):
|
||||
|
||||
argstr = ''
|
||||
if boxed:
|
||||
assert arg_type and not arg_type.is_empty()
|
||||
assert arg_type
|
||||
argstr = '&arg, '
|
||||
elif arg_type:
|
||||
assert not arg_type.variants
|
||||
@ -96,7 +96,7 @@ def gen_marshal_decl(name):
|
||||
|
||||
|
||||
def gen_marshal(name, arg_type, boxed, ret_type):
|
||||
have_args = arg_type and not arg_type.is_empty()
|
||||
have_args = boxed or (arg_type and not arg_type.is_empty())
|
||||
|
||||
ret = mcgen('''
|
||||
|
||||
|
@ -103,11 +103,11 @@ class QAPISemError(QAPIError):
|
||||
|
||||
class QAPIDoc(object):
|
||||
"""
|
||||
A documentation comment block, either expression or free-form
|
||||
A documentation comment block, either definition or free-form
|
||||
|
||||
Expression documentation blocks consist of
|
||||
Definition documentation blocks consist of
|
||||
|
||||
* a body section: one line naming the expression, followed by an
|
||||
* a body section: one line naming the definition, followed by an
|
||||
overview (any number of lines)
|
||||
|
||||
* argument sections: a description of each argument (for commands
|
||||
@ -200,9 +200,9 @@ class QAPIDoc(object):
|
||||
Process a line of documentation text in the body section.
|
||||
|
||||
If this a symbol line and it is the section's first line, this
|
||||
is an expression documentation block for that symbol.
|
||||
is a definition documentation block for that symbol.
|
||||
|
||||
If it's an expression documentation block, another symbol line
|
||||
If it's a definition documentation block, another symbol line
|
||||
begins the argument section for the argument named by it, and
|
||||
a section tag begins an additional section. Start that
|
||||
section and append the line to it.
|
||||
@ -214,13 +214,13 @@ class QAPIDoc(object):
|
||||
# recognized, and get silently treated as ordinary text
|
||||
if not self.symbol and not self.body.text and line.startswith('@'):
|
||||
if not line.endswith(':'):
|
||||
raise QAPIParseError(self._parser, "Line should end with :")
|
||||
raise QAPIParseError(self._parser, "Line should end with ':'")
|
||||
self.symbol = line[1:-1]
|
||||
# FIXME invalid names other than the empty string aren't flagged
|
||||
if not self.symbol:
|
||||
raise QAPIParseError(self._parser, "Invalid name")
|
||||
elif self.symbol:
|
||||
# This is an expression documentation block
|
||||
# This is a definition documentation block
|
||||
if name.startswith('@') and name.endswith(':'):
|
||||
self._append_line = self._append_args_line
|
||||
self._append_args_line(line)
|
||||
@ -428,7 +428,7 @@ class QAPISchemaParser(object):
|
||||
pragma = expr['pragma']
|
||||
if not isinstance(pragma, dict):
|
||||
raise QAPISemError(
|
||||
info, "Value of 'pragma' must be a dictionary")
|
||||
info, "Value of 'pragma' must be an object")
|
||||
for name, value in pragma.items():
|
||||
self._pragma(name, value, info)
|
||||
else:
|
||||
@ -437,7 +437,7 @@ class QAPISchemaParser(object):
|
||||
if cur_doc:
|
||||
if not cur_doc.symbol:
|
||||
raise QAPISemError(
|
||||
cur_doc.info, "Expression documentation required")
|
||||
cur_doc.info, "Definition documentation required")
|
||||
expr_elem['doc'] = cur_doc
|
||||
self.exprs.append(expr_elem)
|
||||
cur_doc = None
|
||||
@ -470,7 +470,7 @@ class QAPISchemaParser(object):
|
||||
else:
|
||||
fobj = open(incl_fname, 'r')
|
||||
except IOError as e:
|
||||
raise QAPISemError(info, '%s: %s' % (e.strerror, incl_fname))
|
||||
raise QAPISemError(info, "%s: %s" % (e.strerror, incl_fname))
|
||||
return QAPISchemaParser(fobj, previously_included, info)
|
||||
|
||||
def _pragma(self, name, value, info):
|
||||
@ -515,57 +515,31 @@ class QAPISchemaParser(object):
|
||||
elif self.tok in '{}:,[]':
|
||||
return
|
||||
elif self.tok == "'":
|
||||
# Note: we accept only printable ASCII
|
||||
string = ''
|
||||
esc = False
|
||||
while True:
|
||||
ch = self.src[self.cursor]
|
||||
self.cursor += 1
|
||||
if ch == '\n':
|
||||
raise QAPIParseError(self, 'Missing terminating "\'"')
|
||||
raise QAPIParseError(self, "Missing terminating \"'\"")
|
||||
if esc:
|
||||
if ch == 'b':
|
||||
string += '\b'
|
||||
elif ch == 'f':
|
||||
string += '\f'
|
||||
elif ch == 'n':
|
||||
string += '\n'
|
||||
elif ch == 'r':
|
||||
string += '\r'
|
||||
elif ch == 't':
|
||||
string += '\t'
|
||||
elif ch == 'u':
|
||||
value = 0
|
||||
for _ in range(0, 4):
|
||||
ch = self.src[self.cursor]
|
||||
self.cursor += 1
|
||||
if ch not in '0123456789abcdefABCDEF':
|
||||
raise QAPIParseError(self,
|
||||
'\\u escape needs 4 '
|
||||
'hex digits')
|
||||
value = (value << 4) + int(ch, 16)
|
||||
# If Python 2 and 3 didn't disagree so much on
|
||||
# how to handle Unicode, then we could allow
|
||||
# Unicode string defaults. But most of QAPI is
|
||||
# ASCII-only, so we aren't losing much for now.
|
||||
if not value or value > 0x7f:
|
||||
raise QAPIParseError(self,
|
||||
'For now, \\u escape '
|
||||
'only supports non-zero '
|
||||
'values up to \\u007f')
|
||||
string += chr(value)
|
||||
elif ch in '\\/\'"':
|
||||
string += ch
|
||||
else:
|
||||
# Note: we recognize only \\ because we have
|
||||
# no use for funny characters in strings
|
||||
if ch != '\\':
|
||||
raise QAPIParseError(self,
|
||||
"Unknown escape \\%s" % ch)
|
||||
esc = False
|
||||
elif ch == '\\':
|
||||
esc = True
|
||||
continue
|
||||
elif ch == "'":
|
||||
self.val = string
|
||||
return
|
||||
else:
|
||||
string += ch
|
||||
if ord(ch) < 32 or ord(ch) >= 127:
|
||||
raise QAPIParseError(
|
||||
self, "Funny character in string")
|
||||
string += ch
|
||||
elif self.src.startswith('true', self.pos):
|
||||
self.val = True
|
||||
self.cursor += 3
|
||||
@ -574,10 +548,6 @@ class QAPISchemaParser(object):
|
||||
self.val = False
|
||||
self.cursor += 4
|
||||
return
|
||||
elif self.src.startswith('null', self.pos):
|
||||
self.val = None
|
||||
self.cursor += 3
|
||||
return
|
||||
elif self.tok == '\n':
|
||||
if self.cursor == len(self.src):
|
||||
self.tok = None
|
||||
@ -585,7 +555,11 @@ class QAPISchemaParser(object):
|
||||
self.line += 1
|
||||
self.line_pos = self.cursor
|
||||
elif not self.tok.isspace():
|
||||
raise QAPIParseError(self, 'Stray "%s"' % self.tok)
|
||||
# Show up to next structural, whitespace or quote
|
||||
# character
|
||||
match = re.match('[^[\\]{}:,\\s\'"]+',
|
||||
self.src[self.cursor-1:])
|
||||
raise QAPIParseError(self, "Stray '%s'" % match.group(0))
|
||||
|
||||
def get_members(self):
|
||||
expr = OrderedDict()
|
||||
@ -593,24 +567,24 @@ class QAPISchemaParser(object):
|
||||
self.accept()
|
||||
return expr
|
||||
if self.tok != "'":
|
||||
raise QAPIParseError(self, 'Expected string or "}"')
|
||||
raise QAPIParseError(self, "Expected string or '}'")
|
||||
while True:
|
||||
key = self.val
|
||||
self.accept()
|
||||
if self.tok != ':':
|
||||
raise QAPIParseError(self, 'Expected ":"')
|
||||
raise QAPIParseError(self, "Expected ':'")
|
||||
self.accept()
|
||||
if key in expr:
|
||||
raise QAPIParseError(self, 'Duplicate key "%s"' % key)
|
||||
raise QAPIParseError(self, "Duplicate key '%s'" % key)
|
||||
expr[key] = self.get_expr(True)
|
||||
if self.tok == '}':
|
||||
self.accept()
|
||||
return expr
|
||||
if self.tok != ',':
|
||||
raise QAPIParseError(self, 'Expected "," or "}"')
|
||||
raise QAPIParseError(self, "Expected ',' or '}'")
|
||||
self.accept()
|
||||
if self.tok != "'":
|
||||
raise QAPIParseError(self, 'Expected string')
|
||||
raise QAPIParseError(self, "Expected string")
|
||||
|
||||
def get_values(self):
|
||||
expr = []
|
||||
@ -618,20 +592,20 @@ class QAPISchemaParser(object):
|
||||
self.accept()
|
||||
return expr
|
||||
if self.tok not in "{['tfn":
|
||||
raise QAPIParseError(self, 'Expected "{", "[", "]", string, '
|
||||
'boolean or "null"')
|
||||
raise QAPIParseError(
|
||||
self, "Expected '{', '[', ']', string, boolean or 'null'")
|
||||
while True:
|
||||
expr.append(self.get_expr(True))
|
||||
if self.tok == ']':
|
||||
self.accept()
|
||||
return expr
|
||||
if self.tok != ',':
|
||||
raise QAPIParseError(self, 'Expected "," or "]"')
|
||||
raise QAPIParseError(self, "Expected ',' or ']'")
|
||||
self.accept()
|
||||
|
||||
def get_expr(self, nested):
|
||||
if self.tok != '{' and not nested:
|
||||
raise QAPIParseError(self, 'Expected "{"')
|
||||
raise QAPIParseError(self, "Expected '{'")
|
||||
if self.tok == '{':
|
||||
self.accept()
|
||||
expr = self.get_members()
|
||||
@ -642,8 +616,8 @@ class QAPISchemaParser(object):
|
||||
expr = self.val
|
||||
self.accept()
|
||||
else:
|
||||
raise QAPIParseError(self, 'Expected "{", "[", string, '
|
||||
'boolean or "null"')
|
||||
raise QAPIParseError(
|
||||
self, "Expected '{', '[', string, boolean or 'null'")
|
||||
return expr
|
||||
|
||||
def get_doc(self, info):
|
||||
@ -698,26 +672,6 @@ def find_alternate_member_qtype(qapi_type):
|
||||
return None
|
||||
|
||||
|
||||
# Return the discriminator enum define if discriminator is specified as an
|
||||
# enum type, otherwise return None.
|
||||
def discriminator_find_enum_define(expr):
|
||||
base = expr.get('base')
|
||||
discriminator = expr.get('discriminator')
|
||||
|
||||
if not (discriminator and base):
|
||||
return None
|
||||
|
||||
base_members = find_base_members(base)
|
||||
if not base_members:
|
||||
return None
|
||||
|
||||
discriminator_value = base_members.get(discriminator)
|
||||
if not discriminator_value:
|
||||
return None
|
||||
|
||||
return enum_types.get(discriminator_value['type'])
|
||||
|
||||
|
||||
# Names must be letters, numbers, -, and _. They must start with letter,
|
||||
# except for downstream extensions which must start with __RFQDN_.
|
||||
# Dots are only valid in the downstream extension prefix.
|
||||
@ -748,7 +702,7 @@ def check_name(info, source, name, allow_optional=False,
|
||||
raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
|
||||
|
||||
|
||||
def add_name(name, info, meta, implicit=False):
|
||||
def add_name(name, info, meta):
|
||||
global all_names
|
||||
check_name(info, "'%s'" % meta, name)
|
||||
# FIXME should reject names that differ only in '_' vs. '.'
|
||||
@ -756,7 +710,7 @@ def add_name(name, info, meta, implicit=False):
|
||||
if name in all_names:
|
||||
raise QAPISemError(info, "%s '%s' is already defined"
|
||||
% (all_names[name], name))
|
||||
if not implicit and (name.endswith('Kind') or name.endswith('List')):
|
||||
if name.endswith('Kind') or name.endswith('List'):
|
||||
raise QAPISemError(info, "%s '%s' should not end in '%s'"
|
||||
% (meta, name, name[-4:]))
|
||||
all_names[name] = meta
|
||||
@ -768,8 +722,9 @@ def check_if(expr, info):
|
||||
if not isinstance(ifcond, str):
|
||||
raise QAPISemError(
|
||||
info, "'if' condition must be a string or a list of strings")
|
||||
if ifcond == '':
|
||||
raise QAPISemError(info, "'if' condition '' makes no sense")
|
||||
if ifcond.strip() == '':
|
||||
raise QAPISemError(info, "'if' condition '%s' makes no sense"
|
||||
% ifcond)
|
||||
|
||||
ifcond = expr.get('if')
|
||||
if ifcond is None:
|
||||
@ -783,9 +738,8 @@ def check_if(expr, info):
|
||||
check_if_str(ifcond, info)
|
||||
|
||||
|
||||
def check_type(info, source, value, allow_array=False,
|
||||
allow_dict=False, allow_optional=False,
|
||||
allow_metas=[]):
|
||||
def check_type(info, source, value,
|
||||
allow_array=False, allow_dict=False, allow_metas=[]):
|
||||
global all_names
|
||||
|
||||
if value is None:
|
||||
@ -816,12 +770,12 @@ def check_type(info, source, value, allow_array=False,
|
||||
|
||||
if not isinstance(value, OrderedDict):
|
||||
raise QAPISemError(info,
|
||||
"%s should be a dictionary or type name" % source)
|
||||
"%s should be an object or type name" % source)
|
||||
|
||||
# value is a dictionary, check that each member is okay
|
||||
for (key, arg) in value.items():
|
||||
check_name(info, "Member of %s" % source, key,
|
||||
allow_optional=allow_optional)
|
||||
allow_optional=True)
|
||||
if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
|
||||
raise QAPISemError(info, "Member of %s uses reserved name '%s'"
|
||||
% (source, key))
|
||||
@ -829,6 +783,8 @@ def check_type(info, source, value, allow_array=False,
|
||||
# an optional argument.
|
||||
check_known_keys(info, "member '%s' of %s" % (key, source),
|
||||
arg, ['type'], ['if'])
|
||||
check_if(arg, info)
|
||||
normalize_if(arg)
|
||||
check_type(info, "Member '%s' of %s" % (key, source),
|
||||
arg['type'], allow_array=True,
|
||||
allow_metas=['built-in', 'union', 'alternate', 'struct',
|
||||
@ -841,16 +797,16 @@ def check_command(expr, info):
|
||||
|
||||
args_meta = ['struct']
|
||||
if boxed:
|
||||
args_meta += ['union', 'alternate']
|
||||
args_meta += ['union']
|
||||
check_type(info, "'data' for command '%s'" % name,
|
||||
expr.get('data'), allow_dict=not boxed, allow_optional=True,
|
||||
expr.get('data'), allow_dict=not boxed,
|
||||
allow_metas=args_meta)
|
||||
returns_meta = ['union', 'struct']
|
||||
if name in returns_whitelist:
|
||||
returns_meta += ['built-in', 'alternate', 'enum']
|
||||
check_type(info, "'returns' for command '%s'" % name,
|
||||
expr.get('returns'), allow_array=True,
|
||||
allow_optional=True, allow_metas=returns_meta)
|
||||
allow_metas=returns_meta)
|
||||
|
||||
|
||||
def check_event(expr, info):
|
||||
@ -859,9 +815,9 @@ def check_event(expr, info):
|
||||
|
||||
meta = ['struct']
|
||||
if boxed:
|
||||
meta += ['union', 'alternate']
|
||||
meta += ['union']
|
||||
check_type(info, "'data' for event '%s'" % name,
|
||||
expr.get('data'), allow_dict=not boxed, allow_optional=True,
|
||||
expr.get('data'), allow_dict=not boxed,
|
||||
allow_metas=meta)
|
||||
|
||||
|
||||
@ -879,7 +835,7 @@ def check_union(expr, info):
|
||||
|
||||
# With no discriminator it is a simple union.
|
||||
if discriminator is None:
|
||||
enum_define = None
|
||||
enum_values = members.keys()
|
||||
allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
|
||||
if base is not None:
|
||||
raise QAPISemError(info, "Simple union '%s' must not have a base" %
|
||||
@ -889,7 +845,7 @@ def check_union(expr, info):
|
||||
else:
|
||||
# The object must have a string or dictionary 'base'.
|
||||
check_type(info, "'base' for union '%s'" % name,
|
||||
base, allow_dict=True, allow_optional=True,
|
||||
base, allow_dict=True,
|
||||
allow_metas=['struct'])
|
||||
if not base:
|
||||
raise QAPISemError(info, "Flat union '%s' must have a base"
|
||||
@ -904,29 +860,32 @@ def check_union(expr, info):
|
||||
discriminator_value = base_members.get(discriminator)
|
||||
if not discriminator_value:
|
||||
raise QAPISemError(info,
|
||||
"Discriminator '%s' is not a member of base "
|
||||
"struct '%s'"
|
||||
% (discriminator, base))
|
||||
"Discriminator '%s' is not a member of 'base'"
|
||||
% discriminator)
|
||||
if discriminator_value.get('if'):
|
||||
raise QAPISemError(info, 'The discriminator %s.%s for union %s '
|
||||
'must not be conditional' %
|
||||
(base, discriminator, name))
|
||||
raise QAPISemError(
|
||||
info,
|
||||
"The discriminator '%s' for union %s must not be conditional"
|
||||
% (discriminator, name))
|
||||
enum_define = enum_types.get(discriminator_value['type'])
|
||||
allow_metas = ['struct']
|
||||
# Do not allow string discriminator
|
||||
if not enum_define:
|
||||
raise QAPISemError(info,
|
||||
"Discriminator '%s' must be of enumeration "
|
||||
"type" % discriminator)
|
||||
enum_values = enum_get_names(enum_define)
|
||||
allow_metas = ['struct']
|
||||
|
||||
if (len(enum_values) == 0):
|
||||
raise QAPISemError(info, "Union '%s' has no branches" % name)
|
||||
|
||||
# Check every branch; don't allow an empty union
|
||||
if len(members) == 0:
|
||||
raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
|
||||
for (key, value) in members.items():
|
||||
check_name(info, "Member of union '%s'" % name, key)
|
||||
|
||||
check_known_keys(info, "member '%s' of union '%s'" % (key, name),
|
||||
value, ['type'], ['if'])
|
||||
check_if(value, info)
|
||||
normalize_if(value)
|
||||
# Each value must name a known type
|
||||
check_type(info, "Member '%s' of union '%s'" % (key, name),
|
||||
value['type'],
|
||||
@ -934,8 +893,8 @@ def check_union(expr, info):
|
||||
|
||||
# If the discriminator names an enum type, then all members
|
||||
# of 'data' must also be members of the enum type.
|
||||
if enum_define:
|
||||
if key not in enum_get_names(enum_define):
|
||||
if discriminator is not None:
|
||||
if key not in enum_values:
|
||||
raise QAPISemError(info,
|
||||
"Discriminator value '%s' is not found in "
|
||||
"enum '%s'"
|
||||
@ -947,16 +906,16 @@ def check_alternate(expr, info):
|
||||
members = expr['data']
|
||||
types_seen = {}
|
||||
|
||||
# Check every branch; require at least two branches
|
||||
if len(members) < 2:
|
||||
if len(members) == 0:
|
||||
raise QAPISemError(info,
|
||||
"Alternate '%s' should have at least two branches "
|
||||
"in 'data'" % name)
|
||||
"Alternate '%s' cannot have empty 'data'" % name)
|
||||
for (key, value) in members.items():
|
||||
check_name(info, "Member of alternate '%s'" % name, key)
|
||||
check_known_keys(info,
|
||||
"member '%s' of alternate '%s'" % (key, name),
|
||||
value, ['type'], ['if'])
|
||||
check_if(value, info)
|
||||
normalize_if(value)
|
||||
typ = value['type']
|
||||
|
||||
# Ensure alternates have no type conflicts.
|
||||
@ -999,9 +958,10 @@ def check_enum(expr, info):
|
||||
"Enum '%s' requires a string for 'prefix'" % name)
|
||||
|
||||
for member in members:
|
||||
source = "dictionary member of enum '%s'" % name
|
||||
check_known_keys(info, source, member, ['name'], ['if'])
|
||||
check_known_keys(info, "member of enum '%s'" % name, member,
|
||||
['name'], ['if'])
|
||||
check_if(member, info)
|
||||
normalize_if(member)
|
||||
check_name(info, "Member of enum '%s'" % name, member['name'],
|
||||
enum_member=True)
|
||||
|
||||
@ -1012,7 +972,7 @@ def check_struct(expr, info):
|
||||
features = expr.get('features')
|
||||
|
||||
check_type(info, "'data' for struct '%s'" % name, members,
|
||||
allow_dict=True, allow_optional=True)
|
||||
allow_dict=True)
|
||||
check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
|
||||
allow_metas=['struct'])
|
||||
|
||||
@ -1027,36 +987,35 @@ def check_struct(expr, info):
|
||||
['name'], ['if'])
|
||||
|
||||
check_if(f, info)
|
||||
normalize_if(f)
|
||||
check_name(info, "Feature of struct %s" % name, f['name'])
|
||||
|
||||
|
||||
def check_known_keys(info, source, keys, required, optional):
|
||||
def check_known_keys(info, source, value, required, optional):
|
||||
|
||||
def pprint(elems):
|
||||
return ', '.join("'" + e + "'" for e in sorted(elems))
|
||||
|
||||
missing = set(required) - set(keys)
|
||||
missing = set(required) - set(value)
|
||||
if missing:
|
||||
raise QAPISemError(info, "Key%s %s %s missing from %s"
|
||||
% ('s' if len(missing) > 1 else '', pprint(missing),
|
||||
'are' if len(missing) > 1 else 'is', source))
|
||||
allowed = set(required + optional)
|
||||
unknown = set(keys) - allowed
|
||||
unknown = set(value) - allowed
|
||||
if unknown:
|
||||
raise QAPISemError(info, "Unknown key%s %s in %s\nValid keys are %s."
|
||||
% ('s' if len(unknown) > 1 else '', pprint(unknown),
|
||||
source, pprint(allowed)))
|
||||
|
||||
|
||||
def check_keys(expr_elem, meta, required, optional=[]):
|
||||
expr = expr_elem['expr']
|
||||
info = expr_elem['info']
|
||||
def check_keys(expr, info, meta, required, optional=[]):
|
||||
name = expr[meta]
|
||||
if not isinstance(name, str):
|
||||
raise QAPISemError(info, "'%s' key must have a string value" % meta)
|
||||
required = required + [meta]
|
||||
source = "%s '%s'" % (meta, name)
|
||||
check_known_keys(info, source, expr.keys(), required, optional)
|
||||
check_known_keys(info, source, expr, required, optional)
|
||||
for (key, value) in expr.items():
|
||||
if key in ['gen', 'success-response'] and value is not False:
|
||||
raise QAPISemError(info,
|
||||
@ -1091,6 +1050,12 @@ def normalize_features(features):
|
||||
for f in features]
|
||||
|
||||
|
||||
def normalize_if(expr):
|
||||
ifcond = expr.get('if')
|
||||
if isinstance(ifcond, str):
|
||||
expr['if'] = [ifcond]
|
||||
|
||||
|
||||
def check_exprs(exprs):
|
||||
global all_names
|
||||
|
||||
@ -1109,65 +1074,50 @@ def check_exprs(exprs):
|
||||
|
||||
if not doc and doc_required:
|
||||
raise QAPISemError(info,
|
||||
"Expression missing documentation comment")
|
||||
"Definition missing documentation comment")
|
||||
|
||||
if 'enum' in expr:
|
||||
meta = 'enum'
|
||||
check_keys(expr_elem, 'enum', ['data'], ['if', 'prefix'])
|
||||
check_keys(expr, info, 'enum', ['data'], ['if', 'prefix'])
|
||||
normalize_enum(expr)
|
||||
enum_types[expr[meta]] = expr
|
||||
elif 'union' in expr:
|
||||
meta = 'union'
|
||||
check_keys(expr_elem, 'union', ['data'],
|
||||
check_keys(expr, info, 'union', ['data'],
|
||||
['base', 'discriminator', 'if'])
|
||||
normalize_members(expr.get('base'))
|
||||
normalize_members(expr['data'])
|
||||
union_types[expr[meta]] = expr
|
||||
elif 'alternate' in expr:
|
||||
meta = 'alternate'
|
||||
check_keys(expr_elem, 'alternate', ['data'], ['if'])
|
||||
check_keys(expr, info, 'alternate', ['data'], ['if'])
|
||||
normalize_members(expr['data'])
|
||||
elif 'struct' in expr:
|
||||
meta = 'struct'
|
||||
check_keys(expr_elem, 'struct', ['data'],
|
||||
check_keys(expr, info, 'struct', ['data'],
|
||||
['base', 'if', 'features'])
|
||||
normalize_members(expr['data'])
|
||||
normalize_features(expr.get('features'))
|
||||
struct_types[expr[meta]] = expr
|
||||
elif 'command' in expr:
|
||||
meta = 'command'
|
||||
check_keys(expr_elem, 'command', [],
|
||||
check_keys(expr, info, 'command', [],
|
||||
['data', 'returns', 'gen', 'success-response',
|
||||
'boxed', 'allow-oob', 'allow-preconfig', 'if'])
|
||||
normalize_members(expr.get('data'))
|
||||
elif 'event' in expr:
|
||||
meta = 'event'
|
||||
check_keys(expr_elem, 'event', [], ['data', 'boxed', 'if'])
|
||||
check_keys(expr, info, 'event', [], ['data', 'boxed', 'if'])
|
||||
normalize_members(expr.get('data'))
|
||||
else:
|
||||
raise QAPISemError(expr_elem['info'],
|
||||
"Expression is missing metatype")
|
||||
raise QAPISemError(info, "Expression is missing metatype")
|
||||
normalize_if(expr)
|
||||
name = expr[meta]
|
||||
add_name(name, info, meta)
|
||||
if doc and doc.symbol != name:
|
||||
raise QAPISemError(info, "Definition of '%s' follows documentation"
|
||||
" for '%s'" % (name, doc.symbol))
|
||||
|
||||
# Try again for hidden UnionKind enum
|
||||
for expr_elem in exprs:
|
||||
expr = expr_elem['expr']
|
||||
|
||||
if 'include' in expr:
|
||||
continue
|
||||
if 'union' in expr and not discriminator_find_enum_define(expr):
|
||||
name = '%sKind' % expr['union']
|
||||
elif 'alternate' in expr:
|
||||
name = '%sKind' % expr['alternate']
|
||||
else:
|
||||
continue
|
||||
enum_types[name] = {'enum': name}
|
||||
add_name(name, info, 'enum', implicit=True)
|
||||
|
||||
# Validate that exprs make sense
|
||||
for expr_elem in exprs:
|
||||
expr = expr_elem['expr']
|
||||
@ -1201,19 +1151,11 @@ def check_exprs(exprs):
|
||||
# Schema compiler frontend
|
||||
#
|
||||
|
||||
def listify_cond(ifcond):
|
||||
if not ifcond:
|
||||
return []
|
||||
if not isinstance(ifcond, list):
|
||||
return [ifcond]
|
||||
return ifcond
|
||||
|
||||
|
||||
class QAPISchemaEntity(object):
|
||||
def __init__(self, name, info, doc, ifcond=None):
|
||||
assert name is None or isinstance(name, str)
|
||||
self.name = name
|
||||
self.module = None
|
||||
self._module = None
|
||||
# For explicitly defined entities, info points to the (explicit)
|
||||
# definition. For builtins (and their arrays), info is None.
|
||||
# For implicitly defined entities, info points to a place that
|
||||
@ -1221,28 +1163,34 @@ class QAPISchemaEntity(object):
|
||||
# such place).
|
||||
self.info = info
|
||||
self.doc = doc
|
||||
self._ifcond = ifcond # self.ifcond is set only after .check()
|
||||
self._ifcond = ifcond or []
|
||||
self._checked = False
|
||||
|
||||
def c_name(self):
|
||||
return c_name(self.name)
|
||||
|
||||
def check(self, schema):
|
||||
if isinstance(self._ifcond, QAPISchemaType):
|
||||
# inherit the condition from a type
|
||||
typ = self._ifcond
|
||||
typ.check(schema)
|
||||
self.ifcond = typ.ifcond
|
||||
else:
|
||||
self.ifcond = listify_cond(self._ifcond)
|
||||
assert not self._checked
|
||||
if self.info:
|
||||
self.module = os.path.relpath(self.info['file'],
|
||||
os.path.dirname(schema.fname))
|
||||
self._module = os.path.relpath(self.info['file'],
|
||||
os.path.dirname(schema.fname))
|
||||
self._checked = True
|
||||
|
||||
@property
|
||||
def ifcond(self):
|
||||
assert self._checked
|
||||
return self._ifcond
|
||||
|
||||
@property
|
||||
def module(self):
|
||||
assert self._checked
|
||||
return self._module
|
||||
|
||||
def is_implicit(self):
|
||||
return not self.info
|
||||
|
||||
def visit(self, visitor):
|
||||
pass
|
||||
assert self._checked
|
||||
|
||||
|
||||
class QAPISchemaVisitor(object):
|
||||
@ -1297,6 +1245,7 @@ class QAPISchemaInclude(QAPISchemaEntity):
|
||||
self.fname = fname
|
||||
|
||||
def visit(self, visitor):
|
||||
QAPISchemaEntity.visit(self, visitor)
|
||||
visitor.visit_include(self.fname, self.info)
|
||||
|
||||
|
||||
@ -1361,6 +1310,7 @@ class QAPISchemaBuiltinType(QAPISchemaType):
|
||||
return self.json_type()
|
||||
|
||||
def visit(self, visitor):
|
||||
QAPISchemaType.visit(self, visitor)
|
||||
visitor.visit_builtin_type(self.name, self.info, self.json_type())
|
||||
|
||||
|
||||
@ -1368,7 +1318,7 @@ class QAPISchemaEnumType(QAPISchemaType):
|
||||
def __init__(self, name, info, doc, ifcond, members, prefix):
|
||||
QAPISchemaType.__init__(self, name, info, doc, ifcond)
|
||||
for m in members:
|
||||
assert isinstance(m, QAPISchemaMember)
|
||||
assert isinstance(m, QAPISchemaEnumMember)
|
||||
m.set_owner(name)
|
||||
assert prefix is None or isinstance(prefix, str)
|
||||
self.members = members
|
||||
@ -1396,6 +1346,7 @@ class QAPISchemaEnumType(QAPISchemaType):
|
||||
return 'string'
|
||||
|
||||
def visit(self, visitor):
|
||||
QAPISchemaType.visit(self, visitor)
|
||||
visitor.visit_enum_type(self.name, self.info, self.ifcond,
|
||||
self.members, self.prefix)
|
||||
|
||||
@ -1411,9 +1362,16 @@ class QAPISchemaArrayType(QAPISchemaType):
|
||||
QAPISchemaType.check(self, schema)
|
||||
self.element_type = schema.lookup_type(self._element_type_name)
|
||||
assert self.element_type
|
||||
self.element_type.check(schema)
|
||||
self.module = self.element_type.module
|
||||
self.ifcond = self.element_type.ifcond
|
||||
|
||||
@property
|
||||
def ifcond(self):
|
||||
assert self._checked
|
||||
return self.element_type.ifcond
|
||||
|
||||
@property
|
||||
def module(self):
|
||||
assert self._checked
|
||||
return self.element_type.module
|
||||
|
||||
def is_implicit(self):
|
||||
return True
|
||||
@ -1431,6 +1389,7 @@ class QAPISchemaArrayType(QAPISchemaType):
|
||||
return 'array of ' + elt_doc_type
|
||||
|
||||
def visit(self, visitor):
|
||||
QAPISchemaType.visit(self, visitor)
|
||||
visitor.visit_array_type(self.name, self.info, self.ifcond,
|
||||
self.element_type)
|
||||
|
||||
@ -1460,13 +1419,20 @@ class QAPISchemaObjectType(QAPISchemaType):
|
||||
self.features = features
|
||||
|
||||
def check(self, schema):
|
||||
QAPISchemaType.check(self, schema)
|
||||
if self.members is False: # check for cycles
|
||||
# This calls another type T's .check() exactly when the C
|
||||
# struct emitted by gen_object() contains that T's C struct
|
||||
# (pointers don't count).
|
||||
if self.members is not None:
|
||||
# A previous .check() completed: nothing to do
|
||||
return
|
||||
if self._checked:
|
||||
# Recursed: C struct contains itself
|
||||
raise QAPISemError(self.info,
|
||||
"Object %s contains itself" % self.name)
|
||||
if self.members:
|
||||
return
|
||||
self.members = False # mark as being checked
|
||||
|
||||
QAPISchemaType.check(self, schema)
|
||||
assert self._checked and self.members is None
|
||||
|
||||
seen = OrderedDict()
|
||||
if self._base_name:
|
||||
self.base = schema.lookup_type(self._base_name)
|
||||
@ -1478,10 +1444,11 @@ class QAPISchemaObjectType(QAPISchemaType):
|
||||
m.check_clash(self.info, seen)
|
||||
if self.doc:
|
||||
self.doc.connect_member(m)
|
||||
self.members = seen.values()
|
||||
members = seen.values()
|
||||
|
||||
if self.variants:
|
||||
self.variants.check(schema, seen)
|
||||
assert self.variants.tag_member in self.members
|
||||
assert self.variants.tag_member in members
|
||||
self.variants.check_clash(self.info, seen)
|
||||
|
||||
# Features are in a name space separate from members
|
||||
@ -1492,14 +1459,26 @@ class QAPISchemaObjectType(QAPISchemaType):
|
||||
if self.doc:
|
||||
self.doc.check()
|
||||
|
||||
self.members = members # mark completed
|
||||
|
||||
# Check that the members of this type do not cause duplicate JSON members,
|
||||
# and update seen to track the members seen so far. Report any errors
|
||||
# on behalf of info, which is not necessarily self.info
|
||||
def check_clash(self, info, seen):
|
||||
assert self._checked
|
||||
assert not self.variants # not implemented
|
||||
for m in self.members:
|
||||
m.check_clash(info, seen)
|
||||
|
||||
@property
|
||||
def ifcond(self):
|
||||
assert self._checked
|
||||
if isinstance(self._ifcond, QAPISchemaType):
|
||||
# Simple union wrapper type inherits from wrapped type;
|
||||
# see _make_implicit_object_type()
|
||||
return self._ifcond.ifcond
|
||||
return self._ifcond
|
||||
|
||||
def is_implicit(self):
|
||||
# See QAPISchema._make_implicit_object_type(), as well as
|
||||
# _def_predefineds()
|
||||
@ -1524,6 +1503,7 @@ class QAPISchemaObjectType(QAPISchemaType):
|
||||
return 'object'
|
||||
|
||||
def visit(self, visitor):
|
||||
QAPISchemaType.visit(self, visitor)
|
||||
visitor.visit_object_type(self.name, self.info, self.ifcond,
|
||||
self.base, self.local_members, self.variants,
|
||||
self.features)
|
||||
@ -1539,7 +1519,7 @@ class QAPISchemaMember(object):
|
||||
def __init__(self, name, ifcond=None):
|
||||
assert isinstance(name, str)
|
||||
self.name = name
|
||||
self.ifcond = listify_cond(ifcond)
|
||||
self.ifcond = ifcond or []
|
||||
self.owner = None
|
||||
|
||||
def set_owner(self, name):
|
||||
@ -1579,6 +1559,10 @@ class QAPISchemaMember(object):
|
||||
return "'%s' %s" % (self.name, self._pretty_owner())
|
||||
|
||||
|
||||
class QAPISchemaEnumMember(QAPISchemaMember):
|
||||
role = 'value'
|
||||
|
||||
|
||||
class QAPISchemaFeature(QAPISchemaMember):
|
||||
role = 'feature'
|
||||
|
||||
@ -1607,7 +1591,6 @@ class QAPISchemaObjectTypeVariants(object):
|
||||
assert bool(tag_member) != bool(tag_name)
|
||||
assert (isinstance(tag_name, str) or
|
||||
isinstance(tag_member, QAPISchemaObjectTypeMember))
|
||||
assert len(variants) > 0
|
||||
for v in variants:
|
||||
assert isinstance(v, QAPISchemaObjectTypeVariant)
|
||||
self._tag_name = tag_name
|
||||
@ -1688,12 +1671,10 @@ class QAPISchemaAlternateType(QAPISchemaType):
|
||||
return 'value'
|
||||
|
||||
def visit(self, visitor):
|
||||
QAPISchemaType.visit(self, visitor)
|
||||
visitor.visit_alternate_type(self.name, self.info, self.ifcond,
|
||||
self.variants)
|
||||
|
||||
def is_empty(self):
|
||||
return False
|
||||
|
||||
|
||||
class QAPISchemaCommand(QAPISchemaEntity):
|
||||
def __init__(self, name, info, doc, ifcond, arg_type, ret_type,
|
||||
@ -1715,16 +1696,8 @@ class QAPISchemaCommand(QAPISchemaEntity):
|
||||
QAPISchemaEntity.check(self, schema)
|
||||
if self._arg_type_name:
|
||||
self.arg_type = schema.lookup_type(self._arg_type_name)
|
||||
assert (isinstance(self.arg_type, QAPISchemaObjectType) or
|
||||
isinstance(self.arg_type, QAPISchemaAlternateType))
|
||||
self.arg_type.check(schema)
|
||||
if self.boxed:
|
||||
if self.arg_type.is_empty():
|
||||
raise QAPISemError(self.info,
|
||||
"Cannot use 'boxed' with empty type")
|
||||
else:
|
||||
assert not isinstance(self.arg_type, QAPISchemaAlternateType)
|
||||
assert not self.arg_type.variants
|
||||
assert isinstance(self.arg_type, QAPISchemaObjectType)
|
||||
assert not self.arg_type.variants or self.boxed
|
||||
elif self.boxed:
|
||||
raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
|
||||
if self._ret_type_name:
|
||||
@ -1732,6 +1705,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
|
||||
assert isinstance(self.ret_type, QAPISchemaType)
|
||||
|
||||
def visit(self, visitor):
|
||||
QAPISchemaEntity.visit(self, visitor)
|
||||
visitor.visit_command(self.name, self.info, self.ifcond,
|
||||
self.arg_type, self.ret_type,
|
||||
self.gen, self.success_response,
|
||||
@ -1751,20 +1725,13 @@ class QAPISchemaEvent(QAPISchemaEntity):
|
||||
QAPISchemaEntity.check(self, schema)
|
||||
if self._arg_type_name:
|
||||
self.arg_type = schema.lookup_type(self._arg_type_name)
|
||||
assert (isinstance(self.arg_type, QAPISchemaObjectType) or
|
||||
isinstance(self.arg_type, QAPISchemaAlternateType))
|
||||
self.arg_type.check(schema)
|
||||
if self.boxed:
|
||||
if self.arg_type.is_empty():
|
||||
raise QAPISemError(self.info,
|
||||
"Cannot use 'boxed' with empty type")
|
||||
else:
|
||||
assert not isinstance(self.arg_type, QAPISchemaAlternateType)
|
||||
assert not self.arg_type.variants
|
||||
assert isinstance(self.arg_type, QAPISchemaObjectType)
|
||||
assert not self.arg_type.variants or self.boxed
|
||||
elif self.boxed:
|
||||
raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
|
||||
|
||||
def visit(self, visitor):
|
||||
QAPISchemaEntity.visit(self, visitor)
|
||||
visitor.visit_event(self.name, self.info, self.ifcond,
|
||||
self.arg_type, self.boxed)
|
||||
|
||||
@ -1853,7 +1820,8 @@ class QAPISchema(object):
|
||||
return [QAPISchemaFeature(f['name'], f.get('if')) for f in features]
|
||||
|
||||
def _make_enum_members(self, values):
|
||||
return [QAPISchemaMember(v['name'], v.get('if')) for v in values]
|
||||
return [QAPISchemaEnumMember(v['name'], v.get('if'))
|
||||
for v in values]
|
||||
|
||||
def _make_implicit_enum_type(self, name, info, ifcond, values):
|
||||
# See also QAPISchemaObjectTypeMember._pretty_owner()
|
||||
@ -2269,7 +2237,7 @@ const QEnumLookup %(c_name)s_lookup = {
|
||||
|
||||
def gen_enum(name, members, prefix=None):
|
||||
# append automatically generated _MAX value
|
||||
enum_members = members + [QAPISchemaMember('_MAX')]
|
||||
enum_members = members + [QAPISchemaEnumMember('_MAX')]
|
||||
|
||||
ret = mcgen('''
|
||||
|
||||
|
@ -65,6 +65,8 @@ def gen_event_send(name, arg_type, boxed, event_enum_name, event_emit):
|
||||
# practice, we can rename our local variables with a leading _ prefix,
|
||||
# or split the code into a wrapper function that creates a boxed
|
||||
# 'param' object then calls another to do the real work.
|
||||
have_args = boxed or (arg_type and not arg_type.is_empty())
|
||||
|
||||
ret = mcgen('''
|
||||
|
||||
%(proto)s
|
||||
@ -73,15 +75,13 @@ def gen_event_send(name, arg_type, boxed, event_enum_name, event_emit):
|
||||
''',
|
||||
proto=build_event_send_proto(name, arg_type, boxed))
|
||||
|
||||
if arg_type and not arg_type.is_empty():
|
||||
if have_args:
|
||||
ret += mcgen('''
|
||||
QObject *obj;
|
||||
Visitor *v;
|
||||
''')
|
||||
if not boxed:
|
||||
ret += gen_param_var(arg_type)
|
||||
else:
|
||||
assert not boxed
|
||||
|
||||
ret += mcgen('''
|
||||
|
||||
@ -90,7 +90,7 @@ def gen_event_send(name, arg_type, boxed, event_enum_name, event_emit):
|
||||
''',
|
||||
name=name)
|
||||
|
||||
if arg_type and not arg_type.is_empty():
|
||||
if have_args:
|
||||
ret += mcgen('''
|
||||
v = qobject_output_visitor_new(&obj);
|
||||
''')
|
||||
@ -121,7 +121,7 @@ def gen_event_send(name, arg_type, boxed, event_enum_name, event_emit):
|
||||
event_emit=event_emit,
|
||||
c_enum=c_enum_const(event_enum_name, name))
|
||||
|
||||
if arg_type and not arg_type.is_empty():
|
||||
if have_args:
|
||||
ret += mcgen('''
|
||||
visit_free(v);
|
||||
''')
|
||||
@ -194,7 +194,7 @@ void %(event_emit)s(%(event_enum)s event, QDict *qdict);
|
||||
self._event_emit_name))
|
||||
# Note: we generate the enum member regardless of @ifcond, to
|
||||
# keep the enumeration usable in target-independent code.
|
||||
self._event_enum_members.append(QAPISchemaMember(name))
|
||||
self._event_enum_members.append(QAPISchemaEnumMember(name))
|
||||
|
||||
|
||||
def gen_events(schema, output_dir, prefix):
|
||||
|
@ -294,6 +294,7 @@ check-qtest-generic-y += tests/test-hmp$(EXESUF)
|
||||
qapi-schema += alternate-any.json
|
||||
qapi-schema += alternate-array.json
|
||||
qapi-schema += alternate-base.json
|
||||
qapi-schema += alternate-branch-if-invalid.json
|
||||
qapi-schema += alternate-clash.json
|
||||
qapi-schema += alternate-conflict-dict.json
|
||||
qapi-schema += alternate-conflict-enum-bool.json
|
||||
@ -311,7 +312,6 @@ qapi-schema += args-array-empty.json
|
||||
qapi-schema += args-array-unknown.json
|
||||
qapi-schema += args-bad-boxed.json
|
||||
qapi-schema += args-boxed-anon.json
|
||||
qapi-schema += args-boxed-empty.json
|
||||
qapi-schema += args-boxed-string.json
|
||||
qapi-schema += args-int.json
|
||||
qapi-schema += args-invalid.json
|
||||
@ -360,7 +360,6 @@ qapi-schema += doc-missing-expr.json
|
||||
qapi-schema += doc-missing-space.json
|
||||
qapi-schema += doc-missing.json
|
||||
qapi-schema += doc-no-symbol.json
|
||||
qapi-schema += double-data.json
|
||||
qapi-schema += double-type.json
|
||||
qapi-schema += duplicate-key.json
|
||||
qapi-schema += empty.json
|
||||
@ -374,15 +373,13 @@ qapi-schema += enum-int-member.json
|
||||
qapi-schema += enum-member-case.json
|
||||
qapi-schema += enum-missing-data.json
|
||||
qapi-schema += enum-wrong-data.json
|
||||
qapi-schema += escape-outside-string.json
|
||||
qapi-schema += escape-too-big.json
|
||||
qapi-schema += escape-too-short.json
|
||||
qapi-schema += event-boxed-empty.json
|
||||
qapi-schema += event-case.json
|
||||
qapi-schema += event-member-invalid-dict.json
|
||||
qapi-schema += event-nest-struct.json
|
||||
qapi-schema += features-bad-type.json
|
||||
qapi-schema += features-duplicate-name.json
|
||||
qapi-schema += features-if-invalid.json
|
||||
qapi-schema += features-missing-name.json
|
||||
qapi-schema += features-name-bad-type.json
|
||||
qapi-schema += features-no-list.json
|
||||
@ -393,6 +390,7 @@ qapi-schema += flat-union-bad-discriminator.json
|
||||
qapi-schema += flat-union-base-any.json
|
||||
qapi-schema += flat-union-base-union.json
|
||||
qapi-schema += flat-union-clash-member.json
|
||||
qapi-schema += flat-union-discriminator-bad-name.json
|
||||
qapi-schema += flat-union-empty.json
|
||||
qapi-schema += flat-union-inline.json
|
||||
qapi-schema += flat-union-inline-invalid-dict.json
|
||||
@ -404,11 +402,11 @@ qapi-schema += flat-union-no-base.json
|
||||
qapi-schema += flat-union-optional-discriminator.json
|
||||
qapi-schema += flat-union-string-discriminator.json
|
||||
qapi-schema += funny-char.json
|
||||
qapi-schema += funny-word.json
|
||||
qapi-schema += ident-with-escape.json
|
||||
qapi-schema += include-before-err.json
|
||||
qapi-schema += include-cycle.json
|
||||
qapi-schema += include-extra-junk.json
|
||||
qapi-schema += include-format-err.json
|
||||
qapi-schema += include-nested-err.json
|
||||
qapi-schema += include-no-file.json
|
||||
qapi-schema += include-non-file.json
|
||||
@ -431,6 +429,7 @@ qapi-schema += pragma-doc-required-crap.json
|
||||
qapi-schema += pragma-extra-junk.json
|
||||
qapi-schema += pragma-name-case-whitelist-crap.json
|
||||
qapi-schema += pragma-non-dict.json
|
||||
qapi-schema += pragma-unknown.json
|
||||
qapi-schema += pragma-returns-whitelist-crap.json
|
||||
qapi-schema += qapi-schema-test.json
|
||||
qapi-schema += quoted-structural-chars.json
|
||||
@ -451,9 +450,12 @@ qapi-schema += returns-array-bad.json
|
||||
qapi-schema += returns-dict.json
|
||||
qapi-schema += returns-unknown.json
|
||||
qapi-schema += returns-whitelist.json
|
||||
qapi-schema += string-code-point-31.json
|
||||
qapi-schema += string-code-point-127.json
|
||||
qapi-schema += struct-base-clash-deep.json
|
||||
qapi-schema += struct-base-clash.json
|
||||
qapi-schema += struct-data-invalid.json
|
||||
qapi-schema += struct-member-if-invalid.json
|
||||
qapi-schema += struct-member-invalid-dict.json
|
||||
qapi-schema += struct-member-invalid.json
|
||||
qapi-schema += trailing-comma-list.json
|
||||
@ -462,10 +464,10 @@ qapi-schema += type-bypass-bad-gen.json
|
||||
qapi-schema += unclosed-list.json
|
||||
qapi-schema += unclosed-object.json
|
||||
qapi-schema += unclosed-string.json
|
||||
qapi-schema += unicode-str.json
|
||||
qapi-schema += union-base-empty.json
|
||||
qapi-schema += union-base-no-discriminator.json
|
||||
qapi-schema += union-branch-case.json
|
||||
qapi-schema += union-branch-if-invalid.json
|
||||
qapi-schema += union-branch-invalid-dict.json
|
||||
qapi-schema += union-clash-branches.json
|
||||
qapi-schema += union-empty.json
|
||||
|
1
tests/qapi-schema/alternate-branch-if-invalid.err
Normal file
1
tests/qapi-schema/alternate-branch-if-invalid.err
Normal file
@ -0,0 +1 @@
|
||||
tests/qapi-schema/alternate-branch-if-invalid.json:2: 'if' condition ' ' makes no sense
|
3
tests/qapi-schema/alternate-branch-if-invalid.json
Normal file
3
tests/qapi-schema/alternate-branch-if-invalid.json
Normal file
@ -0,0 +1,3 @@
|
||||
# Cover alternative with invalid 'if'
|
||||
{ 'alternate': 'Alt',
|
||||
'data': { 'branch': { 'type': 'int', 'if': ' ' } } }
|
@ -1 +1 @@
|
||||
tests/qapi-schema/alternate-empty.json:2: Alternate 'Alt' should have at least two branches in 'data'
|
||||
tests/qapi-schema/alternate-empty.json:2: Alternate 'Alt' cannot have empty 'data'
|
||||
|
@ -1,2 +1,2 @@
|
||||
# alternates must list at least two types to be useful
|
||||
{ 'alternate': 'Alt', 'data': { 'i': 'int' } }
|
||||
# alternates cannot be empty
|
||||
{ 'alternate': 'Alt', 'data': { } }
|
||||
|
@ -1 +0,0 @@
|
||||
tests/qapi-schema/args-boxed-empty.json:3: Cannot use 'boxed' with empty type
|
@ -1,3 +0,0 @@
|
||||
# 'boxed' requires a non-empty type
|
||||
{ 'struct': 'Empty', 'data': {} }
|
||||
{ 'command': 'foo', 'boxed': true, 'data': 'Empty' }
|
@ -1 +1 @@
|
||||
tests/qapi-schema/args-invalid.json:1: 'data' for command 'foo' should be a dictionary or type name
|
||||
tests/qapi-schema/args-invalid.json:1: 'data' for command 'foo' should be an object or type name
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/bad-if-list.json:2: 'if' condition '' makes no sense
|
||||
tests/qapi-schema/bad-if-list.json:2: 'if' condition ' ' makes no sense
|
||||
|
@ -1,3 +1,3 @@
|
||||
# check invalid 'if' content
|
||||
{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
|
||||
'if': ['foo', ''] }
|
||||
'if': ['foo', ' '] }
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/bad-type-int.json:3:13: Stray "1"
|
||||
tests/qapi-schema/bad-type-int.json:3:13: Stray '123'
|
||||
|
@ -1,3 +1,3 @@
|
||||
# we reject an expression with a metatype that is not a string
|
||||
# FIXME: once the parser understands integer inputs, improve the error message
|
||||
{ 'struct': 1, 'data': { } }
|
||||
{ 'struct': 123, 'data': { } }
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/doc-missing-colon.json:4:1: Line should end with :
|
||||
tests/qapi-schema/doc-missing-colon.json:4:1: Line should end with ':'
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/doc-missing.json:5: Expression missing documentation comment
|
||||
tests/qapi-schema/doc-missing.json:5: Definition missing documentation comment
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/doc-no-symbol.json:3: Expression documentation required
|
||||
tests/qapi-schema/doc-no-symbol.json:3: Definition documentation required
|
||||
|
@ -1 +0,0 @@
|
||||
tests/qapi-schema/double-data.json:2:41: Duplicate key "data"
|
@ -1,2 +0,0 @@
|
||||
# we reject an expression with duplicate top-level keys
|
||||
{ 'struct': 'bar', 'data': { }, 'data': { 'string': 'str'} }
|
@ -1 +1 @@
|
||||
tests/qapi-schema/duplicate-key.json:3:10: Duplicate key "key"
|
||||
tests/qapi-schema/duplicate-key.json:3:10: Duplicate key 'key'
|
||||
|
@ -1,3 +1,3 @@
|
||||
# QAPI cannot include the same key more than once in any {}
|
||||
# Cannot include the same key more than once in any {}
|
||||
{ 'key': 'value',
|
||||
'key': 'value' }
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/enum-bad-name.json:2: Member of enum 'MyEnum' uses invalid name 'not^possible'
|
||||
tests/qapi-schema/enum-bad-name.json:3: Member of enum 'MyEnum' uses invalid name 'not\possible'
|
||||
|
@ -1,2 +1,3 @@
|
||||
# we ensure all enum names can map to C
|
||||
{ 'enum': 'MyEnum', 'data': [ 'not^possible' ] }
|
||||
# FIXME reports 'not\possible' instead of 'not\\possible'
|
||||
{ 'enum': 'MyEnum', 'data': [ 'not\\possible' ] }
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/enum-clash-member.json:2: 'one_two' (member of MyEnum) collides with 'one-two' (member of MyEnum)
|
||||
tests/qapi-schema/enum-clash-member.json:2: 'one_two' (value of MyEnum) collides with 'one-two' (value of MyEnum)
|
||||
|
@ -1,2 +1,2 @@
|
||||
tests/qapi-schema/enum-dict-member-unknown.json:2: Unknown key 'bad-key' in dictionary member of enum 'MyEnum'
|
||||
tests/qapi-schema/enum-dict-member-unknown.json:2: Unknown key 'bad-key' in member of enum 'MyEnum'
|
||||
Valid keys are 'if', 'name'.
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/enum-int-member.json:3:31: Stray "1"
|
||||
tests/qapi-schema/enum-int-member.json:3:31: Stray '1'
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/enum-member-case.json:4: 'Value' (member of NoWayThisWillGetWhitelisted) should not use uppercase
|
||||
tests/qapi-schema/enum-member-case.json:4: 'Value' (value of NoWayThisWillGetWhitelisted) should not use uppercase
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/escape-outside-string.json:3:27: Stray "\"
|
||||
tests/qapi-schema/escape-outside-string.json:3:27: Stray '\'
|
||||
|
@ -1,3 +0,0 @@
|
||||
# escape sequences are permitted only inside strings
|
||||
# { 'command': 'foo', 'data': {} }
|
||||
{ 'command': 'foo', 'data'\u003a{} }
|
@ -1 +0,0 @@
|
||||
tests/qapi-schema/escape-too-big.json:3:14: For now, \u escape only supports non-zero values up to \u007f
|
@ -1,3 +0,0 @@
|
||||
# we don't support full Unicode strings, yet
|
||||
# { 'command': 'é' }
|
||||
{ 'command': '\u00e9' }
|
@ -1 +0,0 @@
|
||||
tests/qapi-schema/escape-too-short.json:3:14: \u escape needs 4 hex digits
|
@ -1,3 +0,0 @@
|
||||
# the \u escape requires 4 hex digits
|
||||
# { 'command': 'a' }
|
||||
{ 'command': '\u61' }
|
1
tests/qapi-schema/features-if-invalid.err
Normal file
1
tests/qapi-schema/features-if-invalid.err
Normal file
@ -0,0 +1 @@
|
||||
tests/qapi-schema/features-if-invalid.json:2: 'if' condition must be a string or a list of strings
|
4
tests/qapi-schema/features-if-invalid.json
Normal file
4
tests/qapi-schema/features-if-invalid.json
Normal file
@ -0,0 +1,4 @@
|
||||
# Cover feature with invalid 'if'
|
||||
{ 'struct': 'Stru',
|
||||
'data': {},
|
||||
'features': [{'name': 'f', 'if': false }] }
|
1
tests/qapi-schema/flat-union-discriminator-bad-name.err
Normal file
1
tests/qapi-schema/flat-union-discriminator-bad-name.err
Normal file
@ -0,0 +1 @@
|
||||
tests/qapi-schema/flat-union-discriminator-bad-name.json:7: Discriminator of flat union 'MyUnion' does not allow optional name '*switch'
|
11
tests/qapi-schema/flat-union-discriminator-bad-name.json
Normal file
11
tests/qapi-schema/flat-union-discriminator-bad-name.json
Normal file
@ -0,0 +1,11 @@
|
||||
# discriminator '*switch' isn't a member of base, 'switch' is
|
||||
# reports "does not allow optional name", which is good enough
|
||||
{ 'enum': 'Enum', 'data': [ 'one', 'two' ] }
|
||||
{ 'struct': 'Base',
|
||||
'data': { '*switch': 'Enum' } }
|
||||
{ 'struct': 'Branch', 'data': { 'name': 'str' } }
|
||||
{ 'union': 'MyUnion',
|
||||
'base': 'Base',
|
||||
'discriminator': '*switch',
|
||||
'data': { 'one': 'Branch',
|
||||
'two': 'Branch' } }
|
@ -1 +1 @@
|
||||
tests/qapi-schema/flat-union-empty.json:4: Union 'Union' cannot have empty 'data'
|
||||
tests/qapi-schema/flat-union-empty.json:4: Union 'Union' has no branches
|
||||
|
@ -1,4 +1,4 @@
|
||||
# flat unions cannot be empty
|
||||
# flat union discriminator cannot be empty
|
||||
{ 'enum': 'Empty', 'data': [ ] }
|
||||
{ 'struct': 'Base', 'data': { 'type': 'Empty' } }
|
||||
{ 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } }
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/flat-union-invalid-discriminator.json:13: Discriminator 'enum_wrong' is not a member of base struct 'TestBase'
|
||||
tests/qapi-schema/flat-union-invalid-discriminator.json:10: Discriminator 'enum_wrong' is not a member of 'base'
|
||||
|
@ -1,9 +1,6 @@
|
||||
{ 'enum': 'TestEnum',
|
||||
'data': [ 'value1', 'value2' ] }
|
||||
|
||||
{ 'struct': 'TestBase',
|
||||
'data': { 'enum1': 'TestEnum' } }
|
||||
|
||||
{ 'struct': 'TestTypeA',
|
||||
'data': { 'string': 'str' } }
|
||||
|
||||
@ -11,7 +8,7 @@
|
||||
'data': { 'integer': 'int' } }
|
||||
|
||||
{ 'union': 'TestUnion',
|
||||
'base': 'TestBase',
|
||||
'base': { 'enum1': 'TestEnum' },
|
||||
'discriminator': 'enum_wrong',
|
||||
'data': { 'value1': 'TestTypeA',
|
||||
'value2': 'TestTypeB' } }
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/flat-union-invalid-if-discriminator.json:13: The discriminator TestBase.enum1 for union TestUnion must not be conditional
|
||||
tests/qapi-schema/flat-union-invalid-if-discriminator.json:10: The discriminator 'enum1' for union TestUnion must not be conditional
|
||||
|
@ -1,9 +1,6 @@
|
||||
{ 'enum': 'TestEnum',
|
||||
'data': [ 'value1', 'value2' ] }
|
||||
|
||||
{ 'struct': 'TestBase',
|
||||
'data': { 'enum1': { 'type': 'TestEnum', 'if': 'FOO' } } }
|
||||
|
||||
{ 'struct': 'TestTypeA',
|
||||
'data': { 'string': 'str' } }
|
||||
|
||||
@ -11,7 +8,7 @@
|
||||
'data': { 'integer': 'int' } }
|
||||
|
||||
{ 'union': 'TestUnion',
|
||||
'base': 'TestBase',
|
||||
'base': { 'enum1': { 'type': 'TestEnum', 'if': 'FOO' } },
|
||||
'discriminator': 'enum1',
|
||||
'data': { 'value1': 'TestTypeA',
|
||||
'value2': 'TestTypeB' } }
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/flat-union-optional-discriminator.json:6: Discriminator of flat union 'MyUnion' does not allow optional name '*switch'
|
||||
tests/qapi-schema/flat-union-optional-discriminator.json:7: Discriminator 'switch' is not a member of 'base'
|
||||
|
@ -1,10 +1,11 @@
|
||||
# we require the discriminator to be non-optional
|
||||
# FIXME reports "discriminator 'switch' is not a member of base struct 'Base'"
|
||||
{ 'enum': 'Enum', 'data': [ 'one', 'two' ] }
|
||||
{ 'struct': 'Base',
|
||||
'data': { '*switch': 'Enum' } }
|
||||
{ 'struct': 'Branch', 'data': { 'name': 'str' } }
|
||||
{ 'union': 'MyUnion',
|
||||
'base': 'Base',
|
||||
'discriminator': '*switch',
|
||||
'discriminator': 'switch',
|
||||
'data': { 'one': 'Branch',
|
||||
'two': 'Branch' } }
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/funny-char.json:2:36: Stray ";"
|
||||
tests/qapi-schema/funny-char.json:2:36: Stray ';'
|
||||
|
1
tests/qapi-schema/funny-word.err
Normal file
1
tests/qapi-schema/funny-word.err
Normal file
@ -0,0 +1 @@
|
||||
tests/qapi-schema/funny-word.json:1:3: Stray 'command'
|
1
tests/qapi-schema/funny-word.json
Normal file
1
tests/qapi-schema/funny-word.json
Normal file
@ -0,0 +1 @@
|
||||
{ command: 'foo' }
|
@ -0,0 +1 @@
|
||||
tests/qapi-schema/ident-with-escape.json:3:3: Unknown escape \u
|
@ -1 +1 @@
|
||||
0
|
||||
1
|
||||
|
@ -1,4 +1,4 @@
|
||||
# we allow escape sequences in strings, if they map back to ASCII
|
||||
# we don't recognize any \ escapes other than \\ (tested elsewhere)
|
||||
# { 'command': 'fooA', 'data': { 'bar1': 'str' } }
|
||||
{ 'c\u006fmmand': '\u0066\u006f\u006FA',
|
||||
'd\u0061ta': { '\u0062\u0061\u00721': '\u0073\u0074\u0072' } }
|
||||
|
@ -1,16 +0,0 @@
|
||||
module None
|
||||
object q_empty
|
||||
enum QType
|
||||
prefix QTYPE
|
||||
member none
|
||||
member qnull
|
||||
member qnum
|
||||
member qstring
|
||||
member qdict
|
||||
member qlist
|
||||
member qbool
|
||||
module ident-with-escape.json
|
||||
object q_obj_fooA-arg
|
||||
member bar1: str optional=False
|
||||
command fooA q_obj_fooA-arg -> None
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
@ -1 +1 @@
|
||||
tests/qapi-schema/include-before-err.json:2:13: Expected ":"
|
||||
tests/qapi-schema/include-before-err.json:2:13: Expected ':'
|
||||
|
@ -1 +0,0 @@
|
||||
tests/qapi-schema/include-format-err.json:1: Invalid 'include' directive
|
@ -1,2 +0,0 @@
|
||||
{ 'include': 'include-simple-sub.json',
|
||||
'foo': 'bar' }
|
@ -1,2 +1,2 @@
|
||||
In file included from tests/qapi-schema/include-nested-err.json:1:
|
||||
tests/qapi-schema/missing-colon.json:1:10: Expected ":"
|
||||
tests/qapi-schema/missing-colon.json:1:10: Expected ':'
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/leading-comma-list.json:2:13: Expected "{", "[", "]", string, boolean or "null"
|
||||
tests/qapi-schema/leading-comma-list.json:2:13: Expected '{', '[', ']', string, boolean or 'null'
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/leading-comma-object.json:1:3: Expected string or "}"
|
||||
tests/qapi-schema/leading-comma-object.json:1:3: Expected string or '}'
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/missing-colon.json:1:10: Expected ":"
|
||||
tests/qapi-schema/missing-colon.json:1:10: Expected ':'
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/missing-comma-list.json:2:20: Expected "," or "]"
|
||||
tests/qapi-schema/missing-comma-list.json:2:20: Expected ',' or ']'
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/missing-comma-object.json:2:3: Expected "," or "}"
|
||||
tests/qapi-schema/missing-comma-object.json:2:3: Expected ',' or '}'
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/non-objects.json:1:1: Expected "{"
|
||||
tests/qapi-schema/non-objects.json:1:1: Expected '{'
|
||||
|
@ -1,3 +1,3 @@
|
||||
# 'name-case-whitelist' must be list of strings
|
||||
|
||||
{ 'pragma': { 'name-case-whitelist': null } }
|
||||
{ 'pragma': { 'name-case-whitelist': false } }
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/pragma-non-dict.json:3: Value of 'pragma' must be a dictionary
|
||||
tests/qapi-schema/pragma-non-dict.json:3: Value of 'pragma' must be an object
|
||||
|
1
tests/qapi-schema/pragma-unknown.err
Normal file
1
tests/qapi-schema/pragma-unknown.err
Normal file
@ -0,0 +1 @@
|
||||
tests/qapi-schema/pragma-unknown.json:1: Unknown pragma 'no-such-pragma'
|
1
tests/qapi-schema/pragma-unknown.json
Normal file
1
tests/qapi-schema/pragma-unknown.json
Normal file
@ -0,0 +1 @@
|
||||
{ 'pragma': { 'no-such-pragma': false } }
|
@ -25,6 +25,11 @@
|
||||
{ 'struct': 'Empty1', 'data': { } }
|
||||
{ 'struct': 'Empty2', 'base': 'Empty1', 'data': { } }
|
||||
|
||||
# Likewise for an empty flat union
|
||||
{ 'union': 'Union',
|
||||
'base': { 'type': 'EnumOne' }, 'discriminator': 'type',
|
||||
'data': { } }
|
||||
|
||||
{ 'command': 'user_def_cmd0', 'data': 'Empty2', 'returns': 'Empty2' }
|
||||
|
||||
# for testing override of default naming heuristic
|
||||
@ -149,6 +154,7 @@
|
||||
{ 'command': 'guest-sync', 'data': { 'arg': 'any' }, 'returns': 'any' }
|
||||
{ 'command': 'boxed-struct', 'boxed': true, 'data': 'UserDefZero' }
|
||||
{ 'command': 'boxed-union', 'data': 'UserDefListUnion', 'boxed': true }
|
||||
{ 'command': 'boxed-empty', 'boxed': true, 'data': 'Empty1' }
|
||||
|
||||
# Smoke test on out-of-band and allow-preconfig-test
|
||||
{ 'command': 'test-flags-command', 'allow-oob': true, 'allow-preconfig': true }
|
||||
@ -180,23 +186,26 @@
|
||||
{ 'event': 'EVENT_D',
|
||||
'data': { 'a' : 'EventStructOne', 'b' : 'str', '*c': 'str', '*enum3': 'EnumOne' } }
|
||||
{ 'event': 'EVENT_E', 'boxed': true, 'data': 'UserDefZero' }
|
||||
{ 'event': 'EVENT_F', 'boxed': true, 'data': 'UserDefAlternate' }
|
||||
{ 'event': 'EVENT_F', 'boxed': true, 'data': 'UserDefFlatUnion' }
|
||||
{ 'event': 'EVENT_G', 'boxed': true, 'data': 'Empty1' }
|
||||
|
||||
# test that we correctly compile downstream extensions, as well as munge
|
||||
# ticklish names
|
||||
# also test union and alternate with just one branch
|
||||
{ 'enum': '__org.qemu_x-Enum', 'data': [ '__org.qemu_x-value' ] }
|
||||
{ 'struct': '__org.qemu_x-Base',
|
||||
'data': { '__org.qemu_x-member1': '__org.qemu_x-Enum' } }
|
||||
{ 'struct': '__org.qemu_x-Struct', 'base': '__org.qemu_x-Base',
|
||||
'data': { '__org.qemu_x-member2': 'str', '*wchar-t': 'int' } }
|
||||
{ 'union': '__org.qemu_x-Union1', 'data': { '__org.qemu_x-branch': 'str' } }
|
||||
{ 'alternate': '__org.qemu_x-Alt1', 'data': { '__org.qemu_x-branch': 'str' } }
|
||||
{ 'struct': '__org.qemu_x-Struct2',
|
||||
'data': { 'array': ['__org.qemu_x-Union1'] } }
|
||||
{ 'union': '__org.qemu_x-Union2', 'base': '__org.qemu_x-Base',
|
||||
'discriminator': '__org.qemu_x-member1',
|
||||
'data': { '__org.qemu_x-value': '__org.qemu_x-Struct2' } }
|
||||
{ 'alternate': '__org.qemu_x-Alt',
|
||||
'data': { '__org.qemu_x-branch': 'str', 'b': '__org.qemu_x-Base' } }
|
||||
'data': { '__org.qemu_x-branch': '__org.qemu_x-Base' } }
|
||||
{ 'event': '__ORG.QEMU_X-EVENT', 'data': '__org.qemu_x-Struct' }
|
||||
{ 'command': '__org.qemu_x-command',
|
||||
'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'],
|
||||
|
@ -23,6 +23,15 @@ enum MyEnum
|
||||
object Empty1
|
||||
object Empty2
|
||||
base Empty1
|
||||
object q_obj_Union-base
|
||||
member type: EnumOne optional=False
|
||||
object Union
|
||||
base q_obj_Union-base
|
||||
tag type
|
||||
case value1: q_empty
|
||||
case value2: q_empty
|
||||
case value3: q_empty
|
||||
case value4: q_empty
|
||||
command user_def_cmd0 Empty2 -> Empty2
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
enum QEnumTwo
|
||||
@ -221,6 +230,8 @@ command boxed-struct UserDefZero -> None
|
||||
gen=True success_response=True boxed=True oob=False preconfig=False
|
||||
command boxed-union UserDefListUnion -> None
|
||||
gen=True success_response=True boxed=True oob=False preconfig=False
|
||||
command boxed-empty Empty1 -> None
|
||||
gen=True success_response=True boxed=True oob=False preconfig=False
|
||||
command test-flags-command None -> None
|
||||
gen=True success_response=True boxed=False oob=True preconfig=True
|
||||
object UserDefOptions
|
||||
@ -252,7 +263,9 @@ event EVENT_D q_obj_EVENT_D-arg
|
||||
boxed=False
|
||||
event EVENT_E UserDefZero
|
||||
boxed=True
|
||||
event EVENT_F UserDefAlternate
|
||||
event EVENT_F UserDefFlatUnion
|
||||
boxed=True
|
||||
event EVENT_G Empty1
|
||||
boxed=True
|
||||
enum __org.qemu_x-Enum
|
||||
member __org.qemu_x-value
|
||||
@ -270,6 +283,9 @@ object __org.qemu_x-Union1
|
||||
member type: __org.qemu_x-Union1Kind optional=False
|
||||
tag type
|
||||
case __org.qemu_x-branch: q_obj_str-wrapper
|
||||
alternate __org.qemu_x-Alt1
|
||||
tag type
|
||||
case __org.qemu_x-branch: str
|
||||
array __org.qemu_x-Union1List __org.qemu_x-Union1
|
||||
object __org.qemu_x-Struct2
|
||||
member array: __org.qemu_x-Union1List optional=False
|
||||
@ -279,8 +295,7 @@ object __org.qemu_x-Union2
|
||||
case __org.qemu_x-value: __org.qemu_x-Struct2
|
||||
alternate __org.qemu_x-Alt
|
||||
tag type
|
||||
case __org.qemu_x-branch: str
|
||||
case b: __org.qemu_x-Base
|
||||
case __org.qemu_x-branch: __org.qemu_x-Base
|
||||
event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
|
||||
boxed=False
|
||||
array __org.qemu_x-EnumList __org.qemu_x-Enum
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/quoted-structural-chars.json:1:1: Expected "{"
|
||||
tests/qapi-schema/quoted-structural-chars.json:1:1: Expected '{'
|
||||
|
1
tests/qapi-schema/string-code-point-127.err
Normal file
1
tests/qapi-schema/string-code-point-127.err
Normal file
@ -0,0 +1 @@
|
||||
tests/qapi-schema/string-code-point-127.json:2:14: Funny character in string
|
2
tests/qapi-schema/string-code-point-127.json
Normal file
2
tests/qapi-schema/string-code-point-127.json
Normal file
@ -0,0 +1,2 @@
|
||||
# We accept printable ASCII: code points 32..126. Test code point 127:
|
||||
{ 'command': '' }
|
1
tests/qapi-schema/string-code-point-31.err
Normal file
1
tests/qapi-schema/string-code-point-31.err
Normal file
@ -0,0 +1 @@
|
||||
tests/qapi-schema/string-code-point-31.json:2:14: Funny character in string
|
2
tests/qapi-schema/string-code-point-31.json
Normal file
2
tests/qapi-schema/string-code-point-31.json
Normal file
@ -0,0 +1,2 @@
|
||||
# We accept printable ASCII: code points 32..126. Test code point 127:
|
||||
{ 'command': '' }
|
@ -1 +1 @@
|
||||
tests/qapi-schema/struct-data-invalid.json:1: 'data' for struct 'foo' should be a dictionary or type name
|
||||
tests/qapi-schema/struct-data-invalid.json:1: 'data' for struct 'foo' should be an object or type name
|
||||
|
1
tests/qapi-schema/struct-member-if-invalid.err
Normal file
1
tests/qapi-schema/struct-member-if-invalid.err
Normal file
@ -0,0 +1 @@
|
||||
tests/qapi-schema/struct-member-if-invalid.json:2: 'if' condition must be a string or a list of strings
|
1
tests/qapi-schema/struct-member-if-invalid.exit
Normal file
1
tests/qapi-schema/struct-member-if-invalid.exit
Normal file
@ -0,0 +1 @@
|
||||
1
|
3
tests/qapi-schema/struct-member-if-invalid.json
Normal file
3
tests/qapi-schema/struct-member-if-invalid.json
Normal file
@ -0,0 +1,3 @@
|
||||
# Cover member with invalid 'if'
|
||||
{ 'struct': 'Stru',
|
||||
'data': { 'member': { 'type': 'int', 'if': true } } }
|
0
tests/qapi-schema/struct-member-if-invalid.out
Normal file
0
tests/qapi-schema/struct-member-if-invalid.out
Normal file
@ -1 +1 @@
|
||||
tests/qapi-schema/trailing-comma-list.json:2:36: Expected "{", "[", string, boolean or "null"
|
||||
tests/qapi-schema/trailing-comma-list.json:2:36: Expected '{', '[', string, boolean or 'null'
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/unclosed-list.json:1:20: Expected "," or "]"
|
||||
tests/qapi-schema/unclosed-list.json:1:20: Expected ',' or ']'
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/unclosed-object.json:1:21: Expected "," or "}"
|
||||
tests/qapi-schema/unclosed-object.json:1:21: Expected ',' or '}'
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user