From fb3519577ad8fa17b50e035924bb8f49c3ee46de Mon Sep 17 00:00:00 2001 From: Vaughn Kottler Date: Sat, 17 Aug 2024 22:39:17 -0700 Subject: [PATCH] Enum generation working --- ifgen/common/__init__.py | 2 - ifgen/common/python.py | 30 ------------- ifgen/enum/python/__init__.py | 65 +++++++++++++++++++++++++++-- ifgen/generation/python/__init__.py | 9 +++- 4 files changed, 70 insertions(+), 36 deletions(-) delete mode 100644 ifgen/common/python.py diff --git a/ifgen/common/__init__.py b/ifgen/common/__init__.py index 39a54e6..bd4d07c 100644 --- a/ifgen/common/__init__.py +++ b/ifgen/common/__init__.py @@ -3,7 +3,6 @@ """ # internal -from ifgen.common.python import create_python_common from ifgen.generation.interface import GenerateTask from ifgen.generation.test import unit_test_boilerplate @@ -12,7 +11,6 @@ def create_common_test(task: GenerateTask) -> None: """Create a unit test for the enum string-conversion methods.""" if task.is_python: - create_python_common(task) return with unit_test_boilerplate(task, declare_namespace=True) as writer: diff --git a/ifgen/common/python.py b/ifgen/common/python.py deleted file mode 100644 index e8bddf7..0000000 --- a/ifgen/common/python.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -A module implementing interfaces for generating Python sources that aggregate -common resources. -""" - -# internal -from ifgen.generation.interface import GenerateTask -from ifgen.generation.python import python_function, python_imports - - -def create_python_common(task: GenerateTask) -> None: - """Create a Python module that aggregates runtime registration tasks.""" - - with task.boilerplate() as writer: - # Write imports. - python_imports( - writer, third_party={"runtimepy.enum.registry": ["EnumRegistry"]} - ) - - with python_function( - writer, - "register_enums", - "Register generated enumerations.", - params="registry: EnumRegistry", - ): - writer.write("# iterate over all custom enums, register each") - writer.empty() - writer.write("del registry") - - writer.write("# base class for structs that auto registers enums?") diff --git a/ifgen/enum/python/__init__.py b/ifgen/enum/python/__init__.py index 231bca0..db3ba06 100644 --- a/ifgen/enum/python/__init__.py +++ b/ifgen/enum/python/__init__.py @@ -3,19 +3,55 @@ """ # third-party +from runtimepy.enum.registry import DEFAULT_ENUM_PRIMITIVE from vcorelib.io import IndentedFileWriter # internal from ifgen.generation.interface import GenerateTask -from ifgen.generation.python import python_class, python_imports +from ifgen.generation.python import ( + python_class, + python_function, + python_imports, +) + + +def strip_t_suffix(data: str) -> str: + """Strip a possible '_t' suffix from a string.""" + return data.replace("_t", "") if data.endswith("_t") else data + + +def uses_auto(task: GenerateTask) -> bool: + """ + Determine if a generation task will require 'auto' from the enum module. + """ + + result = False + + for value in task.instance.get("enum", {}).values(): + if not value or "value" not in value: + result = True + break + + return result + + +def to_enum_name(data: str) -> str: + """Ensure a candidate name string is suitable as an enumeration name.""" + return data.upper() def python_enum_header(task: GenerateTask, writer: IndentedFileWriter) -> None: """Create a Python module for an enumeration.""" + built_in = {} + if uses_auto(task): + built_in["enum"] = ["auto"] + # Write imports. python_imports( - writer, third_party={"runtimepy.enum.registry": ["RuntimeIntEnum"]} + writer, + third_party={"runtimepy.enum.registry": ["RuntimeIntEnum"]}, + built_in=built_in, ) with python_class( @@ -25,4 +61,27 @@ def python_enum_header(task: GenerateTask, writer: IndentedFileWriter) -> None: parents=["RuntimeIntEnum"], final_empty=0, ): - writer.write("# register members") + underlying = strip_t_suffix(task.instance["underlying"]) + + if underlying != DEFAULT_ENUM_PRIMITIVE: + with python_function( + writer, + "primitive", + "The underlying primitive type for this runtime enumeration.", + params="cls", + return_type="str", + final_empty=1, + decorators=["classmethod"], + ): + writer.write(f'return "{underlying}"') + + for enum, value in task.instance.get("enum", {}).items(): + final = "auto()" + if value: + final = value.get("value", final) + + line = f"{to_enum_name(enum)} = {final}" + if value and "description" in value: + line += f" # {value['description']}" + + writer.write(line) diff --git a/ifgen/generation/python/__init__.py b/ifgen/generation/python/__init__.py index a1a5785..d196995 100644 --- a/ifgen/generation/python/__init__.py +++ b/ifgen/generation/python/__init__.py @@ -4,7 +4,7 @@ # built-in from contextlib import contextmanager -from typing import Iterator +from typing import Iterable, Iterator # third-party from vcorelib.io import IndentedFileWriter @@ -27,11 +27,14 @@ def write_imports( def python_imports( writer: IndentedFileWriter, + built_in: PythonImports = None, third_party: PythonImports = None, final_empty: int = 2, ) -> None: """Write Python-module imports.""" + if built_in: + write_imports(writer, "built-in", built_in) if third_party: write_imports(writer, "third-party", third_party) @@ -70,9 +73,13 @@ def python_function( params: str = "", return_type: str = "None", final_empty: int = 2, + decorators: Iterable[str] = None, ) -> Iterator[None]: """Write a Python function.""" + if decorators: + for decorator in decorators: + writer.write("@" + decorator) writer.write(f"def {name}({params}) -> {return_type}:") with writer.indented():