[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v1 1/9] qapi: golang: Generate qapi's enum types in Go
From: |
John Snow |
Subject: |
Re: [PATCH v1 1/9] qapi: golang: Generate qapi's enum types in Go |
Date: |
Mon, 2 Oct 2023 15:07:49 -0400 |
On Wed, Sep 27, 2023 at 7:25 AM Victor Toso <victortoso@redhat.com> wrote:
>
> This patch handles QAPI enum types and generates its equivalent in Go.
>
> Basically, 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 [0], which is everything.
>
> [0] https://go.dev/ref/spec#Exported_identifiers
>
> 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 | 140 +++++++++++++++++++++++++++++++++++++++++
> scripts/qapi/main.py | 2 +
> 2 files changed, 142 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..87081cdd05
> --- /dev/null
> +++ b/scripts/qapi/golang.py
> @@ -0,0 +1,140 @@
> +"""
> +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.
> +
> +# due QAPISchemaVisitor interface
> +# pylint: disable=too-many-arguments
> +
> +# Just for type hint on self
> +from __future__ import annotations
> +
> +import os
> +from typing import List, Optional
> +
> +from .schema import (
> + QAPISchema,
> + QAPISchemaType,
> + QAPISchemaVisitor,
> + QAPISchemaEnumMember,
> + QAPISchemaFeature,
> + QAPISchemaIfCond,
> + QAPISchemaObjectType,
> + QAPISchemaObjectTypeMember,
> + QAPISchemaVariants,
> +)
> +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("-", "")
> +
> +
> +class QAPISchemaGenGolangVisitor(QAPISchemaVisitor):
> +
> + def __init__(self, _: str):
> + super().__init__()
> + types = ["enum"]
> + self.target = {name: "" for name in types}
> + self.schema = None
> + self.golang_package_name = "qapi"
> +
> + def visit_begin(self, schema):
> + 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):
> + self.schema = None
> +
> + def visit_object_type(self: QAPISchemaGenGolangVisitor,
> + 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: QAPISchemaGenGolangVisitor,
> + name: str,
> + info: Optional[QAPISourceInfo],
> + ifcond: QAPISchemaIfCond,
> + features: List[QAPISchemaFeature],
> + variants: QAPISchemaVariants
> + ) -> None:
> + pass
> +
> + def visit_enum_type(self: QAPISchemaGenGolangVisitor,
> + name: str,
> + info: Optional[QAPISourceInfo],
> + ifcond: QAPISchemaIfCond,
> + features: List[QAPISchemaFeature],
> + members: List[QAPISchemaEnumMember],
> + prefix: Optional[str]
> + ) -> None:
> +
> + value = qapi_to_field_name_enum(members[0].name)
Unsure if this was addressed on the mailing list yet, but in our call
we discussed how this call was vestigial and was causing the QAPI
tests to fail. Actually, I can't quite run "make check-qapi-schema"
and see the failure, I'm seeing it when I run "make check" and I'm not
sure how to find the failure more efficiently/quickly:
jsnow@scv ~/s/q/build (review)> make
[1/60] Generating subprojects/dtc/version_gen.h with a custom command
[2/60] Generating qemu-version.h with a custom command (wrapped by
meson to capture output)
[3/44] Generating tests/Test QAPI files with a custom command
FAILED: tests/qapi-builtin-types.c tests/qapi-builtin-types.h
tests/qapi-builtin-visit.c tests/qapi-builtin-visit.h
tests/test-qapi-commands-sub-sub-module.c
tests/test-qapi-commands-sub-sub-module.h tests/test-qapi-commands.c
tests/test-qapi-commands.h tests/test-qapi-emit-events.c
tests/test-qapi-emit-events.h tests/test-qapi-events-sub-sub-module.c
tests/test-qapi-events-sub-sub-module.h tests/test-qapi-events.c
tests/test-qapi-events.h tests/test-qapi-init-commands.c
tests/test-qapi-init-commands.h tests/test-qapi-introspect.c
tests/test-qapi-introspect.h tests/test-qapi-types-sub-sub-module.c
tests/test-qapi-types-sub-sub-module.h tests/test-qapi-types.c
tests/test-qapi-types.h tests/test-qapi-visit-sub-sub-module.c
tests/test-qapi-visit-sub-sub-module.h tests/test-qapi-visit.c
tests/test-qapi-visit.h
/home/jsnow/src/qemu/build/pyvenv/bin/python3
/home/jsnow/src/qemu/scripts/qapi-gen.py -o
/home/jsnow/src/qemu/build/tests -b -p test-
../tests/qapi-schema/qapi-schema-test.json --suppress-tracing
Traceback (most recent call last):
File "/home/jsnow/src/qemu/scripts/qapi-gen.py", line 19, in <module>
sys.exit(main.main())
^^^^^^^^^^^
File "/home/jsnow/src/qemu/scripts/qapi/main.py", line 96, in main
generate(args.schema,
File "/home/jsnow/src/qemu/scripts/qapi/main.py", line 58, in generate
gen_golang(schema, output_dir, prefix)
File "/home/jsnow/src/qemu/scripts/qapi/golang.py", line 46, in gen_golang
schema.visit(vis)
File "/home/jsnow/src/qemu/scripts/qapi/schema.py", line 1227, in visit
mod.visit(visitor)
File "/home/jsnow/src/qemu/scripts/qapi/schema.py", line 209, in visit
entity.visit(visitor)
File "/home/jsnow/src/qemu/scripts/qapi/schema.py", line 346, in visit
visitor.visit_enum_type(
File "/home/jsnow/src/qemu/scripts/qapi/golang.py", line 102, in
visit_enum_type
value = qapi_to_field_name_enum(members[0].name)
~~~~~~~^^^
IndexError: list index out of range
ninja: build stopped: subcommand failed.
make: *** [Makefile:162: run-ninja] Error 1
For the rest of my review, I commented this line out and continued on.
> + fields = ""
> + for member in members:
> + value = qapi_to_field_name_enum(member.name)
> + fields += f'''\t{name}{value} {name} = "{member.name}"\n'''
> +
> + self.target["enum"] += TEMPLATE_ENUM.format(name=name,
> fields=fields[:-1])
> +
> + def visit_array_type(self, name, info, ifcond, element_type):
> + 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, info, ifcond, features, arg_type, boxed):
> + 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="ascii") as outfile:
> + outfile.write(content)
> diff --git a/scripts/qapi/main.py b/scripts/qapi/main.py
> index 316736b6a2..cdbb3690fd 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
> @@ -54,6 +55,7 @@ def generate(schema_file: str,
> 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
>
- Re: [PATCH v1 1/9] qapi: golang: Generate qapi's enum types in Go,
John Snow <=