Skip to content

[libc] added newhdrgen python script and class file #96671

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 26, 2024

Conversation

aaryanshukla
Copy link
Contributor

python script uses yaml and classes to generate c headers
header.py is only the main class file, the rest will be in another pr
more files to be added in multiple prs

python script uses yaml and classes to generate c headers
header.py is only the main class file, the rest will be in another pr
more files to be added in multiple prs
@llvmbot llvmbot added the libc label Jun 25, 2024
@llvmbot
Copy link
Member

llvmbot commented Jun 25, 2024

@llvm/pr-subscribers-libc

Author: None (aaryanshukla)

Changes

python script uses yaml and classes to generate c headers
header.py is only the main class file, the rest will be in another pr
more files to be added in multiple prs


Full diff: https://github.com/llvm/llvm-project/pull/96671.diff

2 Files Affected:

  • (added) libc/newhdrgen/header.py (+59)
  • (added) libc/newhdrgen/yaml_to_classes.py (+113)
diff --git a/libc/newhdrgen/header.py b/libc/newhdrgen/header.py
new file mode 100644
index 0000000000000..311345f10d1a2
--- /dev/null
+++ b/libc/newhdrgen/header.py
@@ -0,0 +1,59 @@
+# class_implementation/classes/header.py
+class HeaderFile:
+    def __init__(self, name):
+        self.name = name
+        self.macros = []
+        self.types = []
+        self.enumerations = []
+        self.objects = []
+        self.functions = []
+        self.includes = []
+
+    def add_macro(self, macro):
+        self.macros.append(macro)
+
+    def add_type(self, type_):
+        self.types.append(type_)
+
+    def add_enumeration(self, enumeration):
+        self.enumerations.append(enumeration)
+
+    def add_object(self, object):
+        self.objects.append(object)
+
+    def add_function(self, function):
+        self.functions.append(function)
+
+    def add_include(self, include):
+        self.includes.append(include)
+
+    def __str__(self):
+        # header_guard = self.name.replace(".", "_").upper()
+        content = [""]
+
+        for include in self.includes:
+            content.append(str(include))
+
+        for macro in self.macros:
+            content.append(str(macro))
+
+        for object in self.objects:
+            content.append(str(object))
+
+        for type_ in self.types:
+            content.append(str(type_))
+
+        if self.enumerations:
+            content.append("enum {")
+            for enum in self.enumerations:
+                content.append(f"\t{str(enum)},")
+            content.append("};")
+
+        # ToDo: replace line below with common.h functionality
+        content.append("__BEGIN_C_DECLS\n")
+        if self.functions:
+            for function in self.functions:
+                content.append(str(function))
+                content.append("")
+        content.append("__END_C_DECLS\n")
+        return "\n".join(content)
diff --git a/libc/newhdrgen/yaml_to_classes.py b/libc/newhdrgen/yaml_to_classes.py
new file mode 100644
index 0000000000000..e77e3b8fd8598
--- /dev/null
+++ b/libc/newhdrgen/yaml_to_classes.py
@@ -0,0 +1,113 @@
+import yaml
+import os
+import re
+
+from header import HeaderFile
+from class_implementation.classes.macro import Macro
+from class_implementation.classes.type import Type
+from class_implementation.classes.function import Function
+from class_implementation.classes.include import Include
+from class_implementation.classes.enums import Enumeration
+from class_implementation.classes.object import Object
+
+
+def yaml_to_classes(yaml_data):
+    header_name = yaml_data.get("header", "unknown.h")
+    # standard = yaml_data.get('standard', None)
+    header = HeaderFile(header_name)
+
+    for macro_data in yaml_data.get("macros", []):
+        header.add_macro(Macro(macro_data["macro_name"], macro_data["macro_value"]))
+
+    for type_data in yaml_data.get("types", []):
+        header.add_type(Type(type_data["type_name"]))
+
+    for enum_data in yaml_data.get("enums", []):
+        header.add_enumeration(
+            Enumeration(enum_data["name"], enum_data.get("value", None))
+        )
+
+    for object_data in yaml_data.get("objects", []):
+        header.add_object(
+            Object(object_data["object_name"], object_data["object_type"])
+        )
+
+    for function_data in yaml_data.get("functions", []):
+        arguments = [arg["type"] for arg in function_data["arguments"]]
+        header.add_function(
+            Function(
+                function_data["return_type"],
+                function_data["name"],
+                arguments,
+                function_data.get("guard"),
+                function_data.get("attributes", []),
+            )
+        )
+
+    for include_data in yaml_data.get("includes", []):
+        header.add_include(Include(include_data))
+
+    return header
+
+
+def load_yaml_file(yaml_file):
+    with open(yaml_file, "r") as f:
+        yaml_data = yaml.safe_load(f)
+    return yaml_to_classes(yaml_data)
+
+
+# will be used for specific functions a user wants to generate headers for
+"""
+def filter_functions(header, function_names):
+    filtered_functions = []
+    function_name_set = set(function_names)
+    for func in header.functions:
+        if func.name in function_name_set:
+            filtered_functions.append(func)
+    return filtered_functions
+"""
+
+
+def fill_public_api(header_str, h_def_content):
+    # using regular expression to identify the public_api string
+    return re.sub(r"%%public_api\(\)", header_str, h_def_content)
+
+
+def main(yaml_file, h_def_file, output_dir):
+    header = load_yaml_file(yaml_file)
+
+    with open(h_def_file, "r") as f:
+        h_def_content = f.read()
+
+    header_str = str(header)
+    final_header_content = fill_public_api(header_str, h_def_content)
+
+    output_file_name = os.path.basename(h_def_file).replace(".def", "")
+    output_file_path = os.path.join(output_dir, output_file_name)
+
+    with open(output_file_path, "w") as f:
+        f.write(final_header_content)
+
+    print(f"Generated header file: {output_file_path}")
+
+
+if __name__ == "__main__":
+    import argparse
+
+    parser = argparse.ArgumentParser(
+        description="Generate header files from YAML and .h.def templates"
+    )
+    parser.add_argument(
+        "yaml_file", help="Path to the YAML file containing header specification"
+    )
+    parser.add_argument("h_def_file", help="Path to the .h.def template file")
+    parser.add_argument(
+        "--output_dir",
+        default=".",
+        help="Directory to output the generated header file",
+    )
+    args = parser.parse_args()
+
+    main(args.yaml_file, args.h_def_file, args.output_dir)
+
+# Example Command Line Arg: python3 yaml_to_classes.py yaml/stdc_stdbit.yaml h_def/stdbit.h.def --output_dir output

Copy link

github-actions bot commented Jun 25, 2024

✅ With the latest revision this PR passed the Python code formatter.

added license header to header.py and removed comments
used pathlib instead of os in yaml_to_classes
Copy link
Contributor

@michaelrj-google michaelrj-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM now that the other patch has landed

@aaryanshukla aaryanshukla merged commit 1fa9f50 into llvm:main Jun 26, 2024
6 checks passed
lravenclaw pushed a commit to lravenclaw/llvm-project that referenced this pull request Jul 3, 2024
python script uses yaml and classes to generate c headers
header.py is only the main class file, the rest will be in another pr
more files to be added in multiple prs
AlexisPerry pushed a commit to llvm-project-tlp/llvm-project that referenced this pull request Jul 9, 2024
python script uses yaml and classes to generate c headers
header.py is only the main class file, the rest will be in another pr
more files to be added in multiple prs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants