IrrHaskell-0.2: InterfaceGenerator/createInterface.py
#!/usr/bin/python
#
# createInterface.py is used to parse header files of the Irrlicht API, generate the C interface and Green Card specification files.
# Usage:
# ./createInterface path-to-Irrlicht-include-folder
#
# Author: Maciej Baranski
#
import sys, os
import CppHeaderParser
irrlichtIncludePath = sys.argv[1]
mode = 1
listOfArgumentTypes = []
cInterface_cpp = open("c_interface.cpp","w")
cInterface_h = open("c_interface.h","w")
greenCardSpec = open("autogen_irrlicht_interface.hs","w")
def convertArgType(argType):
newArg = "Int"
returnTypeList = argType.rsplit()
ret_len = len(returnTypeList)
if (ret_len > 0 and "void" not in returnTypeList):
if argType == "const wchar_t *" or "wchar_t" in argType:
newArg = "String"
elif (returnTypeList[ret_len-1] == "*"):
newArg = returnTypeList[ret_len-2] + "Ptr"
else:
newArg = "Int"
if (":" in newArg):
newArg = newArg.rpartition(":")[2]
newArg = newArg[0].upper() + newArg[1:]
return newArg
def getArgType(arg):
newArg = "int"
returnTypeList = arg.rsplit()
ret_len = len(returnTypeList)
if (ret_len > 0 and "void" not in returnTypeList):
if ("wchar" in arg or "c8" in arg):
newArg = "char *"
else:
newArg = "int"
if (":" in newArg):
newArg = newArg.rpartition(":")[2]
return newArg
# args = [{'type': 'ILightManager *', 'name': 'lightManager'}]
# need to generate somthing like this having args:
# %fun FileSystemAddZipFileArchive :: String -> IO ()
# %call (string file)
# %code int result = FileSystemAddZipFileArchive(file);
# %fail {result < 0} {getError();}
def createHaskellSpecification(className, functionName, args, returnType):
returnCode = ""
listOfDataTypes = []
fName = ""
if functionName != "":
for i in range(len(functionName)):
ch = functionName[i]
if ch == '=' or ch == '>' or ch == '<' or ch == '*' or ch == '(' or ch == ')':
ch = '_'
fName += ch
returnCode += "%fun " + className + fName[0].upper() + fName[1:] + " :: "
callLine = "%call "
codeLine = "%code int result = " + className + fName[0].upper() + fName[1:] + "("
codeArgsLine = ""
failLine = "%fail {result < 0} {getError();}\n"
if args != []:
count = 1
for arg in args:
#arg is a dictionary
if arg.has_key('name'):
argName = arg['name']
else:
argName = ")"
if argName == "in":
argName = "i_n"
aName = ""
for i in range(len(argName)):
ch = argName[i]
if ch == '=' or ch == '>' or ch == '<' or ch == '*':
ch = '_'
aName += ch
if str(aName)[0] in ["0","1","2","3","4","5","6","7","8","9"]:
aName = "("
if aName[0] == '"':
aName = aName[1:len(aName)-1]
if not aName in ["(",")","f","_","true","false"]:
count += 1
if arg.has_key('type') and arg['type'] in ["String","Int"]:
argType = arg['type']
else:
argType = "Int"
argType = convertArgType(argType)
aType = ""
if ("Ptr" in argType):
for i in range(len(argType)):
ch = argType[i]
if ch == '=' or ch == '<' or ch == '>' or ch == '*':
ch = '_'
aType += ch
else:
aType += ch
argType = aType
dType = "data " + argType + " = " + argType + " Int\n"
if dType not in listOfArgumentTypes:
listOfArgumentTypes.append(dType)
listOfDataTypes.append(dType)
returnCode += argType
returnCode += " -> "
callLine += "(" + argType[0].lower() + argType[1:] + " " + aName + ") "
if codeArgsLine != "":
codeArgsLine += ", " + aName
else:
codeArgsLine += aName
codeLine += codeArgsLine + ");\n"
returnCode += "IO ()\n"
returnCode += callLine + "\n"
returnCode += codeLine
returnCode += failLine + "\n\n"
return [listOfDataTypes, returnCode]
def createCInterface(className, functionName, args, returnType):
returnCode = ""
hDeclaration = ""
functionCall = ""
fName = ""
for i in range(len(functionName)):
ch = functionName[i]
if ch == '*' or ch == '=' or ch == '(' or ch == ')':
ch = '_'
fName += ch
else:
fName += ch
if fName != "":
returnCode = "extern \"C\" int " + className + fName[0].upper() + fName[1:] + "("
hDeclaration = "int " + className + fName[0].upper() + fName[1:] + "("
functionCall = functionName + "("
if args != []:
args_len = 0
counter = 1
count = 1
for arg in args:
if arg.has_key('name'):
if not arg['name'] in [")","f","(","_","true","false"] and not str(arg['name'])[0] in ["0","1","2","3","4","5","6","7","8","9",">"]:
args_len += 1
for arg in args:
if arg.has_key('name') and not arg['name'] in [")","f","(","_","true","false"] and not str(arg['name'])[0] in ["0","1","2","3","4","5","6","7","8","9",">"]:
argName = arg['name']
else:
argName = ")"
aName = ""
for i in range(len(argName)):
ch = argName[i]
if ch == '*' or ch == '=' or ch == '<' or ch == '<':
if len(argName) != 1:
ch = '_'
aName += ch
else:
aName = ")"
else:
aName += ch
if aName[0] == '"':
aName = aName[1:len(aName) - 1]
if aName != ")":
count += 1
if arg.has_key('type'):
argType = arg['type']
else:
argType = "int"
argType = getArgType(argType)
returnCode += argType + " " + aName
hDeclaration += argType + " " + aName
functionCall += aName
if counter < args_len:
returnCode += ", "
hDeclaration += ", "
functionCall += ", "
counter += 1
functionCall += ");\n"
hDeclaration += ");\n\n"
returnCode += ")" + "\n{\n\n"
if (returnType == "void"):
returnCode += "\t" + className[0].lower() + className[1:] + "Obj->" + functionCall
else:
returnCode += "\t" + className[0].lower() + className[1:] + "Obj = " + functionCall
returnCode += "\treturn (int) " + className[0].lower() + className[1:] + "Obj;\n"
returnCode += "\n}\n\n"
return [hDeclaration, returnCode]
try:
if mode == 0:
cppHeader = CppHeaderParser.CppHeader("/home/ecochran/Desktop/irrlicht/include/SMaterial.h")
else:
pass
except CppHeaderParser.CppParseError, e:
print "Exception: ", e
sys.exit(1)
if mode == 0:
mist = cppHeader.classes
for className,j in mist.iteritems():
Namespaces = j['namespace']
API_methods = j['methods']['public']
if API_methods != []:
print className, "%%%%%"
for m in API_methods:
print "method ", m, " namespace(s): ", Namespaces
if mode == 1:
cInterface_cpp.write("""
#include "c_interface.h"
#include "irrlicht.h"
#include <stdlib.h>
#include <iostream>
using namespace std;
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
using namespace std;\n\n""")
cInterface_h.write("""#ifdef __cplusplus
extern "C" {
#endif\n\n""")
greenCardSpec.write("""{-# LANGUAGE ForeignFunctionInterface #-}
module Irrlicht where
import Foreign.GreenCard
%#include "c_interface.h"\n\n""")
all_classes = {}
dirList = os.listdir(irrlichtIncludePath)
print "Parsing header files...\n"
for fname in dirList:
if fname[-2:] == ".h" and fname[0].isupper() and fname != "IQ3Shader.h":
#now we have a header file
cppHeader = CppHeaderParser.CppHeader(irrlichtIncludePath+"/"+fname)
all_classes[fname] = cppHeader.classes
print "Done parsing header files.\n"
print "Generating Green Card spec...\n"
for headerFile, listOfClasses in all_classes.iteritems():
if listOfClasses != {}:
for irrClass in listOfClasses.iteritems():
functions = listOfClasses[irrClass[0]]['methods']['public']
className = irrClass[0]
for function in functions:
args = function['parameters']
functionName = function['name']
functionName = functionName.replace(">","")
functionName = functionName.replace(")","")
functionName = functionName.replace("<","")
functionName = functionName.replace("=","")
functionName = functionName.replace("+","")
returnType = ""
returnTypeString = function['rtnType']
returnTypeList = returnTypeString.rsplit()
ret_len = len(returnTypeList)
if ("void" in returnTypeList):
returnType = "void"
elif ("bool" in returnTypeList):
returnType = "bool"
elif (returnTypeList[ret_len-1] == "*"):
returnType = returnTypeList[ret_len-2] + " " + returnTypeList[ret_len-1]
cFile = []
cFile = createCInterface(className, functionName, args, returnType)
cInterface_h.write(cFile[0])
cInterface_cpp.write(cFile[1])
greenCardData = []
greenCardData = createHaskellSpecification(className, functionName, args, returnType)
fun_spec = greenCardData[1]
data_type = greenCardData[0]
for dType in data_type:
greenCardSpec.write(dType)
greenCardSpec.write(fun_spec)
print "Done generating Green Card spec.\n"
cInterface_h.write("""#ifdef __cplusplus
}
#endif\n""")
cInterface_cpp.close()
cInterface_h.close()
greenCardSpec.close()