From: Victor Toso <victortoso@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Markus Armbruster" <armbru@redhat.com>,
"John Snow" <jsnow@redhat.com>,
"Daniel P . Berrangé" <berrange@redhat.com>,
"Andrea Bolognani" <abologna@redhat.com>
Subject: [PATCH v2 03/11] qapi: golang: Generate qapi's enum types in Go
Date: Mon, 16 Oct 2023 17:26:56 +0200 [thread overview]
Message-ID: <20231016152704.221611-4-victortoso@redhat.com> (raw)
In-Reply-To: <20231016152704.221611-1-victortoso@redhat.com>
This patch handles QAPI enum types and generates its equivalent in Go.
We sort the output based on enum's type name.
Enums are being handled as strings in Golang.
1. For each QAPI enum, we will define a string type in Go to be the
assigned type of this specific enum.
2. Naming: CamelCase will be used in any identifier that we want to
export, which is everything.
Example:
qapi:
| { 'enum': 'DisplayProtocol',
| 'data': [ 'vnc', 'spice' ] }
go:
| type DisplayProtocol string
|
| const (
| DisplayProtocolVnc DisplayProtocol = "vnc"
| DisplayProtocolSpice DisplayProtocol = "spice"
| )
Signed-off-by: Victor Toso <victortoso@redhat.com>
---
scripts/qapi/golang.py | 173 +++++++++++++++++++++++++++++++++++++++++
scripts/qapi/main.py | 3 +
2 files changed, 176 insertions(+)
create mode 100644 scripts/qapi/golang.py
diff --git a/scripts/qapi/golang.py b/scripts/qapi/golang.py
new file mode 100644
index 0000000000..dc12be7b03
--- /dev/null
+++ b/scripts/qapi/golang.py
@@ -0,0 +1,173 @@
+"""
+Golang QAPI generator
+"""
+# Copyright (c) 2023 Red Hat Inc.
+#
+# Authors:
+# Victor Toso <victortoso@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.
+# See the COPYING file in the top-level directory.
+
+# Just for type hint on self
+from __future__ import annotations
+
+import os
+from typing import List, Optional
+
+from .schema import (
+ QAPISchema,
+ QAPISchemaEnumMember,
+ QAPISchemaFeature,
+ QAPISchemaIfCond,
+ QAPISchemaObjectType,
+ QAPISchemaObjectTypeMember,
+ QAPISchemaType,
+ QAPISchemaVariants,
+ QAPISchemaVisitor,
+)
+from .source import QAPISourceInfo
+
+
+TEMPLATE_ENUM = """
+type {name} string
+
+const (
+{fields}
+)
+"""
+
+
+def gen_golang(schema: QAPISchema, output_dir: str, prefix: str) -> None:
+ vis = QAPISchemaGenGolangVisitor(prefix)
+ schema.visit(vis)
+ vis.write(output_dir)
+
+
+def qapi_to_field_name_enum(name: str) -> str:
+ return name.title().replace("-", "")
+
+
+def generate_content_from_dict(data: dict[str, str]) -> str:
+ content = ""
+
+ for name in sorted(data):
+ content += data[name]
+
+ return content
+
+
+class QAPISchemaGenGolangVisitor(QAPISchemaVisitor):
+ # pylint: disable=too-many-arguments
+ def __init__(self, _: str):
+ super().__init__()
+ types = ("enum",)
+ self.target = dict.fromkeys(types, "")
+ self.schema: QAPISchema
+ self.golang_package_name = "qapi"
+ self.enums: dict[str, str] = {}
+
+ def visit_begin(self, schema: QAPISchema) -> None:
+ self.schema = schema
+
+ # Every Go file needs to reference its package name
+ for target in self.target:
+ self.target[target] = f"package {self.golang_package_name}\n"
+
+ def visit_end(self) -> None:
+ del self.schema
+ self.target["enum"] += generate_content_from_dict(self.enums)
+
+ def visit_object_type(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ base: Optional[QAPISchemaObjectType],
+ members: List[QAPISchemaObjectTypeMember],
+ variants: Optional[QAPISchemaVariants],
+ ) -> None:
+ pass
+
+ def visit_alternate_type(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ variants: QAPISchemaVariants,
+ ) -> None:
+ pass
+
+ def visit_enum_type(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ members: List[QAPISchemaEnumMember],
+ prefix: Optional[str],
+ ) -> None:
+ assert name not in self.enums
+
+ maxname = 0
+ for member in members:
+ enum_name = f"{name}{qapi_to_field_name_enum(member.name)}"
+ maxname = max(maxname, len(enum_name))
+
+ fields = ""
+ for member in members:
+ enum_name = f"{name}{qapi_to_field_name_enum(member.name)}"
+ name2type = " " * (maxname - len(enum_name) + 1)
+ fields += f"""\t{enum_name}{name2type}{name} = "{member.name}"\n"""
+
+ self.enums[name] = TEMPLATE_ENUM.format(name=name, fields=fields[:-1])
+
+ def visit_array_type(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ element_type: QAPISchemaType,
+ ) -> None:
+ pass
+
+ def visit_command(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ arg_type: Optional[QAPISchemaObjectType],
+ ret_type: Optional[QAPISchemaType],
+ gen: bool,
+ success_response: bool,
+ boxed: bool,
+ allow_oob: bool,
+ allow_preconfig: bool,
+ coroutine: bool,
+ ) -> None:
+ pass
+
+ def visit_event(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ arg_type: Optional[QAPISchemaObjectType],
+ boxed: bool,
+ ) -> None:
+ pass
+
+ def write(self, output_dir: str) -> None:
+ for module_name, content in self.target.items():
+ go_module = module_name + "s.go"
+ go_dir = "go"
+ pathname = os.path.join(output_dir, go_dir, go_module)
+ odir = os.path.dirname(pathname)
+ os.makedirs(odir, exist_ok=True)
+
+ with open(pathname, "w", encoding="utf8") as outfile:
+ outfile.write(content)
diff --git a/scripts/qapi/main.py b/scripts/qapi/main.py
index fe65c1a17a..07c29bcbe9 100644
--- a/scripts/qapi/main.py
+++ b/scripts/qapi/main.py
@@ -15,6 +15,7 @@
from .common import must_match
from .error import QAPIError
from .events import gen_events
+from .golang import gen_golang
from .introspect import gen_introspect
from .schema import QAPISchema
from .types import gen_types
@@ -56,6 +57,8 @@ def generate(
gen_events(schema, output_dir, prefix)
gen_introspect(schema, output_dir, prefix, unmask)
+ gen_golang(schema, output_dir, prefix)
+
def main() -> int:
"""
--
2.41.0
next prev parent reply other threads:[~2023-10-16 15:28 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-16 15:26 [PATCH v2 00/11] qapi-go: add generator for Golang interface Victor Toso
2023-10-16 15:26 ` [PATCH v2 01/11] qapi: re-establish linting baseline Victor Toso
2023-10-16 15:26 ` [PATCH v2 02/11] scripts: qapi: black format main.py Victor Toso
2023-10-18 11:00 ` Markus Armbruster
2023-10-18 11:13 ` Daniel P. Berrangé
2023-10-18 15:23 ` Victor Toso
2023-10-19 5:42 ` Markus Armbruster
2023-10-19 7:30 ` Daniel P. Berrangé
2023-10-16 15:26 ` Victor Toso [this message]
2023-10-16 15:26 ` [PATCH v2 04/11] qapi: golang: Generate qapi's alternate types in Go Victor Toso
2023-11-06 15:28 ` Andrea Bolognani
2023-11-06 15:52 ` Victor Toso
2023-11-06 16:12 ` Andrea Bolognani
2023-11-09 17:34 ` Andrea Bolognani
2023-11-09 19:01 ` Victor Toso
2023-11-10 9:58 ` Andrea Bolognani
2023-11-10 15:43 ` Victor Toso
2023-10-16 15:26 ` [PATCH v2 05/11] qapi: golang: Generate qapi's struct " Victor Toso
2023-10-16 15:26 ` [PATCH v2 06/11] qapi: golang: structs: Address 'null' members Victor Toso
2023-10-16 15:27 ` [PATCH v2 07/11] qapi: golang: Generate qapi's union types in Go Victor Toso
2023-11-09 17:29 ` Andrea Bolognani
2023-11-09 18:35 ` Victor Toso
2023-11-10 9:54 ` Andrea Bolognani
2023-11-10 15:45 ` Victor Toso
2023-10-16 15:27 ` [PATCH v2 08/11] qapi: golang: Generate qapi's event " Victor Toso
2023-11-09 17:59 ` Andrea Bolognani
2023-11-09 19:13 ` Victor Toso
2023-11-10 9:52 ` Andrea Bolognani
2023-10-16 15:27 ` [PATCH v2 09/11] qapi: golang: Generate qapi's command " Victor Toso
2023-10-16 15:27 ` [PATCH v2 10/11] qapi: golang: Add CommandResult type to Go Victor Toso
2023-11-09 18:24 ` Andrea Bolognani
2023-11-09 19:31 ` Victor Toso
2023-11-10 9:46 ` Andrea Bolognani
2023-10-16 15:27 ` [PATCH v2 11/11] docs: add notes on Golang code generator Victor Toso
2023-10-18 11:47 ` Markus Armbruster
2023-10-18 16:21 ` Victor Toso
2023-10-19 6:56 ` Markus Armbruster
2023-10-27 17:33 ` [PATCH v2 00/11] qapi-go: add generator for Golang interface Victor Toso
2023-10-31 16:42 ` Andrea Bolognani
2023-11-03 18:34 ` Andrea Bolognani
2023-11-06 12:00 ` Victor Toso
2023-11-09 18:35 ` Andrea Bolognani
2023-11-09 19:03 ` Victor Toso
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231016152704.221611-4-victortoso@redhat.com \
--to=victortoso@redhat.com \
--cc=abologna@redhat.com \
--cc=armbru@redhat.com \
--cc=berrange@redhat.com \
--cc=jsnow@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).