PkmnLibSharp/PkmnLibSharp/generator.py

168 lines
5.7 KiB
Python
Raw Normal View History

2020-05-02 17:54:07 +00:00
import json
import os
def resolve_enum_size(size):
if (size == 1):
return "byte"
if (size == 4):
return "int"
raise Exception("Unknown size {}".format(size))
def clean_namespace(namespace):
if (namespace == "Pkmnlib_ai"):
return "PkmnLibAI"
return namespace
2020-05-02 17:54:07 +00:00
def write_enum(enum, enumNames):
2020-10-17 16:16:00 +00:00
namespace = str.capitalize(enum["filename"][3:])
if (namespace == "Pkmnlib_ai"):
return
2020-08-17 16:51:07 +00:00
if (enum["name"].startswith("bfd_")):
return
if (enum["name"].startswith("float_")):
return
if (enum["name"].startswith("as")):
return
2021-11-27 10:27:19 +00:00
if (enum["name"][0] >= 'a' and enum["name"][0] <= 'z'):
return
if (enum["name"] == "EPOLL_EVENTS"):
return;
if (enum["name"] == "METADATATYPE"):
return;
filename = "Generated/{}/{}.cs".format(clean_namespace(namespace), enum["name"])
2020-05-02 17:54:07 +00:00
os.makedirs(os.path.dirname(filename), exist_ok=True)
with open(filename, "w") as f:
2020-05-03 09:38:49 +00:00
f.write("// AUTOMATICALLY GENERATED, DO NOT EDIT\n")
2020-05-02 17:54:07 +00:00
f.write("using System.Diagnostics.CodeAnalysis;\n\n")
f.write("namespace {}\n{{\n".format(namespace))
f.write(" [SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n")
f.write(" internal enum {} : {}\n {{\n".format(enum["name"], resolve_enum_size(enum["byteSize"]) ))
2020-10-17 16:16:00 +00:00
vals = enum["values"].items()
2020-08-14 14:15:19 +00:00
dict = {}
for k, v in vals:
2020-10-17 16:16:00 +00:00
dict[int(k)] = v
2020-08-14 14:15:19 +00:00
for k, v in sorted(dict.items(), key=lambda item: item[0]):
2021-05-24 09:41:55 +00:00
if (enum["byteSize"] == 1 and k < 0):
k = 256 + k
2020-05-02 17:54:07 +00:00
f.write(" {} = {},\n".format(v, k))
f.write(" }\n")
f.write("}\n")
enumNames.add(enum["name"])
class funcDef:
def __init__(self, name, returns, parameters):
self.name = name
self.returns = returns
self.parameters = parameters
class classDef:
def __init__(self, namespace, name, file):
self.namespace = namespace
self.file = file
self.name = name
self.functions = []
def register_function(self, func):
self.functions.append(func)
def parse_function(function, classDict):
splitName = function["name"].split("_")
classKey = "{}_{}".format(function["filename"], splitName[1])
if (not classKey in classDict):
2020-10-17 16:16:00 +00:00
classDict[classKey] = classDef(function["filename"][3:].capitalize(), splitName[1], function["filename"])
2020-05-02 17:54:07 +00:00
classDict[classKey].register_function(funcDef(function["name"], function["returns"], function["parameters"]))
def parse_type(type, enumSet):
2020-10-17 16:16:00 +00:00
type = type.strip()
2020-05-02 17:54:07 +00:00
if (type == "void"):
return "void"
if (type == "unsigned char"):
return "byte"
if (type == "signed char"):
return "sbyte"
if (type == "unsigned short"):
return "ushort"
if (type == "bool"):
2020-05-03 09:38:49 +00:00
return "byte"
2020-05-02 17:54:07 +00:00
if (type == "float"):
return "float"
2020-07-18 14:49:11 +00:00
if (type == "double"):
return "double"
2020-05-02 17:54:07 +00:00
if (type == "long unsigned int"):
return "ulong"
2020-05-02 20:58:08 +00:00
if (type == "long int"):
return "long"
2020-05-02 17:54:07 +00:00
if (type == "unsigned int"):
return "uint"
if (type == "int"):
return "int"
if (type.endswith("*")):
return "IntPtr"
if (type.endswith("&")):
return "ref " + parse_type(type[:-1], enumSet)
if (type in enumSet):
return type
print("Unhandled type '{}'".format(type))
return "IntPtr"
2020-05-02 17:54:07 +00:00
def clean_name(name):
if (name == "out"):
return "@out"
if (name == "event"):
return "@event"
2020-10-23 16:59:38 +00:00
if (name == ""):
return "_"
2020-05-02 17:54:07 +00:00
return name
def write_class(c, enumSet):
filename = "Generated/{}/{}.cs".format(clean_namespace(c.file[3:].capitalize()), c.name)
2020-05-02 17:54:07 +00:00
os.makedirs(os.path.dirname(filename), exist_ok=True)
with open(filename, "w") as f:
2020-05-03 09:38:49 +00:00
f.write("// AUTOMATICALLY GENERATED, DO NOT EDIT\n")
2020-05-02 17:54:07 +00:00
f.write("using System;\n")
f.write("using System.Runtime.InteropServices;\n\n")
f.write("namespace {}.Generated\n{{\n".format(clean_namespace(c.namespace)))
2020-05-02 17:54:07 +00:00
f.write(" internal static class {}\n {{\n".format(c.name))
for function in c.functions:
for parameter in function.parameters:
f.write(" /// <param name=\"{}\">{}</param>\n".format(parameter["name"], parameter["type"]))
f.write(" /// <returns>{}</returns>\n".format(function.returns))
f.write(" [DllImport(\"{}\", CallingConvention = CallingConvention.Cdecl, EntryPoint= \"{}\")]\n".format(c.file, function.name))
f.write(" internal static extern {} {}(".format(parse_type(function.returns, enumSet), function.name.split("_")[2]))
isFirst = True
for parameter in function.parameters:
if (not isFirst):
f.write(", ")
else:
isFirst = False
f.write("{} {}".format(parse_type(parameter["type"], enumSet), clean_name(parameter["name"])))
f.write(");\n\n")
f.write(" }\n")
f.write("}\n")
2020-07-18 14:49:11 +00:00
def parse_create(data, filepath):
2020-05-02 17:54:07 +00:00
enumSet = set()
for enum in data["enums"]:
write_enum(enum, enumSet)
classDict = dict()
for function in data["functions"]:
parse_function(function, classDict)
2020-07-18 14:49:11 +00:00
print("Registered {} classes from file {}.".format(len(classDict), filepath))
2020-05-02 17:54:07 +00:00
for _, v in classDict.items():
write_class(v, enumSet)
def handle_file(filepath):
with open(filepath) as json_file:
data = json.load(json_file)
2020-07-18 14:49:11 +00:00
parse_create(data, filepath)
2020-05-02 17:54:07 +00:00
def main():
2020-07-18 14:49:11 +00:00
handle_file("arbutils.json")
2020-05-02 17:54:07 +00:00
handle_file("creaturelib.json")
handle_file("pkmnlib.json")
handle_file("pkmnlibai.json")
2020-05-02 17:54:07 +00:00
main()