packages feed

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