packages feed

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()