Helper for move to c++ api
This commit is contained in:
parent
754e168b48
commit
2169e3ee47
240
convert_to_cpp.py
Executable file
240
convert_to_cpp.py
Executable file
@ -0,0 +1,240 @@
|
||||
#!/bin/python3
|
||||
""" A python script to transform a vulkan project to use vulkan.hpp instead of the c api
|
||||
Copyright © 2022 Matthias Quintern.
|
||||
This software comes with no warranty.
|
||||
This software is licensed under the GPL3
|
||||
"""
|
||||
from os import makedirs, mkdir, path, listdir, chdir
|
||||
from sys import argv, exit
|
||||
import re
|
||||
from bs4 import BeautifulSoup as bs
|
||||
|
||||
|
||||
filetypes = [ ".hpp", ".cpp" ]
|
||||
no_delete = False
|
||||
|
||||
def error(s):
|
||||
print(s)
|
||||
exit(1)
|
||||
|
||||
def case_to_camel(s: str) -> str:
|
||||
"""
|
||||
turn all letters following a uppercase letter to lowercase
|
||||
turn letter following " _0-9" to uppercase
|
||||
remove " " and "_"
|
||||
"""
|
||||
ret = ""
|
||||
make_lower = False
|
||||
make_upper = False
|
||||
for c in s:
|
||||
if c in "_ 0123456789":
|
||||
make_lower = False
|
||||
make_upper = True
|
||||
if c in "_ ":
|
||||
continue
|
||||
else:
|
||||
ret += c
|
||||
continue
|
||||
|
||||
if make_lower:
|
||||
ret += c.lower()
|
||||
elif make_upper:
|
||||
ret += c.upper()
|
||||
else:
|
||||
ret += c
|
||||
make_upper = False
|
||||
make_lower = True
|
||||
return ret
|
||||
|
||||
def case_first_letter_low(s: str) -> str:
|
||||
return s[0].lower() + s[1:]
|
||||
|
||||
def delete(s) -> str:
|
||||
global no_delete
|
||||
if no_delete:
|
||||
return "// no-delete " + s
|
||||
else:
|
||||
return ""
|
||||
|
||||
enum_suffixes = [ "KHR", "EXT", "AMD", "NV"]
|
||||
vk_soup = bs()
|
||||
def init_enum_names():
|
||||
global vk_soup
|
||||
with open("vk.xml", "r") as vk:
|
||||
spec = vk.read()
|
||||
vk_soup = bs(spec, features="lxml")
|
||||
|
||||
new_token_begin_chars = r"[<>()\[\]{} ,;=&|\t\n]"
|
||||
|
||||
|
||||
# functions that take the line and a token and return the transformed line
|
||||
re_vk_function: str = new_token_begin_chars + r"(vk[A-Z][a-zA-Z]+)\("
|
||||
re_vk_function_device:str = r"vk[a-zA-Z]+\(((?:device)|(?:vk.getDevice\(\))), "
|
||||
def vk_function(line:str, function:str) -> str:
|
||||
match = re.search(re_vk_function_device, line)
|
||||
if match:
|
||||
new_function:str = match.groups()[0] + "." + case_first_letter_low(function.removeprefix("vk"))
|
||||
return line.replace(match.groups()[0] + ", ", "").replace(function, new_function)
|
||||
else:
|
||||
new_function = "vk::" + case_first_letter_low(function.removeprefix("vk"))
|
||||
return line.replace(function, new_function)
|
||||
|
||||
re_vk_type: str = new_token_begin_chars + r"(Vk[A-Z][a-zA-Z]+)"
|
||||
def vk_type(line:str, type_:str) -> str:
|
||||
new_type = "vk::" + type_.removeprefix("Vk")
|
||||
return line.replace(type_, new_type)
|
||||
|
||||
# 0 -> name, 1 -> suffixes, 2 -> iteration
|
||||
re_vk_enum_name: str = "Vk([a-zA-Z]+?)(?:FlagBits)?((?:KHR)|(?:EXT)|(?:AMD)|(?:NV))*([2-9]?)$"
|
||||
re_vk_enum_val: str = new_token_begin_chars + r"(VK_(?:[A-Z0-9]+_)+([A-Z0-9]+))"
|
||||
def vk_enum_val(line: str, enum_val: str) -> str:
|
||||
new_enum_val = "vk::"
|
||||
|
||||
# name is VkName[FlagBits][Suffix][2] -> VK_NAME[_BIT][_SUFFIX][2]
|
||||
|
||||
tag = vk_soup.find(attrs={"name":enum_val})
|
||||
if not tag:
|
||||
print("skipping", enum_val, "(not found)")
|
||||
return line
|
||||
enum_val_2 = case_to_camel(enum_val)
|
||||
parent = tag.parent
|
||||
|
||||
if not parent.attrs.__contains__("name"):
|
||||
print("skipping", enum_val, "(no parent name)")
|
||||
return line
|
||||
|
||||
# print(enum_val_2)
|
||||
# print(parent["name"], parent["type"])
|
||||
|
||||
match = re.search(re_vk_enum_name, parent["name"])
|
||||
if match:
|
||||
name = match.groups()[0]
|
||||
suffixes = match.groups()[1]
|
||||
iteration = match.groups()[2]
|
||||
# enum name
|
||||
new_enum_val += parent["name"].removeprefix("Vk") + "::"
|
||||
# enum val name
|
||||
print("\tenum_val_2", enum_val_2)
|
||||
print("\tname", name)
|
||||
print("\tparent['name']", parent['name'])
|
||||
print("\tsuffixes", suffixes)
|
||||
print("\titeration", iteration)
|
||||
new_enum_val += "e" + enum_val_2.removeprefix("Vk" + name)
|
||||
if suffixes:
|
||||
new_enum_val = new_enum_val.removesuffix(case_to_camel(suffixes))
|
||||
new_enum_val = new_enum_val.removesuffix("Bit")
|
||||
else:
|
||||
print("skipping", enum_val, "(no parent name match)")
|
||||
return line
|
||||
print(new_enum_val, "\n")
|
||||
return line.replace(enum_val, new_enum_val)
|
||||
|
||||
def vk_str(line, m):
|
||||
# same match with different group
|
||||
match = re.search(r"STR_VK_[A-Z]+\((.+)\)", line)
|
||||
if match:
|
||||
return line.replace(m, match.groups()[0])
|
||||
else:
|
||||
return line
|
||||
|
||||
|
||||
# f = f(line, match_group) -> line
|
||||
re_and_f = {
|
||||
re_vk_function: vk_function,
|
||||
re_vk_type: vk_type,
|
||||
re_vk_enum_val: vk_enum_val,
|
||||
r"(STR_VK_[A-Z]+\(.+\))": vk_str,
|
||||
}
|
||||
|
||||
re_vk_struct_init: str = r"vk::[a-zA-Z2]+ [a-zA-Z]+ ?\{\};"
|
||||
def vk_struct_init(s):
|
||||
return s.replace("};", "").replace("{", " {").replace(" {", " {")
|
||||
|
||||
re_vk_struct_member_init: str = r"([a-zA-Z]+(?:(?:CI)|(?:AI)|(?:I)|(?:MI)))\.[a-zA-Z0-9]+ = .+;"
|
||||
def vk_struct_member_init(s):
|
||||
match= re.search(re_vk_struct_member_init, s)
|
||||
if match:
|
||||
return s.replace(match.groups()[0], "\t").replace(";", ",")
|
||||
else:
|
||||
return s
|
||||
|
||||
# f = f(line) -> line
|
||||
re_no_group_and_f = {
|
||||
"#include <vulkan/vulkan_core.h>": lambda l : "#define VULKAN_HPP_NO_CONSTRUCTORS\n" + l.replace("vulkan_core.h>", "vulkan.hpp>"),
|
||||
r"\.sType ?=": lambda l : delete(l),
|
||||
"VK_SUCCESS": lambda l : l.replace("VK_SUCCESS", "vk::Result::eSuccess"),
|
||||
re_vk_struct_init: vk_struct_init,
|
||||
re_vk_struct_member_init: vk_struct_member_init,
|
||||
}
|
||||
|
||||
|
||||
def transform_file(filename:str, outfilename):
|
||||
"""
|
||||
"""
|
||||
|
||||
print("transform_file:", filename)
|
||||
if not path.isfile(filename): error("File does not exist:" + filename)
|
||||
|
||||
with open(filename, "r") as file:
|
||||
lines = file.readlines()
|
||||
|
||||
for i in range(len(lines)):
|
||||
line = lines[i]
|
||||
for reg, f in re_and_f.items():
|
||||
for m in re.finditer(reg, line):
|
||||
line = f(line, m.groups()[0])
|
||||
|
||||
line = line
|
||||
for reg, f in re_no_group_and_f.items():
|
||||
if re.search(reg, line):
|
||||
line = f(line)
|
||||
lines[i] = line
|
||||
|
||||
with open(outfilename, "w") as file:
|
||||
file.writelines(lines)
|
||||
|
||||
|
||||
|
||||
# with open(filename, "w") as file:
|
||||
# file.writelines(lines)
|
||||
|
||||
|
||||
def process_path(path_):
|
||||
# print("Processing path:", path_)
|
||||
if path.isfile(path_) and path.splitext(path_)[-1] in filetypes:
|
||||
makedirs("new/" + path.dirname(path_), exist_ok=True)
|
||||
transform_file(path_, "new/" + path_)
|
||||
else:
|
||||
if path.isdir(path_):
|
||||
for p in listdir(path_):
|
||||
process_path(path_ + "/" + p)
|
||||
|
||||
|
||||
|
||||
|
||||
def print_help():
|
||||
print("""
|
||||
-h --help help
|
||||
--no-delete comment lines instead of deleting them"""
|
||||
)
|
||||
|
||||
def missing_arg(arg):
|
||||
print("Missing argument for", arg)
|
||||
exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
i = 1
|
||||
while i in range(1, len(argv)):
|
||||
if argv[i] == "--help" or argv[i] == "-h":
|
||||
print_help()
|
||||
exit(0)
|
||||
elif argv[i] == "--no-delete":
|
||||
no_delete = True
|
||||
i += 1
|
||||
|
||||
init_enum_names()
|
||||
process_path(path.curdir)
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user