3 import java_cup.runtime.ComplexSymbolFactory;
4 import java_cup.runtime.ScannerBuffer;
6 import java.util.Arrays;
7 import java.util.ArrayList;
8 import java.util.Collection;
9 import java.util.Collections;
10 import java.util.HashMap;
11 import java.util.HashSet;
12 import java.util.Iterator;
13 import java.util.List;
17 import iotpolicy.parser.Lexer;
18 import iotpolicy.parser.Parser;
19 import iotpolicy.tree.ParseNode;
20 import iotpolicy.tree.ParseNodeVector;
21 import iotpolicy.tree.ParseTreeHandler;
22 import iotpolicy.tree.Declaration;
23 import iotpolicy.tree.DeclarationHandler;
24 import iotpolicy.tree.CapabilityDecl;
25 import iotpolicy.tree.InterfaceDecl;
26 import iotpolicy.tree.RequiresDecl;
28 import iotrmi.Java.IoTRMITypes;
31 /** Class IoTCompiler is the main interface/stub compiler for
32 * files generation. This class calls helper classes
33 * such as Parser, Lexer, InterfaceDecl, CapabilityDecl,
34 * RequiresDecl, ParseTreeHandler, etc.
36 * @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
40 public class IoTCompiler {
45 // Maps multiple interfaces to multiple objects of ParseTreeHandler
46 private Map<String,ParseTreeHandler> mapIntfacePTH;
47 private Map<String,DeclarationHandler> mapIntDeclHand;
48 private Map<String,Map<String,Set<String>>> mapInt2NewInts;
49 // Data structure to store our types (primitives and non-primitives) for compilation
50 private Map<String,String> mapPrimitives;
51 private Map<String,String> mapNonPrimitivesJava;
52 private Map<String,String> mapNonPrimitivesCplus;
53 // Other data structures
54 private Map<String,Integer> mapIntfaceObjId; // Maps interface name to object Id
55 private PrintWriter pw;
57 private String subdir;
62 private final static String OUTPUT_DIRECTORY = "output_files";
64 private enum ParamCategory {
66 PRIMITIVES, // All the primitive types, e.g. byte, short, int, long, etc.
67 NONPRIMITIVES, // Non-primitive types, e.g. Set, Map, List, etc.
68 USERDEFINED // Non-supported type by default; assumed as driver classes
74 public IoTCompiler() {
76 mapIntfacePTH = new HashMap<String,ParseTreeHandler>();
77 mapIntDeclHand = new HashMap<String,DeclarationHandler>();
78 mapInt2NewInts = new HashMap<String,Map<String,Set<String>>>();
79 mapIntfaceObjId = new HashMap<String,Integer>();
80 mapPrimitives = new HashMap<String,String>();
81 arraysToMap(mapPrimitives, IoTRMITypes.primitivesJava, IoTRMITypes.primitivesCplus);
82 mapNonPrimitivesJava = new HashMap<String,String>();
83 arraysToMap(mapNonPrimitivesJava, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitiveJavaLibs);
84 mapNonPrimitivesCplus = new HashMap<String,String>();
85 arraysToMap(mapNonPrimitivesCplus, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitivesCplus);
87 dir = OUTPUT_DIRECTORY;
93 * setDataStructures() sets parse tree and other data structures based on policy files.
95 * It also generates parse tree (ParseTreeHandler) and
96 * copies useful information from parse tree into
97 * InterfaceDecl, CapabilityDecl, and RequiresDecl
99 * Additionally, the data structure handles are
100 * returned from tree-parsing for further process.
103 public void setDataStructures(String origInt, ParseNode pnPol, ParseNode pnReq) {
105 ParseTreeHandler ptHandler = new ParseTreeHandler(origInt, pnPol, pnReq);
106 DeclarationHandler decHandler = new DeclarationHandler();
107 // Process ParseNode and generate Declaration objects
108 ptHandler.processInterfaceDecl();
109 InterfaceDecl intDecl = ptHandler.getInterfaceDecl();
110 decHandler.addInterfaceDecl(origInt, intDecl);
111 ptHandler.processCapabilityDecl();
112 CapabilityDecl capDecl = ptHandler.getCapabilityDecl();
113 decHandler.addCapabilityDecl(origInt, capDecl);
114 ptHandler.processRequiresDecl();
115 RequiresDecl reqDecl = ptHandler.getRequiresDecl();
116 decHandler.addRequiresDecl(origInt, reqDecl);
118 mapIntfacePTH.put(origInt, ptHandler);
119 mapIntDeclHand.put(origInt, decHandler);
120 // Set object Id counter to 0 for each interface
121 mapIntfaceObjId.put(origInt, new Integer(0));
122 //System.out.println("\nInterface: " + origInt + "\n\n");
127 * getMethodsForIntface() reads for methods in the data structure
129 * It is going to give list of methods for a certain interface
130 * based on the declaration of capabilities.
132 public void getMethodsForIntface(String origInt) {
134 ParseTreeHandler ptHandler = mapIntfacePTH.get(origInt);
135 Map<String,Set<String>> mapNewIntMethods = new HashMap<String,Set<String>>();
136 // Get set of new interfaces, e.g. CameraWithCaptureAndData
137 // Generate this new interface with all the methods it needs
138 // from different capabilities it declares
139 DeclarationHandler decHandler = mapIntDeclHand.get(origInt);
140 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(origInt);
141 Set<String> setIntfaces = reqDecl.getInterfaces();
142 for (String strInt : setIntfaces) {
144 // Initialize a set of methods
145 Set<String> setMethods = new HashSet<String>();
146 // Get list of capabilities, e.g. ImageCapture, VideoRecording, etc.
147 List<String> listCapab = reqDecl.getCapabList(strInt);
148 for (String strCap : listCapab) {
150 // Get list of methods for each capability
151 CapabilityDecl capDecl = (CapabilityDecl) decHandler.getCapabilityDecl(origInt);
152 List<String> listCapabMeth = capDecl.getMethods(strCap);
153 for (String strMeth : listCapabMeth) {
155 // Add methods into setMethods
156 // This is to also handle redundancies (say two capabilities
157 // share the same methods)
158 setMethods.add(strMeth);
161 // Add interface and methods information into map
162 mapNewIntMethods.put(strInt, setMethods);
164 // Map the map of interface-methods to the original interface
165 mapInt2NewInts.put(origInt, mapNewIntMethods);
170 * HELPER: writeMethodJavaInterface() writes the method of the interface
172 private void writeMethodJavaInterface(Collection<String> methods, InterfaceDecl intDecl) {
174 for (String method : methods) {
176 List<String> methParams = intDecl.getMethodParams(method);
177 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
178 print("public " + intDecl.getMethodType(method) + " " +
179 intDecl.getMethodId(method) + "(");
180 for (int i = 0; i < methParams.size(); i++) {
181 // Check for params with driver class types and exchange it
182 // with its remote interface
183 String paramType = checkAndGetParamClass(methPrmTypes.get(i), false);
184 print(paramType + " " + methParams.get(i));
185 // Check if this is the last element (don't print a comma)
186 if (i != methParams.size() - 1) {
196 * generateJavaLocalInterface() writes the local interface and provides type-checking.
198 * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
199 * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
200 * The local interface has to be the input parameter for the stub and the stub
201 * interface has to be the input parameter for the local class.
203 public void generateJavaLocalInterfaces() throws IOException {
205 // Create a new directory
206 createDirectory(dir);
207 for (String intface : mapIntfacePTH.keySet()) {
208 // Open a new file to write into
209 FileWriter fw = new FileWriter(dir + "/" + intface + ".java");
210 pw = new PrintWriter(new BufferedWriter(fw));
211 // Pass in set of methods and get import classes
212 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
213 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
214 List<String> methods = intDecl.getMethods();
215 Set<String> importClasses = getImportClasses(methods, intDecl);
216 printImportStatements(importClasses);
217 // Write interface header
219 println("public interface " + intface + " {");
221 writeMethodJavaInterface(methods, intDecl);
224 System.out.println("IoTCompiler: Generated local interface " + intface + ".java...");
230 * generateJavaInterfaces() generate stub interfaces based on the methods list in Java
232 public void generateJavaInterfaces() throws IOException {
234 // Create a new directory
235 String path = createDirectories(dir, subdir);
236 for (String intface : mapIntfacePTH.keySet()) {
238 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
239 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
241 // Open a new file to write into
242 String newIntface = intMeth.getKey();
243 FileWriter fw = new FileWriter(path + "/" + newIntface + ".java");
244 pw = new PrintWriter(new BufferedWriter(fw));
245 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
246 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
247 // Pass in set of methods and get import classes
248 Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
249 printImportStatements(importClasses);
250 // Write interface header
252 println("public interface " + newIntface + " {");
254 writeMethodJavaInterface(intMeth.getValue(), intDecl);
257 System.out.println("IoTCompiler: Generated interface " + newIntface + ".java...");
264 * HELPER: writePropertiesJavaStub() writes the properties of the stub class
266 private void writePropertiesJavaStub(String intface) {
268 println("private IoTRMICall rmiCall;");
269 //println("private IoTRMIObject rmiObj;");
270 println("private String address;");
271 println("private int[] ports;\n");
273 Integer objId = mapIntfaceObjId.get(intface);
274 println("private final static int objectId = " + objId + ";");
275 mapIntfaceObjId.put(intface, objId++);
281 * HELPER: writeConstructorJavaStub() writes the constructor of the stub class
283 private void writeConstructorJavaStub(String intface) {
285 println("public " + intface + "(int _port, String _address, int _rev, int[] _ports) throws Exception {");
286 println("address = _address;");
287 println("ports = _ports;");
288 println("rmiCall = new IoTRMICall(_port, _address, _rev);");
294 * HELPER: writeStdMethodBodyJavaStub() writes the standard method body in the stub class
296 private void writeStdMethodBodyJavaStub(InterfaceDecl intDecl, List<String> methParams,
297 List<String> methPrmTypes, String method) {
299 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
300 String retType = intDecl.getMethodType(method);
301 println("Class<?> retType = " + getSimpleType(retType) + ".class;");
302 // Generate array of parameter types
303 print("Class<?>[] paramCls = new Class<?>[] { ");
304 for (int i = 0; i < methParams.size(); i++) {
305 print(getSimpleType(methPrmTypes.get(i)) + ".class");
306 // Check if this is the last element (don't print a comma)
307 if (i != methParams.size() - 1) {
312 // Generate array of parameter objects
313 print("Object[] paramObj = new Object[] { ");
314 for (int i = 0; i < methParams.size(); i++) {
315 print(getSimpleIdentifier(methParams.get(i)));
316 // Check if this is the last element (don't print a comma)
317 if (i != methParams.size() - 1) {
322 // Check if this is "void"
323 if (retType.equals("void")) {
324 println("rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
325 } else { // We do have a return value
326 // Check if the return value NONPRIMITIVES
327 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES) {
328 String[] retGenValType = getTypeOfGeneric(retType);
329 println("Class<?> retGenValType = " + retGenValType[0] + ".class;");
330 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, retGenValType, paramCls, paramObj);");
331 println("return (" + retType + ")retObj;");
333 println("Object retObj = rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);");
334 println("return (" + retType + ")retObj;");
341 * HELPER: writeMethodJavaStub() writes the method of the stub class
343 private void writeMethodJavaStub(Collection<String> methods, InterfaceDecl intDecl) {
345 for (String method : methods) {
347 List<String> methParams = intDecl.getMethodParams(method);
348 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
349 print("public " + intDecl.getMethodType(method) + " " +
350 intDecl.getMethodId(method) + "(");
351 for (int i = 0; i < methParams.size(); i++) {
353 print(methPrmTypes.get(i) + " " + methParams.get(i));
354 // Check if this is the last element (don't print a comma)
355 if (i != methParams.size() - 1) {
360 // Now, write the body of stub!
361 writeStdMethodBodyJavaStub(intDecl, methParams, methPrmTypes, method);
368 * generateJavaStubClasses() generate stubs based on the methods list in Java
370 public void generateJavaStubClasses() throws IOException {
372 // Create a new directory
373 String path = createDirectories(dir, subdir);
374 for (String intface : mapIntfacePTH.keySet()) {
376 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
377 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
379 // Open a new file to write into
380 String newIntface = intMeth.getKey();
381 String newStubClass = newIntface + "_Stub";
382 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
383 pw = new PrintWriter(new BufferedWriter(fw));
384 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
385 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
386 // Pass in set of methods and get import classes
387 Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
388 List<String> stdImportClasses = getStandardJavaImportClasses();
389 List<String> allImportClasses = getAllImportClasses(stdImportClasses, importClasses);
390 printImportStatements(allImportClasses); println("");
391 // Write interface header
392 println("public class " + newStubClass + " implements " + newIntface + " {\n");
394 writePropertiesJavaStub(intface);
396 writeConstructorJavaStub(newStubClass);
398 writeMethodJavaStub(intMeth.getValue(), intDecl);
401 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
408 * HELPER: writeMethodCplusInterface() writes the method of the interface
410 private void writeMethodCplusInterface(Collection<String> methods, InterfaceDecl intDecl) {
412 for (String method : methods) {
414 List<String> methParams = intDecl.getMethodParams(method);
415 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
416 print("virtual " + checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
417 intDecl.getMethodId(method) + "(");
418 for (int i = 0; i < methParams.size(); i++) {
419 // Check for params with driver class types and exchange it
420 // with its remote interface
421 String paramType = checkAndGetParamClass(methPrmTypes.get(i), true);
422 paramType = checkAndGetCplusType(paramType);
423 // Check for arrays - translate into vector in C++
424 String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
425 print(paramComplete);
426 // Check if this is the last element (don't print a comma)
427 if (i != methParams.size() - 1) {
437 * generateCplusLocalInterfaces() writes the local interfaces and provides type-checking.
439 * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
440 * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
441 * The local interface has to be the input parameter for the stub and the stub
442 * interface has to be the input parameter for the local class.
444 public void generateCplusLocalInterfaces() throws IOException {
446 // Create a new directory
447 createDirectory(dir);
448 for (String intface : mapIntfacePTH.keySet()) {
449 // Open a new file to write into
450 FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp");
451 pw = new PrintWriter(new BufferedWriter(fw));
452 // Write file headers
453 println("#ifndef _" + intface.toUpperCase() + "_HPP__");
454 println("#define _" + intface.toUpperCase() + "_HPP__");
455 println("#include <iostream>");
456 // Pass in set of methods and get include classes
457 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
458 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
459 List<String> methods = intDecl.getMethods();
460 Set<String> includeClasses = getIncludeClasses(methods, intDecl);
461 printIncludeStatements(includeClasses); println("");
462 println("using namespace std;\n");
463 println("class " + intface); println("{");
466 writeMethodCplusInterface(methods, intDecl);
470 System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp...");
476 * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
478 * For C++ we use virtual classe as interface
480 public void generateCPlusInterfaces() throws IOException {
482 // Create a new directory
483 String path = createDirectories(dir, subdir);
484 for (String intface : mapIntfacePTH.keySet()) {
486 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
487 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
489 // Open a new file to write into
490 String newIntface = intMeth.getKey();
491 FileWriter fw = new FileWriter(path + "/" + newIntface + ".hpp");
492 pw = new PrintWriter(new BufferedWriter(fw));
493 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
494 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
495 // Write file headers
496 println("#ifndef _" + newIntface.toUpperCase() + "_HPP__");
497 println("#define _" + newIntface.toUpperCase() + "_HPP__");
498 println("#include <iostream>");
499 // Pass in set of methods and get import classes
500 Set<String> includeClasses = getIncludeClasses(intMeth.getValue(), intDecl);
501 List<String> stdIncludeClasses = getStandardCplusIncludeClasses();
502 List<String> allIncludeClasses = getAllImportClasses(stdIncludeClasses, includeClasses);
503 printIncludeStatements(allIncludeClasses); println("");
504 println("using namespace std;\n");
505 println("class " + newIntface);
509 writeMethodCplusInterface(intMeth.getValue(), intDecl);
513 System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
520 * HELPER: writeMethodCplusStub() writes the method of the stub
522 private void writeMethodCplusStub(Collection<String> methods, InterfaceDecl intDecl) {
524 for (String method : methods) {
526 List<String> methParams = intDecl.getMethodParams(method);
527 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
528 print(checkAndGetCplusType(intDecl.getMethodType(method)) + " " +
529 intDecl.getMethodId(method) + "(");
530 for (int i = 0; i < methParams.size(); i++) {
531 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
532 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
533 print(methParamComplete);
534 // Check if this is the last element (don't print a comma)
535 if (i != methParams.size() - 1) {
540 writeStdMethodBodyCplusStub(intDecl, methParams, methPrmTypes, method);
547 * HELPER: writeStdMethodBodyCplusStub() writes the standard method body in the stub class
549 private void writeStdMethodBodyCplusStub(InterfaceDecl intDecl, List<String> methParams,
550 List<String> methPrmTypes, String method) {
552 println("int numParam = " + methParams.size() + ";");
553 println("int methodId = " + intDecl.getMethodNumId(method) + ";");
554 String retType = intDecl.getMethodType(method);
555 println("string retType = \"" + checkAndGetCplusType(retType) + "\";");
556 // Generate array of parameter types
557 print("string paramCls[] = { ");
558 for (int i = 0; i < methParams.size(); i++) {
559 print("\"" + checkAndGetCplusType(methPrmTypes.get(i)) + "\"");
560 // Check if this is the last element (don't print a comma)
561 if (i != methParams.size() - 1) {
566 // Generate array of parameter objects
567 print("void* paramObj[] = { ");
568 for (int i = 0; i < methParams.size(); i++) {
569 print("&" + checkAndGetCplusType(getSimpleIdentifier(methParams.get(i))));
570 // Check if this is the last element (don't print a comma)
571 if (i != methParams.size() - 1) {
576 // Check if this is "void"
577 if (retType.equals("void")) {
578 println("void* retObj = NULL;");
579 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
580 } else { // We do have a return value
581 if (getParamCategory(retType) == ParamCategory.NONPRIMITIVES)
582 println(checkAndGetCplusType(retType) + " retVal;");
584 println(checkAndGetCplusType(retType) + " retVal = " + generateCplusInitializer(retType) + ";");
585 println("void* retObj = &retVal;");
586 println("rmiCall->remoteCall(objectId, methodId, retType, paramCls, paramObj, numParam, retObj);");
587 println("return retVal;");
593 * HELPER: writePropertiesCplusStub() writes the properties of the stub class
595 private void writePropertiesCplusStub(String intface) {
597 println("IoTRMICall\t\t\t*rmiCall;");
598 //println("IoTRMIObject\t\t\t*rmiObj;");
599 println("string\t\t\t\taddress;");
600 println("vector<int>\t\t\tports;\n");
602 Integer objId = mapIntfaceObjId.get(intface);
603 println("const static int\tobjectId = " + objId + ";");
604 mapIntfaceObjId.put(intface, objId++);
610 * HELPER: writeConstructorCplusStub() writes the constructor of the stub class
612 private void writeConstructorCplusStub(String newStubClass) {
614 println(newStubClass +
615 "(int _port, const char* _address, int _rev, bool* _bResult, vector<int> _ports) {");
616 println("address = _address;");
617 println("ports = _ports;");
618 println("rmiCall = new IoTRMICall(_port, _address, _rev, _bResult);");
624 * HELPER: writeDeconstructorCplusStub() writes the deconstructor of the stub class
626 private void writeDeconstructorCplusStub(String newStubClass) {
628 println("~" + newStubClass + "() {");
629 println("if (rmiCall != NULL) {");
630 println("delete rmiCall;");
631 println("rmiCall = NULL;");
635 // Check if this is callback!!! and print "delete rmiObj and vecCBObj"
640 * generateCPlusStubClasses() generate stubs based on the methods list in C++
642 public void generateCPlusStubClasses() throws IOException {
644 // Create a new directory
645 String path = createDirectories(dir, subdir);
646 for (String intface : mapIntfacePTH.keySet()) {
648 Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
649 for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
650 // Open a new file to write into
651 String newIntface = intMeth.getKey();
652 String newStubClass = newIntface + "_Stub";
653 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
654 pw = new PrintWriter(new BufferedWriter(fw));
655 // Write file headers
656 println("#ifndef _" + newStubClass.toUpperCase() + "_HPP__");
657 println("#define _" + newStubClass.toUpperCase() + "_HPP__");
658 println("#include <iostream>");
659 println("#include \"" + newIntface + ".hpp\""); println("");
660 println("using namespace std;"); println("");
661 println("class " + newStubClass + " : public " + newIntface); println("{");
662 println("private:\n");
663 writePropertiesCplusStub(intface);
664 println("public:\n");
665 // Add default constructor and destructor
666 println(newStubClass + "() { }"); println("");
667 writeConstructorCplusStub(newStubClass);
668 writeDeconstructorCplusStub(newStubClass);
669 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
670 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
672 writeMethodCplusStub(intMeth.getValue(), intDecl);
673 print("}"); println(";");
676 System.out.println("IoTCompiler: Generated stub class " + newIntface + ".hpp...");
683 * generateInitializer() generate initializer based on type
685 public String generateCplusInitializer(String type) {
687 // Generate dummy returns for now
688 if (type.equals("short")||
689 type.equals("int") ||
690 type.equals("long") ||
691 type.equals("float")||
692 type.equals("double")) {
695 } else if ( type.equals("String") ||
696 type.equals("string")) {
699 } else if ( type.equals("char") ||
700 type.equals("byte")) {
703 } else if ( type.equals("boolean")) {
713 * generateReturnStmt() generate return statement based on methType
715 public String generateReturnStmt(String methType) {
717 // Generate dummy returns for now
718 if (methType.equals("short")||
719 methType.equals("int") ||
720 methType.equals("long") ||
721 methType.equals("float")||
722 methType.equals("double")) {
725 } else if ( methType.equals("String")) {
728 } else if ( methType.equals("char") ||
729 methType.equals("byte")) {
732 } else if ( methType.equals("boolean")) {
742 * setDirectory() sets a new directory for stub files
744 public void setDirectory(String _subdir) {
751 * printUsage() prints the usage of this compiler
753 public static void printUsage() {
755 System.out.println();
756 System.out.println("Sentinel interface and stub compiler version 1.0");
757 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
758 System.out.println("All rights reserved.");
759 System.out.println("Usage:");
760 System.out.println("\tjava IoTCompiler -help / --help / -h\n");
761 System.out.println("\t\tDisplay this help texts\n\n");
762 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>]");
763 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>] [options]\n");
764 System.out.println("\t\tTake one or more pairs of main-req policy files, and generate Java and/or C++ files\n");
765 System.out.println("Options:");
766 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
767 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
768 System.out.println();
773 * parseFile() prepares Lexer and Parser objects, then parses the file
775 public static ParseNode parseFile(String file) {
779 ComplexSymbolFactory csf = new ComplexSymbolFactory();
780 ScannerBuffer lexer =
781 new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(file)),csf));
782 Parser parse = new Parser(lexer,csf);
783 pn = (ParseNode) parse.parse().value;
784 } catch (Exception e) {
786 throw new Error("IoTCompiler: ERROR parsing policy file or wrong command line option: " + file);
797 boolean newline=true;
800 private void print(String str) {
805 for(int i=0; i<tab; i++)
815 * This function converts Java to C++ type for compilation
817 private String convertType(String jType) {
819 return mapPrimitives.get(jType);
823 private void println(String str) {
828 for(int i=0; i<tab; i++)
837 private void updatetabbing(String str) {
838 tablevel+=count(str,'{')-count(str,'}');
842 private int count(String str, char key) {
843 char[] array = str.toCharArray();
845 for(int i=0; i<array.length; i++) {
853 private void createDirectory(String dirName) {
855 File file = new File(dirName);
856 if (!file.exists()) {
858 System.out.println("IoTCompiler: Directory " + dirName + " has been created!");
860 System.out.println("IoTCompiler: Failed to create directory " + dirName + "!");
863 System.out.println("IoTCompiler: Directory " + dirName + " exists...");
868 // Create a directory and possibly a sub directory
869 private String createDirectories(String dir, String subdir) {
872 createDirectory(path);
873 if (subdir != null) {
874 path = path + "/" + subdir;
875 createDirectory(path);
881 // Inserting array members into a Map object
882 // that maps arrKey to arrVal objects
883 private void arraysToMap(Map map, Object[] arrKey, Object[] arrVal) {
885 for(int i = 0; i < arrKey.length; i++) {
887 map.put(arrKey[i], arrVal[i]);
892 // Return parameter category, i.e. PRIMITIVES, NONPRIMITIVES, or USERDEFINED
893 private ParamCategory getParamCategory(String paramType) {
895 if (mapPrimitives.containsKey(paramType)) {
896 return ParamCategory.PRIMITIVES;
897 // We can either use mapNonPrimitivesJava or mapNonPrimitivesCplus here
898 } else if (mapNonPrimitivesJava.containsKey(getSimpleType(paramType))) {
899 return ParamCategory.NONPRIMITIVES;
901 return ParamCategory.USERDEFINED;
905 // Return full class name for non-primitives to generate Java import statements
906 // e.g. java.util.Set for Set, java.util.Map for Map
907 private String getNonPrimitiveJavaClass(String paramNonPrimitives) {
909 return mapNonPrimitivesJava.get(paramNonPrimitives);
913 // Return full class name for non-primitives to generate Cplus include statements
914 // e.g. #include <set> for Set, #include <map> for Map
915 private String getNonPrimitiveCplusClass(String paramNonPrimitives) {
917 return mapNonPrimitivesCplus.get(paramNonPrimitives);
921 // Get simple types, e.g. HashSet for HashSet<...>
922 // Basically strip off the "<...>"
923 private String getSimpleType(String paramType) {
925 // Check if this is generics
926 if(paramType.contains("<")) {
927 String[] type = paramType.split("<");
934 // Generate a set of standard classes for import statements
935 private List<String> getStandardJavaImportClasses() {
937 List<String> importClasses = new ArrayList<String>();
938 // Add the standard list first
939 importClasses.add("java.io.IOException");
940 importClasses.add("java.util.List");
941 importClasses.add("java.util.ArrayList");
942 importClasses.add("iotrmi.Java.IoTRMICall");
943 importClasses.add("iotrmi.Java.IoTRMIObject");
945 return importClasses;
949 // Generate a set of standard classes for import statements
950 private List<String> getStandardCplusIncludeClasses() {
952 List<String> importClasses = new ArrayList<String>();
953 // Add the standard list first
954 importClasses.add("<vector>");
955 importClasses.add("\"IoTRMICall.hpp\"");
956 importClasses.add("\"IoTRMIObject.hpp\"");
958 return importClasses;
962 // Generate a set of standard classes for import statements
963 private List<String> getAllImportClasses(Collection<String> stdImportClasses, Collection<String> importClasses) {
965 List<String> allImportClasses = new ArrayList<String>(stdImportClasses);
966 // Iterate over the list of import classes
967 for (String str : importClasses) {
968 if (!stdImportClasses.contains(str)) {
969 stdImportClasses.add(str);
973 return allImportClasses;
978 // Generate a set of classes for import statements
979 private Set<String> getImportClasses(Collection<String> methods, InterfaceDecl intDecl) {
981 Set<String> importClasses = new HashSet<String>();
982 for (String method : methods) {
983 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
984 for (String paramType : methPrmTypes) {
986 String simpleType = getSimpleType(paramType);
987 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
988 importClasses.add(getNonPrimitiveJavaClass(simpleType));
992 return importClasses;
996 // Generate a set of classes for include statements
997 private Set<String> getIncludeClasses(Collection<String> methods, InterfaceDecl intDecl) {
999 Set<String> includeClasses = new HashSet<String>();
1000 for (String method : methods) {
1002 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
1003 List<String> methParams = intDecl.getMethodParams(method);
1004 for (int i = 0; i < methPrmTypes.size(); i++) {
1006 String simpleType = getSimpleType(methPrmTypes.get(i));
1007 String param = methParams.get(i);
1008 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
1009 includeClasses.add("<" + getNonPrimitiveCplusClass(simpleType) + ">");
1010 } else if (getParamCategory(simpleType) == ParamCategory.USERDEFINED) {
1011 includeClasses.add("\"" + exchangeParamType(simpleType) + ".hpp\"");
1012 } else if (param.contains("[]")) {
1013 // Check if this is array for C++; translate into vector
1014 includeClasses.add("<vector>");
1018 return includeClasses;
1022 private void printImportStatements(Collection<String> importClasses) {
1024 for(String cls : importClasses) {
1025 println("import " + cls + ";");
1030 private void printIncludeStatements(Collection<String> includeClasses) {
1032 for(String cls : includeClasses) {
1033 println("#include " + cls);
1038 // Get the C++ version of a non-primitive type
1039 // e.g. set for Set and map for Map
1040 // Input nonPrimitiveType has to be generics in format
1041 private String[] getTypeOfGeneric(String nonPrimitiveType) {
1043 // Handle <, >, and , for 2-type generic/template
1044 String[] substr = nonPrimitiveType.split("<")[1].split(">")[0].split(",");
1049 // This helper function strips off array declaration, e.g. D[] becomes D
1050 private String getSimpleIdentifier(String ident) {
1052 // Handle [ for array declaration
1053 String substr = ident;
1054 if (ident.contains("[]")) {
1055 substr = ident.split("\\[\\]")[0];
1061 private String checkAndGetCplusType(String paramType) {
1063 if (getParamCategory(paramType) == ParamCategory.PRIMITIVES) {
1064 return convertType(paramType);
1065 } else if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES) {
1067 // Check for generic/template format
1068 if (paramType.contains("<") && paramType.contains(">")) {
1070 String genericClass = getSimpleType(paramType);
1071 String[] genericType = getTypeOfGeneric(paramType);
1072 String cplusTemplate = null;
1073 if (genericType.length == 1) // Generic/template with one type
1074 cplusTemplate = getNonPrimitiveCplusClass(genericClass) +
1075 "<" + convertType(genericType[0]) + ">";
1076 else // Generic/template with two types
1077 cplusTemplate = getNonPrimitiveCplusClass(genericClass) +
1078 "<" + convertType(genericType[0]) + "," + convertType(genericType[1]) + ">";
1079 return cplusTemplate;
1081 return getNonPrimitiveCplusClass(paramType);
1083 // Just return it as is if it's not non-primitives
1088 // Detect array declaration, e.g. int A[],
1089 // then generate "int A[]" in C++ as "vector<int> A"
1090 private String checkAndGetCplusArray(String paramType, String param) {
1092 String paramComplete = null;
1093 // Check for array declaration
1094 if (param.contains("[]")) {
1095 paramComplete = "vector<" + paramType + "> " + param.replace("[]","");
1097 // Just return it as is if it's not an array
1098 paramComplete = paramType + " " + param;
1100 return paramComplete;
1104 // Get simple types, e.g. HashSet for HashSet<...>
1105 // Basically strip off the "<...>"
1106 private String checkAndGetParamClass(String paramType, boolean needPtr) {
1108 // Check if this is generics
1109 if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
1110 // If true then return with pointer (C++)
1112 return exchangeParamType(paramType) + "*";
1113 else // Java, so no pointer needed
1114 return exchangeParamType(paramType);
1120 // Returns the other interface for type-checking purposes for USERDEFINED
1121 // classes based on the information provided in multiple policy files
1122 // e.g. return CameraWithXXX instead of Camera
1123 private String exchangeParamType(String intface) {
1125 // Param type that's passed is the interface name we need to look for
1126 // in the map of interfaces, based on available policy files.
1127 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
1128 if (decHandler != null) {
1129 // We've found the required interface policy files
1130 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(intface);
1131 Set<String> setExchInt = reqDecl.getInterfaces();
1132 if (setExchInt.size() == 1) {
1133 Iterator iter = setExchInt.iterator();
1134 return (String) iter.next();
1136 throw new Error("IoTCompiler: Ambiguous stub interfaces: " + setExchInt.toString() +
1137 ". Only one new interface can be declared if the object " + intface +
1138 " needs to be passed in as an input parameter!");
1141 // NULL value - this means policy files missing
1142 throw new Error("IoTCompiler: Parameter type lookup failed for " + intface +
1143 "... Please provide the necessary policy files for user-defined types." +
1144 " If this is an array please type the brackets after the variable name," +
1145 " e.g. \"String str[]\", not \"String[] str\"." +
1146 " If this is a Collections (Java) / STL (C++) type, this compiler only" +
1147 " supports List/ArrayList (Java) or list (C++).");
1152 public static void main(String[] args) throws Exception {
1154 // If there is no argument or just "--help" or "-h", then invoke printUsage()
1155 if ((args[0].equals("-help") ||
1156 args[0].equals("--help")||
1157 args[0].equals("-h")) ||
1158 (args.length == 0)) {
1160 IoTCompiler.printUsage();
1162 } else if (args.length > 1) {
1164 IoTCompiler comp = new IoTCompiler();
1167 // Parse main policy file
1168 ParseNode pnPol = IoTCompiler.parseFile(args[i]);
1169 // Parse "requires" policy file
1170 ParseNode pnReq = IoTCompiler.parseFile(args[i+1]);
1171 // Get interface name
1172 String intface = ParseTreeHandler.getOrigIntface(pnPol);
1173 comp.setDataStructures(intface, pnPol, pnReq);
1174 comp.getMethodsForIntface(intface);
1176 // 1) Check if this is the last option before "-java" or "-cplus"
1177 // 2) Check if this is really the last option (no "-java" or "-cplus")
1178 } while(!args[i].equals("-java") &&
1179 !args[i].equals("-cplus") &&
1182 // Generate everything if we don't see "-java" or "-cplus"
1183 if (i == args.length) {
1184 comp.generateJavaLocalInterfaces();
1185 comp.generateJavaInterfaces();
1186 comp.generateJavaStubClasses();
1187 comp.generateCplusLocalInterfaces();
1188 comp.generateCPlusInterfaces();
1189 comp.generateCPlusStubClasses();
1191 // Check other options
1192 while(i < args.length) {
1194 if (!args[i].equals("-java") &&
1195 !args[i].equals("-cplus")) {
1196 throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i]);
1198 if (i + 1 < args.length) {
1199 comp.setDirectory(args[i+1]);
1201 throw new Error("IoTCompiler: ERROR - please provide <directory> after option: " + args[i]);
1203 if (args[i].equals("-java")) {
1204 comp.generateJavaLocalInterfaces();
1205 comp.generateJavaInterfaces();
1206 comp.generateJavaStubClasses();
1208 comp.generateCplusLocalInterfaces();
1209 comp.generateCPlusInterfaces();
1210 comp.generateCPlusStubClasses();
1217 // Need to at least have exactly 2 parameters, i.e. main policy file and requires file
1218 IoTCompiler.printUsage();
1219 throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!");