gz-cpp-util/gen_enum_str.py
matthias@arch 51fb0d572e unchanged
2022-09-17 19:57:52 +02:00

169 lines
5.2 KiB
Python
Executable File

#!/bin/python3
"""
A python script to generate to_string functions for all enumerations in a cpp file.
Copyright © 2022 Matthias Quintern.
This software comes with no warranty.
This software is licensed under the GPL3
"""
from os import path, listdir, chdir
from sys import argv, exit
import re
filetypes = [".hpp", ".cpp", ".tpp"]
def error(s):
print(s)
exit(1)
def getEnumStrF(name: str, enum: dict, spaces: int):
s = " " * spaces
s += f"const std::map<{name}, std::string> {name}ToStringMap" + " { // generated by gen_enum_str.py\n"
for name_, val in enum.items():
s += " " * (spaces + 4)
s += "{ " + name_ + ", \"" + name_ + "\" },\n"
s += " " * spaces + "};\n"
s += " " * spaces + "const std::string& to_string(" + name + " v) { return " + f"{name}ToStringMap.at(v);" + " }; // generated by gen_enum_str.py\n\n"
return s
def process_file(inputfile: str, outputfile: str):
print("process_file:", inputfile)
if not path.isfile(inputfile): error("File does not exist:" + inputfile)
with open(inputfile, "r") as file:
lines = file.readlines()
# FIND ENUMS
enums_start = []
enums_stop = []
in_enum = False
for i in range(len(lines)):
if re.match(r" *enum [a-zA-Z0-9_-]+ {.*", lines[i]) and not "gen_enum_str.py" in lines[i]:
if in_enum: error("process_file: could not find end of enum starting at line " + str(enums_start.pop()))
in_enum = True
enums_start.append(i)
if in_enum:
if re.match(r" *[^/*]?.*}.*", lines[i]):
enums_stop.append(i)
in_enum = False
if len(enums_start) != len(enums_stop): error("process_file: could not find end of enum starting at line " + str(enums_start.pop()))
# create a single string with the enum
enums = []
for i in range(len(enums_start)):
enums.append("")
j = enums_start[i]
while j <= enums_stop[i]:
enums[i] += lines[j]
j += 1
# get name and vars
enum_names = []
enum_dicts = []
spaces = []
var = "[a-zA-Z0-9_-]+"
enumvar = "(" + var + r"(=*-?\d+)?)"
restring = "enum (" + var + "){(" + enumvar + ",)*" + enumvar + ",?}"
for i in range(len(enums)):
enums[i] = enums[i].replace("\n", "").replace("enum ", "enumü").replace(" ", "").replace("enumü", "enum ")
match = re.match(restring, enums[i])
if not match: error("Invalid enum at line " + str(enums_start[i]))
spaces.append(lines[enums_start[i]].find("e"))
enum_names.append(match.groups()[0])
enum_val = 0
enum = {}
for m in re.finditer(enumvar, enums[i][len("enum " + enum_names[i]):]):
if "=" in m.group():
enum_val = int(m.group()[m.group().find("=")+1:])
var_end = m.group().find("=")
else:
var_end = len(m.group())
enum[m.group()[0:var_end]] = enum_val
enum_val += 1
print("enum:", enum_names[i], enum)
enum_dicts.append(enum)
for i in reversed(range(len(enum_names))):
lines.insert(enums_stop[i] + 1, getEnumStrF(enum_names[i], enum_dicts[i], spaces[i]))
lines[enums_start[i]] = lines[enums_start[i]].strip("\n") + " // processed by gen_enum_str.py\n"
with open(outputfile, "w") as file:
file.writelines(lines)
def process_path(path_):
if path.isfile(path_) and path.splitext(path_)[-1] in filetypes:
process_file(path_, path_)
elif path.isdir(path_):
for p in listdir(path_):
if path.isfile(p) and path.splitext(p)[-1] in filetypes:
process_file(p, p)
elif path.isdir(p):
chdir(p)
process_path(p)
chdir("..")
else:
print("Invalid path:", path_)
def print_help():
"""
Synposis: get_enum_str.py <Options>... <file>...
-o <path> output: file to path. Only when 1 input file.
-h --help help
-r recurse: Recurse through the directory and process all cpp/hpp files. Implies -i
-i in place: Edit the file in place
"""
def missing_arg(arg):
print("Missing argument for", arg)
exit(1)
if __name__ == "__main__":
output_file = None
input_files = []
in_place = False
recurse = False
i = 1
while i in range(1, len(argv)):
if argv[i] == "--help" or argv[i] == "-h":
print_help()
exit(0)
if argv[i] == "-o":
if len(argv) > i + 1: output_file = argv[i+1]
else: missing_arg(argv[i])
i += 1
elif argv[i] == "-r":
recurse = True
elif argv[i] == "-i":
in_place = True
else:
input_files.append(argv[i])
i += 1
if output_file is None and not in_place and not recurse:
error("Missing output path or -i")
if output_file and (recurse or in_place or len(input_files) > 1):
error("Error: -o does not work with -r, -i or multiple input paths.")
if len(input_files) == 0:
error("Missing input files.")
if in_place:
output_file = input_files[0]
if (recurse):
for f in input_files:
process_path(f)
else:
process_file(input_files[0], output_file)