diff mbox series

[04/13] qapi/introspect: hide fields in schema

Message ID 20250507231442.879619-5-pierrick.bouvier@linaro.org
State New
Headers show
Series single-binary: make QAPI generated files common | expand

Commit Message

Pierrick Bouvier May 7, 2025, 11:14 p.m. UTC
We know have a way to parse runtime conditionals in QAPI json, and hide
qlit elements at runtime.
So we can combine both to hide elements in our schema based on a
conditional specified in json.

Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
 scripts/qapi/introspect.py | 28 +++++++++++++++++++---------
 scripts/qapi/schema.py     |  3 +++
 2 files changed, 22 insertions(+), 9 deletions(-)
diff mbox series

Patch

diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index e0269bef0ce..c70b97a455d 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -94,7 +94,8 @@  class Annotated(Generic[_ValueT]):
 
 def _tree_to_qlit(obj: JSONValue,
                   level: int = 0,
-                  dict_value: bool = False) -> str:
+                  dict_value: bool = False,
+                  hidden_cond: str = '') -> str:
     """
     Convert the type tree into a QLIT C string, recursively.
 
@@ -120,7 +121,11 @@  def indent(level: int) -> str:
             ret += indent(level) + f"/* {obj.comment} */\n"
         if obj.ifcond.is_present():
             ret += obj.ifcond.gen_if()
-        ret += _tree_to_qlit(obj.value, level)
+        hidden_cond = obj.ifcond.get_runtime_cond()
+        # reverse runtime_if
+        if hidden_cond:
+            hidden_cond = '!(' + hidden_cond + ')'
+        ret += _tree_to_qlit(obj.value, level, hidden_cond=hidden_cond)
         if obj.ifcond.is_present():
             ret += '\n' + obj.ifcond.gen_endif()
         return ret
@@ -129,30 +134,35 @@  def indent(level: int) -> str:
     if not dict_value:
         ret += indent(level)
 
+    macro_suffix = ''
+    if hidden_cond:
+        macro_suffix = '_HIDDEN'
+        hidden_cond = ', (' + hidden_cond + ')'
+
     # Scalars:
     if obj is None:
         ret += 'QLIT_QNULL'
     elif isinstance(obj, str):
-        ret += f"QLIT_QSTR({to_c_string(obj)})"
+        ret += f"QLIT_QSTR{macro_suffix}({to_c_string(obj)}{hidden_cond})"
     elif isinstance(obj, bool):
-        ret += f"QLIT_QBOOL({str(obj).lower()})"
+        ret += f"QLIT_QBOOL{macro_suffix}({str(obj).lower()}{hidden_cond})"
 
     # Non-scalars:
     elif isinstance(obj, list):
-        ret += 'QLIT_QLIST(((QLitObject[]) {\n'
+        ret += 'QLIT_QLIST' + macro_suffix + '(((QLitObject[]) {\n'
         for value in obj:
             ret += _tree_to_qlit(value, level + 1).strip('\n') + '\n'
         ret += indent(level + 1) + '{}\n'
-        ret += indent(level) + '}))'
+        ret += indent(level) + '})' + hidden_cond + ')'
     elif isinstance(obj, dict):
-        ret += 'QLIT_QDICT(((QLitDictEntry[]) {\n'
+        ret += 'QLIT_QDICT' + macro_suffix + '(((QLitDictEntry[]) {\n'
         for key, value in sorted(obj.items()):
             ret += indent(level + 1) + "{{ {:s}, {:s} }},\n".format(
                 to_c_string(key),
-                _tree_to_qlit(value, level + 1, dict_value=True)
+                _tree_to_qlit(value, level + 1, dict_value=True),
             )
         ret += indent(level + 1) + '{}\n'
-        ret += indent(level) + '}))'
+        ret += indent(level) + '})' + hidden_cond + ')'
     else:
         raise NotImplementedError(
             f"type '{type(obj).__name__}' not implemented"
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index 533d0dfe088..7767893f979 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -79,6 +79,9 @@  def gen_runtime_if(self) -> str:
     def gen_runtime_endif(self) -> str:
         return gen_runtime_endif(self._cgen_runtime())
 
+    def get_runtime_cond(self) -> str:
+        return self._cgen_runtime()
+
     def is_present(self) -> bool:
         return bool(self.ifcond) or bool(self.runtime_ifcond)