QAPI patches patches for 2021-02-08

-----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmAhQpISHGFybWJydUBy
 ZWRoYXQuY29tAAoJEDhwtADrkYZTBFYP/jh1x1Isn35q3jwjzKy6N3EYbzmaRKhW
 rc5bFlZLQ95Nso+Q3b8izUSeoGz7t8E+WLZBBxzNoOWBS2uC8HS0jIpUmCJaB+Yu
 aVrG70+5/s/BPTX7iF6LIrcRj3GIQdFEWR5Zn1V4PFk5G7NZFwEiTnViq8pLw87H
 c2ktAorDyH6Zl4DA2YjV0XBLPMclt53sQ/M5b6ythUq6E05bVUkQFiUm3N8joIEX
 2djwumVi/dYpDwR/pVPBjPXcP5gc44y4D9sjJU6I16kyCyKi8Tr9mmEcSJFmR/Y/
 GdSilmtFhxUikAQogZwi/48BhR0GawhgcKZP5IkKNjvfwqE13Vhx8/p0pEubFPUE
 YexvFqkSmBRZ1mT0QpCcG4lp+u6PzhTyc/gbWwPm42/T+x9fG0cDgvDZCPjIRSsg
 LiUmmqrwOXr+Lw6GP1Q0f0KKv5QhCfeq1YcYrEXTQsa1PDT5T8ARBzxR5O1X2UNR
 Xw7j4u9R63p6P5nOk5+wwRLQkUkGl7N0SYqe4thyHUfW4r48V5J9RT7ONKD2CXO9
 Dw/Q3Ga1GmHaydpoZ4Az1k5kyr5dVBbAISRRWRpYA0sneg85o3RU3aTMt3r43pzC
 5pjeSpx6v7K4Y3NJPL1e/j/qJZq10WtEslkF/TKcBS2qLgiKCZ1oXQPORQxxX9uK
 zuK8oPQR7W42
 =uLm+
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2021-02-08' into staging

QAPI patches patches for 2021-02-08

# gpg: Signature made Mon 08 Feb 2021 13:54:26 GMT
# 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-2021-02-08:
  qapi: enable strict-optional checks
  qapi: type 'info' as Optional[QAPISourceInfo]
  qapi/gen: Drop support for QAPIGen without a file name
  qapi/commands: Simplify command registry generation
  qapi/gen: Support switching to another module temporarily
  qapi/gen: write _genc/_genh access shims
  qapi: centralize the built-in module name definition
  qapi/gen: Combine ._add_[user|system]_module
  qapi: use './builtin' as the built-in module name
  qapi: use explicitly internal module names
  qapi/gen: Replace ._begin_system_module()
  qapi: centralize is_[user|system|builtin]_module methods
  qapi/gen: inline _wrap_ifcond into end_if()
  qapi/main: handle theoretical None-return from re.match()
  qapi/events: fix visit_event typing
  qapi/commands: assert arg_type is not None

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-02-08 16:12:20 +00:00
commit 4f799257b3
16 changed files with 139 additions and 104 deletions

View File

