Re: [PATCH v2 09/16] scripts/qapi: add QAPISchemaIfCond.rsgen()
Markus Armbruster <[email protected]> Wed, 25 Feb 2026 07:48:48 +0100
| Newsgroups | org.nongnu.qemu-rust,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
Paolo Bonzini <[email protected]> writes: > From: Marc-André Lureau <[email protected]> > > Generate Rust #[cfg(...)] guards from QAPI 'if' conditions; it > turns out that they are very similar, with both of them using > not/any/all, so just walk the tree. > > The next commit will put it to use. > > Signed-off-by: Marc-André Lureau <[email protected]> > Link: https://lore.kernel.org/r/[email protected] > Signed-off-by: Paolo Bonzini <[email protected]> > --- > scripts/qapi/common.py | 19 +++++++++++++++++++ > scripts/qapi/schema.py | 4 ++++ > 2 files changed, 23 insertions(+) > > diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py > index d7c8aa3365c..14d5dd259c4 100644 > --- a/scripts/qapi/common.py > +++ b/scripts/qapi/common.py > @@ -199,6 +199,25 @@ def guardend(name: str) -> str: > name=c_fname(name).upper()) > > > +def rsgen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]]) -> str: > + > + def cfg(ifcond: Union[str, Dict[str, Any]]) -> str: > + if isinstance(ifcond, str): > + return ifcond > + assert isinstance(ifcond, dict) and len(ifcond) == 1 > + if 'not' in ifcond: > + oper = 'not' > + arg = cfg(ifcond['not']) > + else: > + oper, operands = next(iter(ifcond.items())) > + arg = ', '.join([cfg(c) for c in operands]) > + return f'{oper}({arg})' > + > + if not ifcond: > + return '' > + return '#[cfg(%s)]' % cfg(ifcond) > + > + Why not reuse the existing tree walker? See appended diff. > def gen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]], > cond_fmt: str, not_fmt: str, > all_operator: str, any_operator: str) -> str: > diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py > index 8d88b40de2e..848a7401251 100644 > --- a/scripts/qapi/schema.py > +++ b/scripts/qapi/schema.py > @@ -37,6 +37,7 @@ > docgen_ifcond, > gen_endif, > gen_if, > + rsgen_ifcond, > ) > from .error import QAPIError, QAPISemError, QAPISourceError > from .expr import check_exprs > @@ -63,6 +64,9 @@ def gen_endif(self) -> str: > def docgen(self) -> str: > return docgen_ifcond(self.ifcond) > > + def rsgen(self) -> str: > + return rsgen_ifcond(self.ifcond) > + > def is_present(self) -> bool: > return bool(self.ifcond) diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index d7c8aa3365..d8accae835 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -201,7 +201,8 @@ def guardend(name: str) -> str: def gen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]], cond_fmt: str, not_fmt: str, - all_operator: str, any_operator: str) -> str: + all_fmt: str, all_sep: str, + any_fmt: str, any_sep: str) -> str: def do_gen(ifcond: Union[str, Dict[str, Any]], need_parens: bool) -> str: @@ -211,15 +212,15 @@ def do_gen(ifcond: Union[str, Dict[str, Any]], if 'not' in ifcond: return not_fmt % do_gen(ifcond['not'], True) if 'all' in ifcond: - gen = gen_infix(all_operator, ifcond['all']) + gen = gen_infix(all_fmt, all_sep, ifcond['all']) else: - gen = gen_infix(any_operator, ifcond['any']) + gen = gen_infix(any_fmt, any_sep, ifcond['any']) if need_parens: gen = '(' + gen + ')' return gen - def gen_infix(operator: str, operands: Sequence[Any]) -> str: - return operator.join([do_gen(o, True) for o in operands]) + def gen_infix(fmt: str, sep: str, operands: Sequence[Any]) -> str: + return fmt % sep.join([do_gen(o, True) for o in operands]) if not ifcond: return '' @@ -227,12 +228,18 @@ def gen_infix(operator: str, operands: Sequence[Any]) -> str: def cgen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]]) -> str: - return gen_ifcond(ifcond, 'defined(%s)', '!%s', ' && ', ' || ') + return gen_ifcond(ifcond, 'defined(%s)', '!%s', + '%s', ' && ', '%s', ' || ') + + +def rsgen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]]) -> str: + return '#[cfg(%s)]' % gen_ifcond(ifcond, '%s', 'not(%s)', + 'all(%s)', ', ', 'any(%s)', ', ') def docgen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]]) -> str: # TODO Doc generated for conditions needs polish - return gen_ifcond(ifcond, '%s', 'not %s', ' and ', ' or ') + return gen_ifcond(ifcond, '%s', 'not %s', '%s', ' and ', '%s', ' or ') def gen_if(cond: str) -> str: