Re: [PATCH v2 09/16] scripts/qapi: add QAPISchemaIfCond.rsgen()

Paolo Bonzini <[email protected]> Wed, 25 Feb 2026 08:53:57 +0100
Newsgroups org.nongnu.qemu-rust,org.nongnu.qemu-devel
Message-ID <[email protected]>
On 2/25/26 07:48, Markus Armbruster wrote:
> 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.

I think it won't work due to need_parens?  gen_ifcond is really designed 
for infix notation, I have no doubt that it *can* be made to work (for 
example pass 'all' and 'any' and prefix them after processing 
need_parens), but there is little duplication in the code other than

         if isinstance(ifcond, str):
             return cond_fmt % ifcond
         assert isinstance(ifcond, dict) and len(ifcond) == 1

because unary and n-ary operators in prefix notation are quite similar, 
unlike unary and binary operators in infix notation.

Paolo