@ -23,7 +23,6 @@ from typing import (
from .common import c_name, mcgen
from .gen import (
QAPIGenC,
QAPIGenCCode,
QAPISchemaModularCVisitor,
build_params,
ifcontext,
@ -126,6 +125,9 @@ def gen_marshal(name: str,
boxed: bool,
ret_type: Optional[QAPISchemaType]) -> str:
have_args = boxed or (arg_type and not arg_type.is_empty())
if have_args:
assert arg_type is not None
arg_type_c_name = arg_type.c_name()
ret = mcgen('''
@ -147,7 +149,7 @@ def gen_marshal(name: str,
ret += mcgen('''
%(c_name)s arg = {0};
''',
c_name=arg_type.c_name())
c_name=arg_type_c_name)
ret += mcgen('''
@ -163,7 +165,7 @@ def gen_marshal(name: str,
ok = visit_check_struct(v, errp);
}
''',
c_arg_type=arg_type.c_name())
c_arg_type=arg_type_c_name)
else:
ret += mcgen('''
ok = visit_check_struct(v, errp);
@ -193,7 +195,7 @@ out:
ret += mcgen('''
visit_type_%(c_arg_type)s_members(v, &arg, NULL);
''',
c_arg_type=arg_type.c_name())
c_arg_type=arg_type_c_name)
ret += mcgen('''
visit_end_struct(v, NULL);
@ -234,28 +236,11 @@ def gen_register_command(name: str,
return ret
def gen_registry(registry: str, prefix: str) -> str:
ret = mcgen('''
void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
{
QTAILQ_INIT(cmds);
''',
c_prefix=c_name(prefix, protect=False))
ret += registry
ret += mcgen('''
}
''')
return ret
class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
def __init__(self, prefix: str):
super().__init__(
prefix, 'qapi-commands',
' * Schema-defined QAPI/QMP commands', None, __doc__)
self._regy = QAPIGenCCode(None)
self._visited_ret_types: Dict[QAPIGenC, Set[QAPISchemaType]] = {}
def _begin_user_module(self, name: str) -> None:
@ -282,25 +267,36 @@ class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
''',
types=types))
def visit_end(self) -> None:
self._add_system_module('init', ' * QAPI Commands initialization')
def visit_begin(self, schema: QAPISchema) -> None:
self._add_module('./init', ' * QAPI Commands initialization')
self._genh.add(mcgen('''
#include "qapi/qmp/dispatch.h"
void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
''',
c_prefix=c_name(self._prefix, protect=False)))
self._genc.preamble_add(mcgen('''
self._genc.add(mcgen('''
#include "qemu/osdep.h"
#include "%(prefix)sqapi-commands.h"
#include "%(prefix)sqapi-init-commands.h"
void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
{
QTAILQ_INIT(cmds);
''',
prefix=self._prefix))
self._genc.add(gen_registry(self._regy.get_content(), self._prefix))
prefix=self._prefix,
c_prefix=c_name(self._prefix, protect=False)))
def visit_end(self) -> None:
with self._temp_module('./init'):
self._genc.add(mcgen('''
}
'''))
def visit_command(self,
name: str,
info: QAPISourceInfo,
info: Optional[QAPISourceInfo],
ifcond: List[str],
features: List[QAPISchemaFeature],
arg_type: Optional[QAPISchemaObjectType],
@ -321,13 +317,15 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
if ret_type and ret_type not in self._visited_ret_types[self._genc]:
self._visited_ret_types[self._genc].add(ret_type)
with ifcontext(ret_type.ifcond,
self._genh, self._genc, self._regy):
self._genh, self._genc):
self._genc.add(gen_marshal_output(ret_type))
with ifcontext(ifcond, self._genh, self._genc, self._regy):
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
self._genh.add(gen_marshal_decl(name))
self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
self._regy.add(gen_register_command(name, success_response,
with self._temp_module('./init'):
with ifcontext(ifcond, self._genh, self._genc):
self._genc.add(gen_register_command(name, success_response,
allow_oob, allow_preconfig,
coroutine))

View File

@ -12,7 +12,7 @@ This work is licensed under the terms of the GNU GPL, version 2.
See the COPYING file in the top-level directory.
"""
from typing import List
from typing import List, Optional
from .common import c_enum_const, c_name, mcgen
from .gen import QAPISchemaModularCVisitor, build_params, ifcontext
@ -27,7 +27,7 @@ from .types import gen_enum, gen_enum_lookup
def build_event_send_proto(name: str,
arg_type: QAPISchemaObjectType,
arg_type: Optional[QAPISchemaObjectType],
boxed: bool) -> str:
return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
'c_name': c_name(name.lower()),
@ -35,7 +35,7 @@ def build_event_send_proto(name: str,
def gen_event_send_decl(name: str,
arg_type: QAPISchemaObjectType,
arg_type: Optional[QAPISchemaObjectType],
boxed: bool) -> str:
return mcgen('''
@ -78,7 +78,7 @@ def gen_param_var(typ: QAPISchemaObjectType) -> str:
def gen_event_send(name: str,
arg_type: QAPISchemaObjectType,
arg_type: Optional[QAPISchemaObjectType],
boxed: bool,
event_enum_name: str,
event_emit: str) -> str:
@ -99,6 +99,7 @@ def gen_event_send(name: str,
proto=build_event_send_proto(name, arg_type, boxed))
if have_args:
assert arg_type is not None
ret += mcgen('''
QObject *obj;
Visitor *v;
@ -114,6 +115,7 @@ def gen_event_send(name: str,
name=name)
if have_args:
assert arg_type is not None
ret += mcgen('''
v = qobject_output_visitor_new(&obj);
''')
@ -189,7 +191,7 @@ class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor):
types=types))
def visit_end(self) -> None:
self._add_system_module('emit', ' * QAPI Events emission')
self._add_module('./emit', ' * QAPI Events emission')
self._genc.preamble_add(mcgen('''
#include "qemu/osdep.h"
#include "%(prefix)sqapi-emit-events.h"
@ -211,10 +213,10 @@ void %(event_emit)s(%(event_enum)s event, QDict *qdict);
def visit_event(self,
name: str,
info: QAPISourceInfo,
info: Optional[QAPISourceInfo],
ifcond: List[str],
features: List[QAPISchemaFeature],
arg_type: QAPISchemaObjectType,
arg_type: Optional[QAPISchemaObjectType],
boxed: bool) -> None:
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_event_send_decl(name, arg_type, boxed))

View File

@ -31,12 +31,16 @@ from .common import (
guardstart,
mcgen,
)
from .schema import QAPISchemaObjectType, QAPISchemaVisitor
from .schema import (
QAPISchemaModule,
QAPISchemaObjectType,
QAPISchemaVisitor,
)
from .source import QAPISourceInfo
class QAPIGen:
def __init__(self, fname: Optional[str]):
def __init__(self, fname: str):
self.fname = fname
self._preamble = ''
self._body = ''
@ -121,7 +125,7 @@ def build_params(arg_type: Optional[QAPISchemaObjectType],
class QAPIGenCCode(QAPIGen):
def __init__(self, fname: Optional[str]):
def __init__(self, fname: str):
super().__init__(fname)
self._start_if: Optional[Tuple[List[str], str, str]] = None
@ -130,15 +134,12 @@ class QAPIGenCCode(QAPIGen):
self._start_if = (ifcond, self._body, self._preamble)
def end_if(self) -> None:
assert self._start_if
self._wrap_ifcond()
self._start_if = None
def _wrap_ifcond(self) -> None:
assert self._start_if is not None
self._body = _wrap_ifcond(self._start_if[0],
self._start_if[1], self._body)
self._preamble = _wrap_ifcond(self._start_if[0],
self._start_if[2], self._preamble)
self._start_if = None
def get_content(self) -> str:
assert self._start_if is None
@ -243,85 +244,88 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor):
self._user_blurb = user_blurb
self._builtin_blurb = builtin_blurb
self._pydoc = pydoc
self._genc: Optional[QAPIGenC] = None
self._genh: Optional[QAPIGenH] = None
self._module: Dict[Optional[str], Tuple[QAPIGenC, QAPIGenH]] = {}
self._current_module: Optional[str] = None
self._module: Dict[str, Tuple[QAPIGenC, QAPIGenH]] = {}
self._main_module: Optional[str] = None
@staticmethod
def _is_user_module(name: Optional[str]) -> bool:
return bool(name and not name.startswith('./'))
@property
def _genc(self) -> QAPIGenC:
assert self._current_module is not None
return self._module[self._current_module][0]
@property
def _genh(self) -> QAPIGenH:
assert self._current_module is not None
return self._module[self._current_module][1]
@staticmethod
def _is_builtin_module(name: Optional[str]) -> bool:
return not name
def _module_dirname(self, name: Optional[str]) -> str:
if self._is_user_module(name):
def _module_dirname(name: str) -> str:
if QAPISchemaModule.is_user_module(name):
return os.path.dirname(name)
return ''
def _module_basename(self, what: str, name: Optional[str]) -> str:
ret = '' if self._is_builtin_module(name) else self._prefix
if self._is_user_module(name):
def _module_basename(self, what: str, name: str) -> str:
ret = '' if QAPISchemaModule.is_builtin_module(name) else self._prefix
if QAPISchemaModule.is_user_module(name):
basename = os.path.basename(name)
ret += what
if name != self._main_module:
ret += '-' + os.path.splitext(basename)[0]
else:
name = name[2:] if name else 'builtin'
ret += re.sub(r'-', '-' + name + '-', what)
assert QAPISchemaModule.is_system_module(name)
ret += re.sub(r'-', '-' + name[2:] + '-', what)
return ret
def _module_filename(self, what: str, name: Optional[str]) -> str:
def _module_filename(self, what: str, name: str) -> str:
return os.path.join(self._module_dirname(name),
self._module_basename(what, name))
def _add_module(self, name: Optional[str], blurb: str) -> None:
def _add_module(self, name: str, blurb: str) -> None:
if QAPISchemaModule.is_user_module(name):
if self._main_module is None:
self._main_module = name
basename = self._module_filename(self._what, name)
genc = QAPIGenC(basename + '.c', blurb, self._pydoc)
genh = QAPIGenH(basename + '.h', blurb, self._pydoc)
self._module[name] = (genc, genh)
self._genc, self._genh = self._module[name]
self._current_module = name
def _add_user_module(self, name: str, blurb: str) -> None:
assert self._is_user_module(name)
if self._main_module is None:
self._main_module = name
self._add_module(name, blurb)
def _add_system_module(self, name: Optional[str], blurb: str) -> None:
self._add_module(name and './' + name, blurb)
@contextmanager
def _temp_module(self, name: str) -> Iterator[None]:
old_module = self._current_module
self._current_module = name
yield
self._current_module = old_module
def write(self, output_dir: str, opt_builtins: bool = False) -> None:
for name in self._module:
if self._is_builtin_module(name) and not opt_builtins:
if QAPISchemaModule.is_builtin_module(name) and not opt_builtins:
continue
(genc, genh) = self._module[name]
genc.write(output_dir)
genh.write(output_dir)
def _begin_system_module(self, name: None) -> None:
def _begin_builtin_module(self) -> None:
pass
def _begin_user_module(self, name: str) -> None:
pass
def visit_module(self, name: Optional[str]) -> None:
if name is None:
def visit_module(self, name: str) -> None:
if QAPISchemaModule.is_builtin_module(name):
if self._builtin_blurb:
self._add_system_module(None, self._builtin_blurb)
self._begin_system_module(name)
self._add_module(name, self._builtin_blurb)
self._begin_builtin_module()
else:
# The built-in module has not been created. No code may
# be generated.
self._genc = None
self._genh = None
self._current_module = None
else:
self._add_user_module(name, self._user_blurb)
assert QAPISchemaModule.is_user_module(name)
self._add_module(name, self._user_blurb)
self._begin_user_module(name)
def visit_include(self, name: str, info: QAPISourceInfo) -> None:
def visit_include(self, name: str, info: Optional[QAPISourceInfo]) -> None:
relname = os.path.relpath(self._module_filename(self._what, name),
os.path.dirname(self._genh.fname))
self._genh.preamble_add(mcgen('''

View File

@ -23,6 +23,8 @@ from .visit import gen_visit
def invalid_prefix_char(prefix: str) -> Optional[str]:
match = re.match(r'([A-Za-z_.-][A-Za-z0-9_.-]*)?', prefix)
# match cannot be None, but mypy cannot infer that.
assert match is not None
if match.end() != len(prefix):
return prefix[match.end()]
return None

View File

@ -1,6 +1,5 @@
[mypy]
strict = True
strict_optional = False
disallow_untyped_calls = False
python_version = 3.6

View File

@ -68,7 +68,8 @@ class QAPISchemaEntity:
def _set_module(self, schema, info):
assert self._checked
self._module = schema.module_by_fname(info and info.fname)
fname = info.fname if info else QAPISchemaModule.BUILTIN_MODULE_NAME
self._module = schema.module_by_fname(fname)
self._module.add_entity(self)
def set_module(self, schema):
@ -137,10 +138,40 @@ class QAPISchemaVisitor:
class QAPISchemaModule:
BUILTIN_MODULE_NAME = './builtin'
def __init__(self, name):
self.name = name
self._entity_list = []
@staticmethod
def is_system_module(name: str) -> bool:
"""
System modules are internally defined modules.
Their names start with the "./" prefix.
"""
return name.startswith('./')
@classmethod
def is_user_module(cls, name: str) -> bool:
"""
User modules are those defined by the user in qapi JSON files.
They do not start with the "./" prefix.
"""
return not cls.is_system_module(name)
@classmethod
def is_builtin_module(cls, name: str) -> bool:
"""
The built-in module is a single System module for the built-in types.
It is always "./builtin".
"""
return name == cls.BUILTIN_MODULE_NAME
def add_entity(self, ent):
self._entity_list.append(ent)
@ -825,7 +856,7 @@ class QAPISchema:
self._entity_dict = {}
self._module_dict = OrderedDict()
self._schema_dir = os.path.dirname(fname)
self._make_module(None) # built-ins
self._make_module(QAPISchemaModule.BUILTIN_MODULE_NAME)
self._make_module(fname)
self._predefining = True
self._def_predefineds()
@ -870,9 +901,9 @@ class QAPISchema:
info, "%s uses unknown type '%s'" % (what, name))
return typ
def _module_name(self, fname):
if fname is None:
return None
def _module_name(self, fname: str) -> str:
if QAPISchemaModule.is_system_module(fname):
return fname
return os.path.relpath(fname, self._schema_dir)
def _make_module(self, fname):
@ -883,7 +914,6 @@ class QAPISchema:
def module_by_fname(self, fname):
name = self._module_name(fname)
assert name in self._module_dict
return self._module_dict[name]
def _def_include(self, expr, info, doc):

View File

@ -271,7 +271,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
prefix, 'qapi-types', ' * Schema-defined QAPI types',
' * Built-in QAPI types', __doc__)
def _begin_system_module(self, name: None) -> None:
def _begin_builtin_module(self) -> None:
self._genc.preamble_add(mcgen('''
#include "qemu/osdep.h"
#include "qapi/dealloc-visitor.h"
@ -350,7 +350,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
def visit_alternate_type(self,
name: str,
info: QAPISourceInfo,
info: Optional[QAPISourceInfo],
ifcond: List[str],
features: List[QAPISchemaFeature],
variants: QAPISchemaVariants) -> None:

View File

@ -305,7 +305,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
prefix, 'qapi-visit', ' * Schema-defined QAPI visitors',
' * Built-in QAPI visitors', __doc__)
def _begin_system_module(self, name: None) -> None:
def _begin_builtin_module(self) -> None:
self._genc.preamble_add(mcgen('''
#include "qemu/osdep.h"
#include "qapi/error.h"
@ -336,7 +336,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
def visit_enum_type(self,
name: str,
info: QAPISourceInfo,
info: Optional[QAPISourceInfo],
ifcond: List[str],
features: List[QAPISchemaFeature],
members: List[QAPISchemaEnumMember],
@ -378,7 +378,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
def visit_alternate_type(self,
name: str,
info: QAPISourceInfo,
info: Optional[QAPISourceInfo],
ifcond: List[str],
features: List[QAPISchemaFeature],
variants: QAPISchemaVariants) -> None:

View File

@ -1,4 +1,4 @@
module None
module ./builtin
object q_empty
enum QType
prefix QTYPE

View File

@ -1,4 +1,4 @@
module None
module ./builtin
object q_empty
enum QType
prefix QTYPE

View File

@ -1,4 +1,4 @@
module None
module ./builtin
object q_empty
enum QType
prefix QTYPE

View File

@ -1,4 +1,4 @@
module None
module ./builtin
object q_empty
enum QType
prefix QTYPE

View File

@ -1,4 +1,4 @@
module None
module ./builtin
object q_empty
enum QType
prefix QTYPE

View File

@ -1,4 +1,4 @@
module None
module ./builtin
object q_empty
enum QType
prefix QTYPE

View File

@ -1,4 +1,4 @@
module None
module ./builtin
object q_empty
enum QType
prefix QTYPE

View File

@ -1,4 +1,4 @@
module None
module ./builtin
object q_empty
enum QType
prefix QTYPE