Completing parser to parse generic/template return types; adding standard method...
[iot2.git] / iotjava / iotpolicy / IoTCompiler.java
index 8849c4d5dc55ea7471a2df4025c536be204e76b3..94029cad39c9e16d5040fef0578123b142466d52 100644 (file)
@@ -3,6 +3,8 @@ package iotpolicy;
 import java_cup.runtime.ComplexSymbolFactory;
 import java_cup.runtime.ScannerBuffer;
 import java.io.*;
+import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -48,6 +50,8 @@ public class IoTCompiler {
        private Map<String,String> mapPrimitives;
        private Map<String,String> mapNonPrimitivesJava;
        private Map<String,String> mapNonPrimitivesCplus;
+       // Other data structures
+       private Map<String,Integer> mapIntfaceObjId;    // Maps interface name to object Id
        private PrintWriter pw;
        private String dir;
        private String subdir;
@@ -72,6 +76,7 @@ public class IoTCompiler {
                mapIntfacePTH = new HashMap<String,ParseTreeHandler>();
                mapIntDeclHand = new HashMap<String,DeclarationHandler>();
                mapInt2NewInts = new HashMap<String,Map<String,Set<String>>>();
+               mapIntfaceObjId = new HashMap<String,Integer>();
                mapPrimitives = new HashMap<String,String>();
                        arraysToMap(mapPrimitives, IoTRMITypes.primitivesJava, IoTRMITypes.primitivesCplus);
                mapNonPrimitivesJava = new HashMap<String,String>();
@@ -85,7 +90,7 @@ public class IoTCompiler {
 
 
        /**
-        * setParseTree() sets parse tree based on policy files.
+        * setDataStructures() sets parse tree and other data structures based on policy files.
         * <p>
         * It also generates parse tree (ParseTreeHandler) and
         * copies useful information from parse tree into
@@ -95,11 +100,10 @@ public class IoTCompiler {
         * returned from tree-parsing for further process.
         *
         */
-       public void setParseTree(String origInt, ParseNode pnPol, ParseNode pnReq) {
+       public void setDataStructures(String origInt, ParseNode pnPol, ParseNode pnReq) {
 
                ParseTreeHandler ptHandler = new ParseTreeHandler(origInt, pnPol, pnReq);
                DeclarationHandler decHandler = new DeclarationHandler();
-
                // Process ParseNode and generate Declaration objects
                ptHandler.processInterfaceDecl();
                InterfaceDecl intDecl = ptHandler.getInterfaceDecl();
@@ -113,6 +117,9 @@ public class IoTCompiler {
 
                mapIntfacePTH.put(origInt, ptHandler);
                mapIntDeclHand.put(origInt, decHandler);
+               // Set object Id counter to 0 for each interface
+               mapIntfaceObjId.put(origInt, new Integer(0));
+               //System.out.println("\nInterface: " + origInt + "\n\n");
        }
 
 
@@ -253,6 +260,83 @@ public class IoTCompiler {
        }
 
 
+       /**
+        * HELPER: writePropertiesJavaStub() writes the properties of the stub class
+        */
+       private void writePropertiesJavaStub(String intface) {
+
+               println("private IoTRMICall rmiCall;");
+               //println("private IoTRMIObject rmiObj;");
+               println("private String address;");
+               println("private int[] ports;\n");
+               // Get the object Id
+               Integer objId = mapIntfaceObjId.get(intface);
+               println("private final static int objectId = " + objId + ";");
+               mapIntfaceObjId.put(intface, objId++);
+               println("\n");
+       }
+
+
+       /**
+        * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
+        */
+       private void writeConstructorJavaStub(String intface) {
+
+               println("public " + intface + "(int _port, String _address, int _rev, int[] _ports) throws Exception {");
+               println("address = _address;");
+               println("ports = _ports;");
+               println("rmiCall = new IoTRMICall(_port, _address, _rev);");
+               println("}\n");
+       }
+
+
+       /**
+        * HELPER: writeStdMethodBodyJavaStub() writes the standard method body in the stub class
+        */
+       private void writeStdMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
+                       List<String> methPrmTypes, String method) {
+
+               println("int methodId = " + intDecl.getMethodNumId(method) + ";");
+               String retType = intDecl.getMethodType(method);
+               println("Class<?> retType = " + getSimpleType(retType) + ".class;");
+               // Generate array of parameter types
+               print("Class<?>[] paramCls = new Class<?>[] { ");
+               for (int i = 0; i < methParams.size(); i++) {
+                       print(getSimpleType(methPrmTypes.get(i)) + ".class");
+                       // Check if this is the last element (don't print a comma)
+                       if (i != methParams.size() - 1) {
+                               print(", ");
+                       }
+               }
+               println(" };");
+               // Generate array of parameter objects
+               print("Object[] paramObj = new Object[] { ");
+               for (int i = 0; i < methParams.size(); i++) {
+                       print(getSimpleIdentifier(methParams.get(i)));
+                       // Check if this is the last element (don't print a comma)
+                       if (i != methParams.size() - 1) {
+                               print(", ");
+                       }
+               }
+               println(" };");
+               // Check if this is "void"
+               if (retType.equals("void")) {
+                       println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
+               } else { // We do have a return value
+               // Check if the return value NONPRIMITIVES
+                       if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
+                               String[] retGenValType = getTypeOfGeneric(retType);
+                               println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
+                               println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
+                               println("return (" + retType + ")retObj;");
+                       } else {
+                               println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
+                               println("return (" + retType + ")retObj;");
+                       }
+               }
+       }
+
+
        /**
         * HELPER: writeMethodJavaStub() writes the method of the stub class
         */
@@ -273,12 +357,9 @@ public class IoTCompiler {
                                }
                        }
                        println(") {");
-                       // Check if this is not "void"
-                       if (!intDecl.getMethodType(method).equals("void")) {
-                               String retStmt = generateReturnStmt(intDecl.getMethodType(method));
-                               println("return " + retStmt + ";");
-                       }
-                       println("}"); println("");
+                       // Now, write the body of stub!
+                       writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method);
+                       println("}\n");
                }
        }
 
