I made a python script that you can input a c++ library and it will generate externs for it… it’s not done yet so it doesnt work fully, but ill release the script anyway. Its written in python.
What needs to be done… Make it work with cpp template arguments i dont even know how they work so i will have to do some research.
HOW TO USE:
The python script doesnt actually work on the c++ directly. it works on the xml generated from it when you use the tool “castxml” on it. You just put the xml filename in the script as the variable filename to the name of the xml file.
i feel like haxe is a really cool language and to be able to fully integrate it with cpp so i can write fast stuff to would be really nice without slaving over externs when u can do it automatically theoretically.
step one:
library.cpp —>>> library.xml : with cast xml
step two:
python.py ---->> epic.haxe :done.
edit: it might not be clear what the script is doing. Every class is trying to imitate something in the c++. For every variable in every c++ class u input, it makes a “feild” class to “Be” it and generate the “haxe” from it.
import os
#os is to generate the file
cppFile = 'library.cpp'
class cppMethod:
def __init__(self,parent,name,returnType,id):
self.parent = parent
self.name = name
self.typey = "method"
self.args = []
self.returnType = returnType
self.id = id
self.args = []
def getPath(self):
return self.parent.getPath() + "::" + self.name
class cppVar:
def __init__(self,name,type,id,parent):
self.parent = parent
self.name = name
self.type = type
self.id = id
self.typey = "var"
def getPath(self):
return self.parent.getPath() + "::" + self.name
class cppArg:
def __init__(self,name,type):
self.name = name
self.type = type
class cppClass:
def __init__(self,parent,name,id) -> None:
self.stuffInside = []
self.parent = parent
self.typey = "class"
self.name = name
self.constructorArgs = []
self.id = id
def getPath(self):
return self.parent.getPath() + "::" + self.name
class cppNamespace:
def __init__(self,parent,name,id) -> None:
self.parent = parent
self.name = name
self.typey = "namespace"
self.id = id
def getPath(self):
return self.parent.getPath() + "::" + self.name
class baseClass:
def getPath(self):
return ""
def __init__(self):
self.id = "_1"
self.stuffInside = []
def idToType(id):
types = doc.getElementsByTagName("FundamentalType")
for type in types:
if type.getAttribute("id") == id:
return type.getAttribute("name")
types = doc.getElementsByTagName("Typedef")
for type in types:
if type.getAttribute("id") == id:
return type.getAttribute("name")
types = doc.getElementsByTagName("ReferenceType")
for type in types:
if type.getAttribute("id") == id:
return idToType(type.getAttribute("type"))
clazzez = doc.getElementsByTagName("Class")
for clazz in clazzez:
if clazz.getAttribute("id") == id:
return clazz.getAttribute("name")
clazzez = doc.getElementsByTagName("Struct")
for clazz in clazzez:
if clazz.getAttribute("id") == id:
return clazz.getAttribute("name")
return "Not found"
from xml.dom import minidom
doc = minidom.parse("library.xml")
namespaces = doc.getElementsByTagName("Namespace")
fields = doc.getElementsByTagName("Field")
destructors = doc.getElementsByTagName("Destructor")
constructors = doc.getElementsByTagName("Constructor")
classes = doc.getElementsByTagName("Class")
structs = doc.getElementsByTagName("Struct")
methods = doc.getElementsByTagName("Method")
base = baseClass()
namespaceObjects = [base]
FieldObjects = []
deconstructorObjects = []
constructorObjects = []
classObjects = []
methodObjects = []
def getObjectById(id):
for namespace in namespaceObjects:
if(namespace.id == id):
return namespace
for clazz in classObjects:
if(clazz.id == id):
return clazz
for Field in FieldObjects:
if(Field.id == id):
return Field
for constructor in constructorObjects:
if(constructor.id == id):
return constructor
for deconstructor in deconstructorObjects:
if(deconstructor.id == id):
return deconstructor
return "Not found"
output = ""
percentDone = 0
for namespace in namespaces:
newNamespace = cppNamespace(getObjectById(namespace.getAttribute("context")),namespace.getAttribute("name"),namespace.getAttribute("id"))
if namespace.getAttribute("id") != "_1":
namespaceObjects.append(newNamespace)
percentDone += 100/len(namespaces)
os.system("clear")
print("namespaces: " + str(percentDone) + "%")
percentDone = 0
for clazz in classes:
newClass = cppClass(getObjectById(clazz.getAttribute("context")),clazz.getAttribute("name"),clazz.getAttribute("id"))
classObjects.append(newClass)
percentDone += 100/len(classes)
os.system("clear")
print("classes: " + str(percentDone) + "%")
percentDone = 0
for clazz in structs:
newClass = cppClass(getObjectById(clazz.getAttribute("context")),clazz.getAttribute("name"),clazz.getAttribute("id"))
if(newClass.name != ""):
classObjects.append(newClass)
percentDone += 100/len(structs)
os.system("clear")
print("structs: " + str(percentDone) + "%")
percentDone = 0
for method in methods:
if method.getAttribute("name") != "" and getObjectById(method.getAttribute("context")) != "Not found" and method.getAttribute("access") == "public":
newMethod = cppMethod(getObjectById(method.getAttribute("context")),method.getAttribute("name"),idToType(method.getAttribute("returns")),method.getAttribute("id"))
methodObjects.append(newMethod)
newMethod.parent.stuffInside.append(newMethod)
for arg in method.getElementsByTagName("Argument"):
newArg = cppArg(arg.getAttribute("name"),idToType(arg.getAttribute("type")))
newMethod.args.append(newArg)
percentDone += 100/len(methods)
os.system("clear")
print("methods: " + str(percentDone) + "%")
percentDone = 0
for field in fields:
if field.getAttribute("name") != "" and field.getAttribute("access") == "public" and idToType(field.getAttribute("type")) != "Not found" or field.getAttribute("context") != "_1" and type( getObjectById(field.getAttribute("context"))) != cppNamespace:
newField = cppVar(field.getAttribute("name"),idToType(field.getAttribute("type")),field.getAttribute("id"),getObjectById(field.getAttribute("context")))
FieldObjects.append(newField)
if newField.type != "Not found" and newField.parent != "Not found":
newField.parent.stuffInside.append(newField)
percentDone += 100/len(fields)
os.system("clear")
print("fields: " + str(percentDone) + "%")
percentDone = 0
for constructor in constructors:
if not constructor.getAttribute("artificial") and len(constructor.getElementsByTagName("Argument")) > 0 and idToType(constructor.getAttribute("context")) != "Not found":
for arg in constructor.getElementsByTagName("Argument"):
newArg = cppArg(arg.getAttribute("name"),idToType(arg.getAttribute("type")))
getObjectById(constructor.getAttribute("context")).constructorArgs.append(newArg)
percentDone += 100/len(constructors)
os.system("clear")
print("constructors: " + str(percentDone) + "%")
def ctoh(string):
if string == "int":
string == "Int"
string = string.capitalize()
if string[0] == "_":
string = "H" + string
return string
def classToHaxeExtern(classOb):
output = '''
@:include("''' + cppFile + '''")
@:structAccess()
\n@:native("''' + classOb.getPath() + '''")
'''
output += "extern class " + ctoh(classOb.name) + "{\n"
argList = ""
for arg in classOb.constructorArgs:
argList += arg.name + ":" + ctoh(arg.type)
output += '\t\t@:native("' + classOb.getPath() + '") static public function create(' + argList + '):' + ctoh(classOb.name) + ';\n'
for thing in classOb.stuffInside:
if thing.typey == "method":
argList = ""
for arg in thing.args:
argList += arg.name + ":" + ctoh(arg.type)
output += '\t\t@:native("' + thing.name + '") public function ' + thing.name + '('+ argList +'):' + ctoh(thing.returnType) + ';\n'
if thing.typey == "var":
output += '\t\t@:native("' + thing.name + '") var ' + thing.name + ':'+ ctoh(thing.type) + ';\n'
output += "}\n\n\n\n\n\n"
return output
#TODO: add class function args into output. Get a life lol!
file = open("Epic.hx","w")
percentDone = 0
for a in classObjects:
output += classToHaxeExtern(a)
percentDone += 100/len(classObjects)
os.system("clear")
print("Writing Haxe: " + str(percentDone) + "%")
file.write(output)
file.close()