diff --git a/projects/jdwp/codegen/BUCK b/projects/jdwp/codegen/BUCK index 1e63709..f33b9bb 100644 --- a/projects/jdwp/codegen/BUCK +++ b/projects/jdwp/codegen/BUCK @@ -9,6 +9,15 @@ python_binary( visibility=["//projects/jdwp/runtime/..."], ) +python_binary( + name="generate-dataclasses", + main_module="projects.jdwp.codegen.dataclass_generator", + deps=[ + ":codegen", + ], + visibility=["//projects/jdwp/runtime/..."], +) + python_library( name="codegen", srcs=glob(["**/*.py"]), diff --git a/projects/jdwp/codegen/dataclass_generator.py b/projects/jdwp/codegen/dataclass_generator.py index 12276ba..b710354 100644 --- a/projects/jdwp/codegen/dataclass_generator.py +++ b/projects/jdwp/codegen/dataclass_generator.py @@ -1,5 +1,6 @@ # Copyright (c) Meta Platforms, Inc. and affiliates. +import enum from textwrap import dedent from projects.jdwp.codegen.types import python_type_for import typing @@ -7,6 +8,8 @@ from projects.jdwp.defs.schema import ( Array, ArrayLength, + Command, + CommandSet, Field, Struct, TaggedUnion, @@ -59,14 +62,13 @@ def __generate_dataclass(self, struct: Struct) -> str: class_def = f"@dataclasses.dataclass(frozen=True)\nclass {name}:\n{fields_def}" return dedent(class_def) - def generate(self): - return [ - self.__generate_dataclass(nested) - for _, _, nested in reversed(list(nested_structs(self.__root))) - ] + [self.__generate_dataclass(self.__root)] + def generate(self) -> typing.Generator[str, None, None]: + for _, _, nested in reversed(list(nested_structs(self.__root))): + yield self.__generate_dataclass(nested) + yield self.__generate_dataclass(self.__root) -def format_enum_name(enum_value): +def format_enum_name(enum_value: enum.Enum) -> str: words = enum_value.name.split("_") formatted_name = "".join(word.capitalize() for word in words) return f"{formatted_name}Type" @@ -110,3 +112,42 @@ def compute_struct_names(root: Struct, name: str) -> typing.Mapping[Struct, str] case_struct ] = f"{names[parent]}{sanitized_field_name}Case{case_name}" return names + + +def generate_for_command(command: Command) -> typing.Generator[str, None, None]: + if command.out: + yield from StructGenerator(command.out, f"{command.name}Out").generate() + if command.reply: + yield from StructGenerator(command.reply, f"{command.name}Reply").generate() + + +def generate_for_command_set( + command_set: CommandSet, +) -> typing.Generator[str, None, None]: + for command in command_set.commands: + yield from generate_for_command(command) + + +def generate_for_all_command_sets() -> typing.Generator[str, None, None]: + # TODO: refactor this once PR90 is merged + from projects.jdwp.defs.command_sets.virtual_machine import VirtualMachine + from projects.jdwp.defs.command_sets.reference_type import ReferenceType + from projects.jdwp.defs.command_sets.event_request import EventRequest + + yield from generate_for_command_set(VirtualMachine) + yield from generate_for_command_set(ReferenceType) + yield from generate_for_command_set(EventRequest) + + +def main(): + print("import dataclasses") + print("import typing") + print("from projects.jdwp.runtime.type_aliases import *") + + for struct_definition in generate_for_all_command_sets(): + print() + print(struct_definition) + + +if __name__ == "__main__": + main() diff --git a/projects/jdwp/runtime/BUCK b/projects/jdwp/runtime/BUCK index 2c75ba2..03d4a2e 100644 --- a/projects/jdwp/runtime/BUCK +++ b/projects/jdwp/runtime/BUCK @@ -6,9 +6,16 @@ genrule( cmd = "$(exe //projects/jdwp/codegen:generate-new-types) > $OUT", ) +genrule( + name = "structs", + out = "structs.py", + cmd = "$(exe //projects/jdwp/codegen:generate-dataclasses) > $OUT", +) + python_library( name = "runtime", srcs = [ + ":structs", ":type-aliases", "async_streams.py", "jdwpstruct.py", diff --git a/projects/jdwp/tests/runtime/structs.py b/projects/jdwp/tests/runtime/structs.py new file mode 100644 index 0000000..1ddea56 --- /dev/null +++ b/projects/jdwp/tests/runtime/structs.py @@ -0,0 +1,8 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. + +import unittest + + +class GeneratedStructsTest(unittest.TestCase): + def test_structs_can_be_imported(self): + from projects.jdwp.runtime.structs import IDSizesReply diff --git a/projects/jdwp/tests/test_dataclass_generator.py b/projects/jdwp/tests/test_dataclass_generator.py index d69edd9..4114689 100644 --- a/projects/jdwp/tests/test_dataclass_generator.py +++ b/projects/jdwp/tests/test_dataclass_generator.py @@ -23,7 +23,7 @@ def test_simple_struct(self): " id: int" ] - self.assertEqual(result, expected) + self.assertSequenceEqual(list(result), expected) def test_nested_struct(self): inner_struct = Struct( @@ -54,7 +54,7 @@ def test_nested_struct(self): " nested: OuterStructNested", ] - self.assertEqual(result, expected) + self.assertSequenceEqual(list(result), expected) def test_struct_in_array(self): # Define a structure @@ -101,4 +101,4 @@ def test_struct_in_array(self): " arrayOfElements: typing.List[ArrayStructArrayOfElementsElement]", ] - self.assertEqual(result, expected) + self.assertSequenceEqual(list(result), expected)