@@ -304,11 +385,15 @@ public class IoTCompiler {
                                InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
                                // Pass in set of methods and get import classes
                                Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
-                               printImportStatements(importClasses);
+                               List<String> stdImportClasses = getStandardJavaImportClasses();
+                               List<String> allImportClasses = getAllImportClasses(stdImportClasses, importClasses);
+                               printImportStatements(allImportClasses); println("");
                                // Write interface header
-                               println("");
-                               println("public class " + newStubClass + " implements " + newIntface + " {");
-                               println("");
+                               println("public class " + newStubClass + " implements " + newIntface + " {\n");
+                               // Write properties
+                               writePropertiesJavaStub(intface);
+                               // Write constructor
+                               writeConstructorJavaStub(newStubClass);
                                // Write methods
                                writeMethodJavaStub(intMeth.getValue(), intDecl);
                                println("}");
@@ -328,7 +413,7 @@ public class IoTCompiler {
 
                        List<String> methParams = intDecl.getMethodParams(method);
                        List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
-                       print("virtual " + convertType(intDecl.getMethodType(method)) + " " +
+                       print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
                                intDecl.getMethodId(method) + "(");
                        for (int i = 0; i < methParams.size(); i++) {
                                // Check for params with driver class types and exchange it 
@@ -365,23 +450,22 @@ public class IoTCompiler {
                        FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp");
                        pw = new PrintWriter(new BufferedWriter(fw));
                        // Write file headers
+                       println("#ifndef _" + intface.toUpperCase() + "_HPP__");
+                       println("#define _" + intface.toUpperCase() + "_HPP__");
                        println("#include <iostream>");
                        // Pass in set of methods and get include classes
                        DeclarationHandler decHandler = mapIntDeclHand.get(intface);
                        InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
                        List<String> methods = intDecl.getMethods();
                        Set<String> includeClasses = getIncludeClasses(methods, intDecl);
-                       printIncludeStatements(includeClasses);
-                       println("");
-                       println("using namespace std;");
-                       println("");
-                       println("class " + intface);
-                       println("{");
+                       printIncludeStatements(includeClasses); println("");
+                       println("using namespace std;\n");
+                       println("class " + intface); println("{");
                        println("public:");
                        // Write methods
                        writeMethodCplusInterface(methods, intDecl);
-                       print("}");
-                       println(";");
+                       println("};");
+                       println("#endif");
                        pw.close();
                        System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp...");
                }
@@ -409,20 +493,22 @@ public class IoTCompiler {
                                DeclarationHandler decHandler = mapIntDeclHand.get(intface);
                                InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
                                // Write file headers
+                               println("#ifndef _" + newIntface.toUpperCase() + "_HPP__");
+                               println("#define _" + newIntface.toUpperCase() + "_HPP__");
                                println("#include <iostream>");
                                // Pass in set of methods and get import classes
                                Set<String> includeClasses = getIncludeClasses(intMeth.getValue(), intDecl);
-                               printIncludeStatements(includeClasses);
-                               println("");
-                               println("using namespace std;");
-                               println("");
+                               List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
+                               List<String> allIncludeClasses = getAllImportClasses(stdIncludeClasses, includeClasses);
+                               printIncludeStatements(allIncludeClasses); println("");                 
+                               println("using namespace std;\n");
                                println("class " + newIntface);
                                println("{");
                                println("public:");
                                // Write methods
                                writeMethodCplusInterface(intMeth.getValue(), intDecl);
-                               print("}");
-                               println(";");
+                               println("};");
+                               println("#endif");
                                pw.close();
                                System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
                        }
@@ -439,7 +525,7 @@ public class IoTCompiler {
 
                        List<String> methParams = intDecl.getMethodParams(method);
                        List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
-                       print(convertType(intDecl.getMethodType(method)) + " " +
+                       print(checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
                                intDecl.getMethodId(method) + "(");
                        for (int i = 0; i < methParams.size(); i++) {
                                String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
@@ -451,16 +537,102 @@ public class IoTCompiler {
                                }
                        }
                        println(") { ");
-                       // Check if this is not "void"
-                       if (!intDecl.getMethodType(method).equals("void")) {
-                               String retStmt = generateReturnStmt(intDecl.getMethodType(method));
-                               if (retStmt.equals("null")) { // null = NULL in C++
-                                       retStmt = "NULL";
-                               }
-                               println("return " + retStmt + ";");
+                       writeStdMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method);
+                       println("}\n");
+               }
+       }
+
+
+       /**
+        * HELPER: writeStdMethodBodyCplusStub() writes the standard method body in the stub class
+        */
+       private void writeStdMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
+                       List<String> methPrmTypes, String method) {
+
+               println("int numParam = " + methParams.size() + ";");
+               println("int methodId = " + intDecl.getMethodNumId(method) + ";");
+               String retType = intDecl.getMethodType(method);
+               println("string retType = \"" + checkAndGetCplusType(retType) + "\";");
+               // Generate array of parameter types
+               print("string paramCls[] = { ");
+               for (int i = 0; i < methParams.size(); i++) {
+                       print("\"" + checkAndGetCplusType(methPrmTypes.get(i)) + "\"");
+                       // Check if this is the last element (don't print a comma)
+                       if (i != methParams.size() - 1) {
+                               print(", ");
                        }
-                       println("}"); println("");
                }
+               println(" };");
+               // Generate array of parameter objects
+               print("void* paramObj[] = { ");
+               for (int i = 0; i < methParams.size(); i++) {
+                       print("&" + checkAndGetCplusType(getSimpleIdentifier(methParams.get(i))));
+                       // Check if this is the last element (don't print a comma)
+                       if (i != methParams.size() - 1) {
+                               print(", ");
+                       }
+               }
+               println(" };");
+               // Check if this is "void"
+               if (retType.equals("void")) {
+                       println("void* retObj = NULL;");
+                       println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
+               } else { // We do have a return value
+                       if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
+                               println(checkAndGetCplusType(retType) + " retVal;");
+                       else
+                               println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
+                       println("void* retObj = &retVal;");
+                       println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
+                       println("return retVal;");
+               }
+       }
+
+
+       /**
+        * HELPER: writePropertiesCplusStub() writes the properties of the stub class
+        */
+       private void writePropertiesCplusStub(String intface) {
+
+               println("IoTRMICall\t\t\t*rmiCall;");
+               //println("IoTRMIObject\t\t\t*rmiObj;");
+               println("string\t\t\t\taddress;");
+               println("vector<int>\t\t\tports;\n");
+               // Get the object Id
+               Integer objId = mapIntfaceObjId.get(intface);
+               println("const static int\tobjectId = " + objId + ";");
+               mapIntfaceObjId.put(intface, objId++);
+               println("\n");
+       }
+
+
+       /**
+        * HELPER: writeConstructorCplusStub() writes the constructor of the stub class
+        */
+       private void writeConstructorCplusStub(String newStubClass) {
+
+               println(newStubClass + 
+                       "(int _port, const char* _address, int _rev, bool* _bResult, vector<int> _ports) {");
+               println("address = _address;");
+               println("ports = _ports;");
+               println("rmiCall = new IoTRMICall(_port, _address, _rev, _bResult);");
+               println("}\n");
+       }
+
+
+       /**
+        * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
+        */
+       private void writeDeconstructorCplusStub(String newStubClass) {
+
+               println("~" + newStubClass + "() {");
+               println("if (rmiCall != NULL) {");
+               println("delete rmiCall;");
+               println("rmiCall = NULL;");
+               println("}");
+               println("}");
+               println("");
+               // Check if this is callback!!! and print "delete rmiObj and vecCBObj"
        }
 
 
@@ -481,19 +653,25 @@ public class IoTCompiler {
                                FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
                                pw = new PrintWriter(new BufferedWriter(fw));
                                // Write file headers
+                               println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
+                               println("#define _" + newStubClass.toUpperCase() + "_HPP__");
                                println("#include <iostream>");
                                println("#include \"" + newIntface + ".hpp\""); println("");            
                                println("using namespace std;"); println("");
                                println("class " + newStubClass + " : public " + newIntface); println("{");
-                               println("public:"); println("");
+                               println("private:\n");
+                               writePropertiesCplusStub(intface);
+                               println("public:\n");
                                // Add default constructor and destructor
                                println(newStubClass + "() { }"); println("");
-                               println("~" + newStubClass + "() { }"); println("");
+                               writeConstructorCplusStub(newStubClass);
+                               writeDeconstructorCplusStub(newStubClass);
                                DeclarationHandler decHandler = mapIntDeclHand.get(intface);
                                InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
                                // Write methods
                                writeMethodCplusStub(intMeth.getValue(), intDecl);
                                print("}"); println(";");
+                               println("#endif");
                                pw.close();
                                System.out.println("IoTCompiler: Generated stub class " + newIntface + ".hpp...");
                        }
@@ -501,6 +679,36 @@ public class IoTCompiler {
        }
 
 
+       /**
+        * generateInitializer() generate initializer based on type
+        */
+       public String generateCplusInitializer(String type) {
+
+               // Generate dummy returns for now
+               if (type.equals("short")||
+                       type.equals("int")      ||
+                       type.equals("long") ||
+                       type.equals("float")||
+                       type.equals("double")) {
+
+                       return "0";
+               } else if ( type.equals("String") ||
+                                       type.equals("string")) {
+  
+                       return "\"\"";
+               } else if ( type.equals("char") ||
+                                       type.equals("byte")) {
+
+                       return "\' \'";
+               } else if ( type.equals("boolean")) {
+
+                       return "false";
+               } else {
+                       return "NULL";
+               }
+       }
+
+
        /**
         * generateReturnStmt() generate return statement based on methType
         */
@@ -602,6 +810,7 @@ public class IoTCompiler {
                newline=false;
        }
 
+
        /**
         * This function converts Java to C++ type for compilation
         */
@@ -722,6 +931,50 @@ public class IoTCompiler {
        }
 
 
+       // Generate a set of standard classes for import statements
+       private List<String> getStandardJavaImportClasses() {
+
+               List<String> importClasses = new ArrayList<String>();
+               // Add the standard list first
+               importClasses.add("java.io.IOException");
+               importClasses.add("java.util.List");
+               importClasses.add("java.util.ArrayList");
+               importClasses.add("iotrmi.Java.IoTRMICall");
+               importClasses.add("iotrmi.Java.IoTRMIObject");
+
+               return importClasses;
+       }
+
+
+       // Generate a set of standard classes for import statements
+       private List<String> getStandardCplusIncludeClasses() {
+
+               List<String> importClasses = new ArrayList<String>();
+               // Add the standard list first
+               importClasses.add("<vector>");
+               importClasses.add("\"IoTRMICall.hpp\"");
+               importClasses.add("\"IoTRMIObject.hpp\"");
+
+               return importClasses;
+       }
+
+
+       // Generate a set of standard classes for import statements
+       private List<String> getAllImportClasses(Collection<String> stdImportClasses, Collection<String> importClasses) {
+
+               List<String> allImportClasses = new ArrayList<String>(stdImportClasses);
+               // Iterate over the list of import classes
+               for (String str : importClasses) {
+                       if (!stdImportClasses.contains(str)) {
+                               stdImportClasses.add(str);
+                       }
+               }
+
+               return allImportClasses;
+       }
+
+
+
        // Generate a set of classes for import statements
        private Set<String> getImportClasses(Collection<String> methods, InterfaceDecl intDecl) {
 
@@ -766,7 +1019,7 @@ public class IoTCompiler {
        }
 
 
-       private void printImportStatements(Set<String> importClasses) {
+       private void printImportStatements(Collection<String> importClasses) {
 
                for(String cls : importClasses) {
                        println("import " + cls + ";");
@@ -774,7 +1027,7 @@ public class IoTCompiler {
        }
 
 
-       private void printIncludeStatements(Set<String> includeClasses) {
+       private void printIncludeStatements(Collection<String> includeClasses) {
 
                for(String cls : includeClasses) {
                        println("#include " + cls);
@@ -793,6 +1046,18 @@ public class IoTCompiler {
        }
 
 
+       // This helper function strips off array declaration, e.g. D[] becomes D
+       private String getSimpleIdentifier(String ident) {
+
+               // Handle [ for array declaration
+               String substr = ident;
+               if (ident.contains("[]")) {
+                       substr = ident.split("\\[\\]")[0];
+               }
+               return substr;
+       }
+
+
        private String checkAndGetCplusType(String paramType) {
 
                if (getParamCategory(paramType) == ParamCategory.PRIMITIVES) {
@@ -905,7 +1170,7 @@ public class IoTCompiler {
                                ParseNode pnReq = IoTCompiler.parseFile(args[i+1]);
                                // Get interface name
                                String intface = ParseTreeHandler.getOrigIntface(pnPol);
-                               comp.setParseTree(intface, pnPol, pnReq);
+                               comp.setDataStructures(intface, pnPol, pnReq);
                                comp.getMethodsForIntface(intface);
                                i = i + 2;
                        // 1) Check if this is the last option before "-java" or "-cplus"