#!/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 #include 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()