IrrHaskell-0.1.1: 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 = []
if functionName != "":
returnCode += "%fun " + className + functionName[0].upper() + functionName[1:] + " :: "
callLine = "%call "
codeLine = "%code int result = " + className + functionName[0].upper() + functionName[1:] + "("
codeArgsLine = ""
failLine = "%fail {result < 0} {getError();}\n"
if args != []:
count = 1
for arg in args:
#arg is a dictionary
if arg.has_key('type'):
argType = arg['type']
else:
argType = "Int"
argType = convertArgType(argType)
if ("Ptr" in argType):
dType = "data " + argType + " = " + argType + " Int\n"
if dType not in listOfArgumentTypes:
listOfArgumentTypes.append(dType)
listOfDataTypes.append(dType)
returnCode += argType
returnCode += " -> "
if arg.has_key('name'):
argName = arg['name']
else:
argName = "arg" + str(count)
count += 1
callLine += "(" + argType[0].lower() + argType[1:] + " " + argName + ") "
if codeArgsLine != "":
codeArgsLine += ", " + argName
else:
codeArgsLine += argName
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 = ""
if functionName != "":
returnCode = "extern \"C\" int " + className + functionName[0].upper() + functionName[1:] + "("
hDeclaration = "int " + className + functionName[0].upper() + functionName[1:] + "("
functionCall = functionName + "("
if args != []:
args_len = len(args)
counter = 1
count = 1
for arg in args:
if arg.has_key('name'):
argName = arg['name']
else:
argName = "arg" + str(count)
count += 1
if arg.has_key('type'):
argType = arg['type']
else:
argType = "int"
argType = getArgType(argType)
returnCode += argType + " " + argName
hDeclaration += argType + " " + argName
functionCall += argName
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" + returnType + " " + "temp = " + className[0].lower() + className[1:] + "Obj->" + functionCall
returnCode += "\treturn (int) temp;\n"
returnCode += "\n}\n\n"
return [hDeclaration, returnCode]
try:
if mode == 0:
cppHeader = CppHeaderParser.CppHeader("/home/maciek/Desktop/irrlicht-1.6/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(">","")
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()