PkmnLibSharp/PkmnLibSharp/generator.py

162 lines
5.5 KiB
Python

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
def write_enum(enum, enumNames):
namespace = str.capitalize(enum["filename"][3:])
if (namespace == "Pkmnlib_ai"):
return
if (enum["name"].startswith("bfd_")):
return
if (enum["name"].startswith("float_")):
return
if (enum["name"].startswith("as")):
return
filename = "Generated/{}/{}.cs".format(clean_namespace(namespace), enum["name"])
os.makedirs(os.path.dirname(filename), exist_ok=True)
with open(filename, "w") as f:
f.write("// AUTOMATICALLY GENERATED, DO NOT EDIT\n")
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"]) ))
vals = enum["values"].items()
dict = {}
for k, v in vals:
dict[int(k)] = v
for k, v in sorted(dict.items(), key=lambda item: item[0]):
if (enum["byteSize"] == 1 and k < 0):
k = 256 + k
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):
classDict[classKey] = classDef(function["filename"][3:].capitalize(), splitName[1], function["filename"])
classDict[classKey].register_function(funcDef(function["name"], function["returns"], function["parameters"]))
def parse_type(type, enumSet):
type = type.strip()
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"):
return "byte"
if (type == "float"):
return "float"
if (type == "double"):
return "double"
if (type == "long unsigned int"):
return "ulong"
if (type == "long int"):
return "long"
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 "void"
def clean_name(name):
if (name == "out"):
return "@out"
if (name == "event"):
return "@event"
if (name == ""):
return "_"
return name
def write_class(c, enumSet):
filename = "Generated/{}/{}.cs".format(clean_namespace(c.file[3:].capitalize()), c.name)
os.makedirs(os.path.dirname(filename), exist_ok=True)
with open(filename, "w") as f:
f.write("// AUTOMATICALLY GENERATED, DO NOT EDIT\n")
f.write("using System;\n")
f.write("using System.Runtime.InteropServices;\n\n")
f.write("namespace {}.Generated\n{{\n".format(clean_namespace(c.namespace)))
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")
def parse_create(data, filepath):
enumSet = set()
for enum in data["enums"]:
write_enum(enum, enumSet)
classDict = dict()
for function in data["functions"]:
parse_function(function, classDict)
print("Registered {} classes from file {}.".format(len(classDict), filepath))
for _, v in classDict.items():
write_class(v, enumSet)
def handle_file(filepath):
with open(filepath) as json_file:
data = json.load(json_file)
parse_create(data, filepath)
def main():
handle_file("arbutils.json")
handle_file("creaturelib.json")
handle_file("pkmnlib.json")
handle_file("pkmnlibai.json")
main()