Adding #include<vector> declaration when array is translated as vector in C++
[iot2.git] / iotjava / iotpolicy / IoTCompiler.java
1 package iotpolicy;
2
3 import java_cup.runtime.ComplexSymbolFactory;
4 import java_cup.runtime.ScannerBuffer;
5 import java.io.*;
6 import java.util.Collection;
7 import java.util.Collections;
8 import java.util.HashMap;
9 import java.util.HashSet;
10 import java.util.Iterator;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Set;
14
15 import iotpolicy.parser.Lexer;
16 import iotpolicy.parser.Parser;
17 import iotpolicy.tree.ParseNode;
18 import iotpolicy.tree.ParseNodeVector;
19 import iotpolicy.tree.ParseTreeHandler;
20 import iotpolicy.tree.Declaration;
21 import iotpolicy.tree.DeclarationHandler;
22 import iotpolicy.tree.CapabilityDecl;
23 import iotpolicy.tree.InterfaceDecl;
24 import iotpolicy.tree.RequiresDecl;
25
26 import iotrmi.Java.IoTRMITypes;
27
28
29 /** Class IoTCompiler is the main interface/stub compiler for
30  *  files generation. This class calls helper classes
31  *  such as Parser, Lexer, InterfaceDecl, CapabilityDecl,
32  *  RequiresDecl, ParseTreeHandler, etc.
33  *
34  * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
35  * @version     1.0
36  * @since       2016-09-22
37  */
38 public class IoTCompiler {
39
40         /**
41          * Class properties
42          */
43         // Maps multiple interfaces to multiple objects of ParseTreeHandler
44         private Map<String,ParseTreeHandler> mapIntfacePTH;
45         private Map<String,DeclarationHandler> mapIntDeclHand;
46         private Map<String,Map<String,Set<String>>> mapInt2NewInts;
47         // Data structure to store our types (primitives and non-primitives) for compilation
48         private Map<String,String> mapPrimitives;
49         private Map<String,String> mapNonPrimitivesJava;
50         private Map<String,String> mapNonPrimitivesCplus;
51         private PrintWriter pw;
52         private String dir;
53         private String subdir;
54
55         /**
56          * Class constants
57          */
58         private final static String OUTPUT_DIRECTORY = "output_files";
59
60         private enum ParamCategory {
61
62                 PRIMITIVES,             // All the primitive types, e.g. byte, short, int, long, etc.
63                 NONPRIMITIVES,  // Non-primitive types, e.g. Set, Map, List, etc.
64                 USERDEFINED             // Non-supported type by default; assumed as driver classes
65         }
66
67         /**
68          * Class constructors
69          */
70         public IoTCompiler() {
71
72                 mapIntfacePTH = new HashMap<String,ParseTreeHandler>();
73                 mapIntDeclHand = new HashMap<String,DeclarationHandler>();
74                 mapInt2NewInts = new HashMap<String,Map<String,Set<String>>>();
75                 mapPrimitives = new HashMap<String,String>();
76                         arraysToMap(mapPrimitives, IoTRMITypes.primitivesJava, IoTRMITypes.primitivesCplus);
77                 mapNonPrimitivesJava = new HashMap<String,String>();
78                         arraysToMap(mapNonPrimitivesJava, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitiveJavaLibs);
79                 mapNonPrimitivesCplus = new HashMap<String,String>();
80                         arraysToMap(mapNonPrimitivesCplus, IoTRMITypes.nonPrimitivesJava, IoTRMITypes.nonPrimitivesCplus);
81                 pw = null;
82                 dir = OUTPUT_DIRECTORY;
83                 subdir = null;
84         }
85
86
87         /**
88          * setParseTree() sets parse tree based on policy files.
89          * <p>
90          * It also generates parse tree (ParseTreeHandler) and
91          * copies useful information from parse tree into
92          * InterfaceDecl, CapabilityDecl, and RequiresDecl 
93          * data structures.
94          * Additionally, the data structure handles are
95          * returned from tree-parsing for further process.
96          *
97          */
98         public void setParseTree(String origInt, ParseNode pnPol, ParseNode pnReq) {
99
100                 ParseTreeHandler ptHandler = new ParseTreeHandler(origInt, pnPol, pnReq);
101                 DeclarationHandler decHandler = new DeclarationHandler();
102
103                 // Process ParseNode and generate Declaration objects
104                 ptHandler.processInterfaceDecl();
105                 InterfaceDecl intDecl = ptHandler.getInterfaceDecl();
106                 decHandler.addInterfaceDecl(origInt, intDecl);
107                 ptHandler.processCapabilityDecl();
108                 CapabilityDecl capDecl = ptHandler.getCapabilityDecl();
109                 decHandler.addCapabilityDecl(origInt, capDecl);
110                 ptHandler.processRequiresDecl();
111                 RequiresDecl reqDecl = ptHandler.getRequiresDecl();
112                 decHandler.addRequiresDecl(origInt, reqDecl);
113
114                 mapIntfacePTH.put(origInt, ptHandler);
115                 mapIntDeclHand.put(origInt, decHandler);
116         }
117
118
119         /**
120          * getMethodsForIntface() reads for methods in the data structure
121          * <p>
122          * It is going to give list of methods for a certain interface
123          *              based on the declaration of capabilities.
124          */
125         public void getMethodsForIntface(String origInt) {
126
127                 ParseTreeHandler ptHandler = mapIntfacePTH.get(origInt);
128                 Map<String,Set<String>> mapNewIntMethods = new HashMap<String,Set<String>>();
129                 // Get set of new interfaces, e.g. CameraWithCaptureAndData
130                 // Generate this new interface with all the methods it needs
131                 //              from different capabilities it declares
132                 DeclarationHandler decHandler = mapIntDeclHand.get(origInt);
133                 RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(origInt);
134                 Set<String> setIntfaces = reqDecl.getInterfaces();
135                 for (String strInt : setIntfaces) {
136
137                         // Initialize a set of methods
138                         Set<String> setMethods = new HashSet<String>();
139                         // Get list of capabilities, e.g. ImageCapture, VideoRecording, etc.
140                         List<String> listCapab = reqDecl.getCapabList(strInt);
141                         for (String strCap : listCapab) {
142
143                                 // Get list of methods for each capability
144                                 CapabilityDecl capDecl = (CapabilityDecl) decHandler.getCapabilityDecl(origInt);
145                                 List<String> listCapabMeth = capDecl.getMethods(strCap);
146                                 for (String strMeth : listCapabMeth) {
147
148                                         // Add methods into setMethods
149                                         // This is to also handle redundancies (say two capabilities
150                                         //              share the same methods)
151                                         setMethods.add(strMeth);
152                                 }
153                         }
154                         // Add interface and methods information into map
155                         mapNewIntMethods.put(strInt, setMethods);
156                 }
157                 // Map the map of interface-methods to the original interface
158                 mapInt2NewInts.put(origInt, mapNewIntMethods);
159         }
160
161
162         /**
163          * generateJavaLocalInterface() writes the local interface and provides type-checking.
164          * <p>
165          * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
166          * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
167          * The local interface has to be the input parameter for the stub and the stub 
168          * interface has to be the input parameter for the local class.
169          */
170         public void generateJavaLocalInterfaces() throws IOException {
171
172                 // Create a new directory
173                 createDirectory(dir);
174                 for (String intface : mapIntfacePTH.keySet()) {
175                         // Open a new file to write into
176                         FileWriter fw = new FileWriter(dir + "/" + intface + ".java");
177                         pw = new PrintWriter(new BufferedWriter(fw));
178                         // Pass in set of methods and get import classes
179                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
180                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
181                         List<String> methods = intDecl.getMethods();
182                         Set<String> importClasses = getImportClasses(methods, intDecl);
183                         printImportStatements(importClasses);
184                         // Write interface header
185                         println("");
186                         println("public interface " + intface + " {");
187                         // Write methods
188                         for (String method : methods) {
189
190                                 List<String> methParams = intDecl.getMethodParams(method);
191                                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
192                                 print("public " + intDecl.getMethodType(method) + " " +
193                                         intDecl.getMethodId(method) + "(");
194                                 for (int i = 0; i < methParams.size(); i++) {
195                                         // Check for params with driver class types and exchange it 
196                                         //              with its remote interface
197                                         String paramType = checkAndGetParamClass(methPrmTypes.get(i));
198                                         String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
199                                         //print(paramType + " " + methParams.get(i));
200                                         print(paramComplete);
201                                         // Check if this is the last element (don't print a comma)
202                                         if (i != methParams.size() - 1) {
203                                                 print(", ");
204                                         }
205                                 }
206                                 println(");");
207                         }
208                         println("}");
209                         pw.close();
210                         System.out.println("IoTCompiler: Generated local interface " + intface + ".java...");
211                 }
212         }
213
214
215         /**
216          * generateCplusLocalInterfaces() writes the local interfaces and provides type-checking.
217          * <p>
218          * It needs to rewrite and exchange USERDEFINED types in input parameters of stub
219          * and original interfaces, e.g. exchange Camera and CameraWithVideoAndRecording.
220          * The local interface has to be the input parameter for the stub and the stub 
221          * interface has to be the input parameter for the local class.
222          */
223         public void generateCplusLocalInterfaces() throws IOException {
224
225                 // Create a new directory
226                 createDirectory(dir);
227                 for (String intface : mapIntfacePTH.keySet()) {
228                         // Open a new file to write into
229                         FileWriter fw = new FileWriter(dir + "/" + intface + ".hpp");
230                         pw = new PrintWriter(new BufferedWriter(fw));
231                         // Write file headers
232                         println("#include <iostream>");
233                         // Pass in set of methods and get include classes
234                         DeclarationHandler decHandler = mapIntDeclHand.get(intface);
235                         InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
236                         List<String> methods = intDecl.getMethods();
237                         Set<String> includeClasses = getIncludeClasses(methods, intDecl);
238                         printIncludeStatements(includeClasses);
239                         println("");
240                         println("using namespace std;");
241                         println("");
242                         println("class " + intface);
243                         println("{");
244                         println("public:");
245                         // Write methods
246                         for (String method : methods) {
247
248                                 List<String> methParams = intDecl.getMethodParams(method);
249                                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
250                                 print("virtual " + convertType(intDecl.getMethodType(method)) + " " +
251                                         intDecl.getMethodId(method) + "(");
252                                 for (int i = 0; i < methParams.size(); i++) {
253                                         // Check for params with driver class types and exchange it 
254                                         //              with its remote interface
255                                         String paramType = checkAndGetParamClass(methPrmTypes.get(i));
256                                         paramType = checkAndGetCplusType(paramType);
257                                         // Check for arrays - translate into vector in C++
258                                         String paramComplete = checkAndGetCplusArray(paramType, methParams.get(i));
259                                         //print(paramType + " " + param);
260                                         print(paramComplete);
261                                         // Check if this is the last element (don't print a comma)
262                                         if (i != methParams.size() - 1) {
263                                                 print(", ");
264                                         }
265                                 }
266                                 println(") = 0;");
267                         }
268                         print("}");
269                         println(";");
270                         pw.close();
271                         System.out.println("IoTCompiler: Generated local interface " + intface + ".hpp...");
272                 }
273         }
274
275
276         /**
277          * generateJavaInterfaces() generate stub interfaces based on the methods list in Java
278          */
279         public void generateJavaInterfaces() throws IOException {
280
281                 // Create a new directory
282                 String path = createDirectories(dir, subdir);
283                 for (String intface : mapIntfacePTH.keySet()) {
284
285                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
286                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
287
288                                 // Open a new file to write into
289                                 String newIntface = intMeth.getKey();
290                                 FileWriter fw = new FileWriter(path + "/" + newIntface + ".java");
291                                 pw = new PrintWriter(new BufferedWriter(fw));
292                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
293                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
294                                 // Pass in set of methods and get import classes
295                                 Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
296                                 printImportStatements(importClasses);
297                                 // Write interface header
298                                 println("");
299                                 println("public interface " + newIntface + " {");
300                                 List<String> meths = intDecl.getMethods();
301                                 // Write methods
302                                 for (String method : intMeth.getValue()) {
303
304                                         List<String> methParams = intDecl.getMethodParams(method);
305                                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
306                                         print("public " + intDecl.getMethodType(method) + " " +
307                                                 intDecl.getMethodId(method) + "(");
308                                         for (int i = 0; i < methParams.size(); i++) {
309                                                 print(methPrmTypes.get(i) + " " + methParams.get(i));
310                                                 // Check if this is the last element (don't print a comma)
311                                                 if (i != methParams.size() - 1) {
312                                                         print(", ");
313                                                 }
314                                         }
315                                         println(");");
316                                 }
317                                 println("}");
318                                 pw.close();
319                                 System.out.println("IoTCompiler: Generated interface " + newIntface + ".java...");
320                         }
321                 }
322         }
323
324
325         /**
326          * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
327          * <p>
328          * For C++ we use virtual classe as interface
329          */
330         public void generateCPlusInterfaces() throws IOException {
331
332                 // Create a new directory
333                 String path = createDirectories(dir, subdir);
334                 for (String intface : mapIntfacePTH.keySet()) {
335
336                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
337                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
338
339                                 // Open a new file to write into
340                                 String newIntface = intMeth.getKey();
341                                 FileWriter fw = new FileWriter(path + "/" + newIntface + ".hpp");
342                                 pw = new PrintWriter(new BufferedWriter(fw));
343                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
344                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
345                                 // Write file headers
346                                 println("#include <iostream>");
347                                 // Pass in set of methods and get import classes
348                                 Set<String> includeClasses = getIncludeClasses(intMeth.getValue(), intDecl);
349                                 printIncludeStatements(includeClasses);
350                                 println("");
351                                 println("using namespace std;");
352                                 println("");
353                                 println("class " + newIntface);
354                                 println("{");
355                                 println("public:");
356                                 // Write methods
357                                 for (String method : intMeth.getValue()) {
358
359                                         List<String> methParams = intDecl.getMethodParams(method);
360                                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
361                                         print("virtual " + convertType(intDecl.getMethodType(method)) + " " +
362                                                 intDecl.getMethodId(method) + "(");
363                                         for (int i = 0; i < methParams.size(); i++) {
364
365                                                 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
366                                                 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
367                                                 //print(methPrmType + " " + methParam);
368                                                 print(methParamComplete);
369                                                 // Check if this is the last element (don't print a comma)
370                                                 if (i != methParams.size() - 1) {
371                                                         print(", ");
372                                                 }
373                                         }
374                                         println(") = 0;");
375                                 }
376                                 print("}");
377                                 println(";");
378                                 pw.close();
379                                 System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
380                         }
381                 }
382         }
383
384
385         /**
386          * generateJavaStubClasses() generate stubs based on the methods list in Java
387          */
388         public void generateJavaStubClasses() throws IOException {
389
390                 // Create a new directory
391                 String path = createDirectories(dir, subdir);
392                 for (String intface : mapIntfacePTH.keySet()) {
393
394                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
395                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
396
397                                 // Open a new file to write into
398                                 String newIntface = intMeth.getKey();
399                                 String newStubClass = newIntface + "_Stub";
400                                 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".java");
401                                 pw = new PrintWriter(new BufferedWriter(fw));
402                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
403                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
404                                 // Pass in set of methods and get import classes
405                                 Set<String> importClasses = getImportClasses(intMeth.getValue(), intDecl);
406                                 printImportStatements(importClasses);
407                                 // Write interface header
408                                 println("");
409                                 println("public class " + newStubClass + " implements " + newIntface + " {");
410                                 println("");
411                                 // Write methods
412                                 for (String method : intMeth.getValue()) {
413
414                                         List<String> methParams = intDecl.getMethodParams(method);
415                                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
416                                         print("public " + intDecl.getMethodType(method) + " " +
417                                                 intDecl.getMethodId(method) + "(");
418                                         for (int i = 0; i < methParams.size(); i++) {
419
420                                                 print(methPrmTypes.get(i) + " " + methParams.get(i));
421                                                 // Check if this is the last element (don't print a comma)
422                                                 if (i != methParams.size() - 1) {
423                                                         print(", ");
424                                                 }
425                                         }
426                                         println(") {");
427                                         // Check if this is not "void"
428                                         if (!intDecl.getMethodType(method).equals("void")) {
429                                                 String retStmt = generateReturnStmt(intDecl.getMethodType(method));
430                                                 println("return " + retStmt + ";");
431                                         }
432                                         println("}"); println("");
433                                 }
434                                 println("}");
435                                 pw.close();
436                                 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
437                         }
438                 }
439         }
440
441
442         /**
443          * generateCPlusStubClasses() generate stubs based on the methods list in C++
444          */
445         public void generateCPlusStubClasses() throws IOException {
446
447                 // Create a new directory
448                 String path = createDirectories(dir, subdir);
449                 for (String intface : mapIntfacePTH.keySet()) {
450
451                         Map<String,Set<String>> mapNewIntMethods = mapInt2NewInts.get(intface);
452                         for (Map.Entry<String,Set<String>> intMeth : mapNewIntMethods.entrySet()) {
453                                 // Open a new file to write into
454                                 String newIntface = intMeth.getKey();
455                                 String newStubClass = newIntface + "_Stub";
456                                 FileWriter fw = new FileWriter(path + "/" + newStubClass + ".hpp");
457                                 pw = new PrintWriter(new BufferedWriter(fw));
458                                 // Write file headers
459                                 println("#include <iostream>");
460                                 println("#include \"" + newIntface + ".hpp\""); println("");            
461                                 println("using namespace std;"); println("");
462                                 println("class " + newStubClass + " : public " + newIntface); println("{");
463                                 println("public:"); println("");
464                                 // Add default constructor and destructor
465                                 println(newStubClass + "() { }"); println("");
466                                 println("~" + newStubClass + "() { }"); println("");
467                                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
468                                 InterfaceDecl intDecl = (InterfaceDecl) decHandler.getInterfaceDecl(intface);
469                                 // Write methods
470                                 for (String method : intMeth.getValue()) {
471
472                                         List<String> methParams = intDecl.getMethodParams(method);
473                                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
474
475                                         //System.out.println("\n\nMethod param: " + intDecl.getMethodParams(method));
476                                         //System.out.println("\n\nMethod param type: " + intDecl.getMethodParamTypes(method));
477                                         //System.out.println("\n\n");
478
479                                         print(convertType(intDecl.getMethodType(method)) + " " +
480                                                 intDecl.getMethodId(method) + "(");
481                                         for (int i = 0; i < methParams.size(); i++) {
482                                                 String methPrmType = checkAndGetCplusType(methPrmTypes.get(i));
483                                                 String methParamComplete = checkAndGetCplusArray(methPrmType, methParams.get(i));
484                                                 //print(methPrmType + " " + methParam);
485                                                 print(methParamComplete);
486                                                 // Check if this is the last element (don't print a comma)
487                                                 if (i != methParams.size() - 1) {
488                                                         print(", ");
489                                                 }
490                                         }
491                                         println(") { ");
492                                         // Check if this is not "void"
493                                         if (!intDecl.getMethodType(method).equals("void")) {
494                                                 String retStmt = generateReturnStmt(intDecl.getMethodType(method));
495                                                 if (retStmt.equals("null")) { // null = NULL in C++
496                                                         retStmt = "NULL";
497                                                 }
498                                                 println("return " + retStmt + ";");
499                                         }
500                                         println("}"); println("");
501                                 }
502                                 print("}"); println(";");
503                                 pw.close();
504                                 System.out.println("IoTCompiler: Generated stub class " + newIntface + ".hpp...");
505                         }
506                 }
507         }
508
509
510         /**
511          * generateReturnStmt() generate return statement based on methType
512          */
513         public String generateReturnStmt(String methType) {
514
515                 // Generate dummy returns for now
516                 if (methType.equals("short")||
517                         methType.equals("int")  ||
518                         methType.equals("long") ||
519                         methType.equals("float")||
520                         methType.equals("double")) {
521
522                         return "1";
523                 } else if ( methType.equals("String") ||
524                                         methType.equals("byte")) {
525   
526                         return "\"a\"";
527                 } else if ( methType.equals("char")) {
528
529                         return "\'a\'";
530                 } else if ( methType.equals("boolean")) {
531
532                         return "true";
533                 } else {
534                         return "null";
535                 }
536         }
537
538
539         /**
540          * setDirectory() sets a new directory for stub files
541          */
542         public void setDirectory(String _subdir) {
543
544                 subdir = _subdir;
545         }
546
547
548         /**
549          * printUsage() prints the usage of this compiler
550          */
551         public static void printUsage() {
552
553                 System.out.println();
554                 System.out.println("Sentinel interface and stub compiler version 1.0");
555                 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
556                 System.out.println("All rights reserved.");
557                 System.out.println("Usage:");
558                 System.out.println("\tjava IoTCompiler -help / --help / -h\n");
559                 System.out.println("\t\tDisplay this help texts\n\n");
560                 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>]");
561                 System.out.println("\tjava IoTCompiler [<main-policy-file> <req-policy-file>] [options]\n");
562                 System.out.println("\t\tTake one or more pairs of main-req policy files, and generate Java and/or C++ files\n");
563                 System.out.println("Options:");
564                 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
565                 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
566                 System.out.println();
567         }
568
569
570         /**
571          * parseFile() prepares Lexer and Parser objects, then parses the file
572          */
573         public static ParseNode parseFile(String file) {
574
575                 ParseNode pn = null;
576                 try {
577                         ComplexSymbolFactory csf = new ComplexSymbolFactory();
578                         ScannerBuffer lexer = 
579                                 new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(file)),csf));
580                         Parser parse = new Parser(lexer,csf);
581                         pn = (ParseNode) parse.parse().value;
582                 } catch (Exception e) {
583                         e.printStackTrace();
584                         throw new Error("IoTCompiler: ERROR parsing policy file or wrong command line option: " + file);
585                 }
586
587                 return pn;
588         }
589
590
591         /**================
592          * Helper functions
593          **================
594          */
595         boolean newline=true;
596         int tablevel=0;
597
598         private void print(String str) {
599                 if (newline) {
600                         int tab=tablevel;
601                         if (str.equals("}"))
602                                 tab--;
603                         for(int i=0; i<tab; i++)
604                                 pw.print("\t");
605                 }
606                 pw.print(str);
607                 updatetabbing(str);
608                 newline=false;
609         }
610
611         /**
612          * This function converts Java to C++ type for compilation
613          */
614         private String convertType(String jType) {
615
616                 return mapPrimitives.get(jType);
617         }
618
619
620         private void println(String str) {
621                 if (newline) {
622                         int tab = tablevel;
623                         if (str.equals("}"))
624                                 tab--;
625                         for(int i=0; i<tab; i++)
626                                 pw.print("\t");
627                 }
628                 pw.println(str);
629                 updatetabbing(str);
630                 newline = true;
631         }
632
633
634         private void updatetabbing(String str) {
635                 tablevel+=count(str,'{')-count(str,'}');
636         }
637
638
639         private int count(String str, char key) {
640                 char[] array = str.toCharArray();
641                 int count = 0;
642                 for(int i=0; i<array.length; i++) {
643                         if (array[i] == key)
644                                 count++;
645                 }
646                 return count;
647         }
648
649
650         private void createDirectory(String dirName) {
651
652                 File file = new File(dirName);
653                 if (!file.exists()) {
654                         if (file.mkdir()) {
655                                 System.out.println("IoTCompiler: Directory " + dirName + " has been created!");
656                         } else {
657                                 System.out.println("IoTCompiler: Failed to create directory " + dirName + "!");
658                         }
659                 } else {
660                         System.out.println("IoTCompiler: Directory " + dirName + " exists...");
661                 }
662         }
663
664
665         // Create a directory and possibly a sub directory
666         private String createDirectories(String dir, String subdir) {
667
668                 String path = dir;
669                 createDirectory(path);
670                 if (subdir != null) {
671                         path = path + "/" + subdir;
672                         createDirectory(path);
673                 }
674                 return path;
675         }
676
677
678         // Inserting array members into a Map object
679         // that maps arrKey to arrVal objects
680         private void arraysToMap(Map map, Object[] arrKey, Object[] arrVal) {
681
682                 for(int i = 0; i < arrKey.length; i++) {
683
684                         map.put(arrKey[i], arrVal[i]);
685                 }
686         }
687
688
689         // Return parameter category, i.e. PRIMITIVES, NONPRIMITIVES, or USERDEFINED
690         private ParamCategory getParamCategory(String paramType) {
691
692                 if (mapPrimitives.containsKey(paramType)) {
693                         return ParamCategory.PRIMITIVES;
694                 // We can either use mapNonPrimitivesJava or mapNonPrimitivesCplus here
695                 } else if (mapNonPrimitivesJava.containsKey(getSimpleType(paramType))) {
696                         return ParamCategory.NONPRIMITIVES;
697                 } else
698                         return ParamCategory.USERDEFINED;
699         }
700
701
702         // Return full class name for non-primitives to generate Java import statements
703         // e.g. java.util.Set for Set, java.util.Map for Map
704         private String getNonPrimitiveJavaClass(String paramNonPrimitives) {
705
706                 return mapNonPrimitivesJava.get(paramNonPrimitives);
707         }
708
709
710         // Return full class name for non-primitives to generate Cplus include statements
711         // e.g. #include <set> for Set, #include <map> for Map
712         private String getNonPrimitiveCplusClass(String paramNonPrimitives) {
713
714                 return mapNonPrimitivesCplus.get(paramNonPrimitives);
715         }
716
717
718         // Get simple types, e.g. HashSet for HashSet<...>
719         // Basically strip off the "<...>"
720         private String getSimpleType(String paramType) {
721
722                 // Check if this is generics
723                 if(paramType.contains("<")) {
724                         String[] type = paramType.split("<");
725                         return type[0];
726                 } else
727                         return paramType;
728         }
729
730
731         // Generate a set of classes for import statements
732         private Set<String> getImportClasses(Collection<String> methods, InterfaceDecl intDecl) {
733
734                 Set<String> importClasses = new HashSet<String>();
735                 for (String method : methods) {
736                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
737                         for (String paramType : methPrmTypes) {
738
739                                 String simpleType = getSimpleType(paramType);
740                                 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
741                                         importClasses.add(getNonPrimitiveJavaClass(simpleType));
742                                 }
743                         }
744                 }
745                 return importClasses;
746         }
747
748
749         // Generate a set of classes for include statements
750         private Set<String> getIncludeClasses(Collection<String> methods, InterfaceDecl intDecl) {
751
752                 Set<String> includeClasses = new HashSet<String>();
753                 for (String method : methods) {
754
755                         List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
756                         List<String> methParams = intDecl.getMethodParams(method);
757                         for (int i = 0; i < methPrmTypes.size(); i++) {
758
759                                 String simpleType = getSimpleType(methPrmTypes.get(i));
760                                 String param = methParams.get(i);
761                                 if (getParamCategory(simpleType) == ParamCategory.NONPRIMITIVES) {
762                                         includeClasses.add(getNonPrimitiveCplusClass(simpleType));
763                                 } else if (param.contains("[]")) {
764                                 // Check if this is array for C++; translate into vector
765                                         includeClasses.add("vector");
766                                 }
767                         }
768                 }
769                 return includeClasses;
770         }
771
772
773         private void printImportStatements(Set<String> importClasses) {
774
775                 for(String cls : importClasses) {
776                         println("import " + cls + ";");
777                 }
778         }
779
780
781         private void printIncludeStatements(Set<String> includeClasses) {
782
783                 for(String cls : includeClasses) {
784                         println("#include <" + cls + ">");
785                 }
786         }
787
788
789         // Get the C++ version of a non-primitive type
790         // e.g. set for Set and map for Map
791         // Input nonPrimitiveType has to be generics in format
792         private String[] getTypeOfGeneric(String nonPrimitiveType) {
793
794                 // Handle <, >, and , for 2-type generic/template
795                 String[] substr = nonPrimitiveType.split("<")[1].split(">")[0].split(",");
796                 return substr;
797         }
798
799
800         private String checkAndGetCplusType(String paramType) {
801
802                 if (getParamCategory(paramType) == ParamCategory.PRIMITIVES) {
803                         return convertType(paramType);
804                 } else if (getParamCategory(paramType) == ParamCategory.NONPRIMITIVES) {
805
806                         // Check for generic/template format
807                         if (paramType.contains("<") && paramType.contains(">")) {
808
809                                 String genericClass = getSimpleType(paramType);
810                                 String[] genericType = getTypeOfGeneric(paramType);
811                                 String cplusTemplate = null;
812                                 if (genericType.length == 1) // Generic/template with one type
813                                         cplusTemplate = getNonPrimitiveCplusClass(genericClass) + 
814                                                 "<" + convertType(genericType[0]) + ">";
815                                 else // Generic/template with two types
816                                         cplusTemplate = getNonPrimitiveCplusClass(genericClass) + 
817                                                 "<" + convertType(genericType[0]) + "," + convertType(genericType[1]) + ">";
818                                 return cplusTemplate;
819                         } else
820                                 return getNonPrimitiveCplusClass(paramType);
821                 } else
822                         // Just return it as is if it's not non-primitives
823                         return paramType;
824         }
825
826
827         // Detect array declaration, e.g. int A[],
828         //              then generate "int A[]" in C++ as "vector<int> A"
829         private String checkAndGetCplusArray(String paramType, String param) {
830
831                 String paramComplete = null;
832                 // Check for array declaration
833                 if (param.contains("[]")) {
834                         paramComplete = "vector<" + paramType + "> " + param.replace("[]","");
835                 } else
836                         // Just return it as is if it's not an array
837                         paramComplete = paramType + " " + param;
838
839                 return paramComplete;
840         }
841
842
843         // Get simple types, e.g. HashSet for HashSet<...>
844         // Basically strip off the "<...>"
845         private String checkAndGetParamClass(String paramType) {
846
847                 // Check if this is generics
848                 if(getParamCategory(paramType) == ParamCategory.USERDEFINED) {
849                         return exchangeParamType(paramType);
850                 } else
851                         return paramType;
852         }
853
854
855         // Returns the other interface for type-checking purposes for USERDEFINED
856         //              classes based on the information provided in multiple policy files
857         // e.g. return CameraWithXXX instead of Camera
858         private String exchangeParamType(String intface) {
859
860                 // Param type that's passed is the interface name we need to look for
861                 //              in the map of interfaces, based on available policy files.
862                 DeclarationHandler decHandler = mapIntDeclHand.get(intface);
863                 if (decHandler != null) {
864                 // We've found the required interface policy files
865                         RequiresDecl reqDecl = (RequiresDecl) decHandler.getRequiresDecl(intface);
866                         Set<String> setExchInt = reqDecl.getInterfaces();
867                         if (setExchInt.size() == 1) {
868                                 Iterator iter = setExchInt.iterator();
869                                 return (String) iter.next();
870                         } else {
871                                 throw new Error("IoTCompiler: Ambiguous stub interfaces: " + setExchInt.toString() + 
872                                         ". Only one new interface can be declared if the object " + intface +
873                                         " needs to be passed in as an input parameter!");
874                         }
875                 } else {
876                 // NULL value - this means policy files missing
877                         throw new Error("IoTCompiler: Parameter type lookup failed for " + intface +
878                                 "... Please provide the necessary policy files for user-defined types." +
879                                 " If this is an array please type the brackets after the variable name," +
880                                 " e.g. \"String str[]\", not \"String[] str\"." +
881                                 " If this is a Collections (Java) / STL (C++) type, this compiler only" +
882                                 " supports List/ArrayList (Java) or list (C++).");
883                 }
884         }
885
886
887         public static void main(String[] args) throws Exception {
888
889                 // If there is no argument or just "--help" or "-h", then invoke printUsage()
890                 if ((args[0].equals("-help") ||
891                          args[0].equals("--help")||
892                          args[0].equals("-h"))   ||
893                         (args.length == 0)) {
894
895                         IoTCompiler.printUsage();
896
897                 } else if (args.length > 1) {
898
899                         IoTCompiler comp = new IoTCompiler();
900                         int i = 0;                              
901                         do {
902                                 // Parse main policy file
903                                 ParseNode pnPol = IoTCompiler.parseFile(args[i]);
904                                 // Parse "requires" policy file
905                                 ParseNode pnReq = IoTCompiler.parseFile(args[i+1]);
906                                 // Get interface name
907                                 String intface = ParseTreeHandler.getOrigIntface(pnPol);
908                                 comp.setParseTree(intface, pnPol, pnReq);
909                                 comp.getMethodsForIntface(intface);
910                                 i = i + 2;
911                         // 1) Check if this is the last option before "-java" or "-cplus"
912                         // 2) Check if this is really the last option (no "-java" or "-cplus")
913                         } while(!args[i].equals("-java") &&
914                                         !args[i].equals("-cplus") &&
915                                         (i < args.length));
916
917                         // Generate everything if we don't see "-java" or "-cplus"
918                         if (i == args.length) {
919                                 comp.generateJavaLocalInterfaces();
920                                 comp.generateJavaInterfaces();
921                                 comp.generateJavaStubClasses();
922                                 comp.generateCplusLocalInterfaces();
923                                 comp.generateCPlusInterfaces();
924                                 comp.generateCPlusStubClasses();
925                         } else {
926                         // Check other options
927                                 while(i < args.length) {
928                                         // Error checking
929                                         if (!args[i].equals("-java") &&
930                                                 !args[i].equals("-cplus")) {
931                                                 throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i]);
932                                         } else {
933                                                 if (i + 1 < args.length) {
934                                                         comp.setDirectory(args[i+1]);
935                                                 } else
936                                                         throw new Error("IoTCompiler: ERROR - please provide <directory> after option: " + args[i]);
937
938                                                 if (args[i].equals("-java")) {
939                                                         comp.generateJavaLocalInterfaces();
940                                                         comp.generateJavaInterfaces();
941                                                         comp.generateJavaStubClasses();
942                                                 } else {
943                                                         comp.generateCplusLocalInterfaces();
944                                                         comp.generateCPlusInterfaces();
945                                                         comp.generateCPlusStubClasses();
946                                                 }
947                                         }
948                                         i = i + 2;
949                                 }
950                         }
951                 } else {
952                 // Need to at least have exactly 2 parameters, i.e. main policy file and requires file
953                         IoTCompiler.printUsage();
954                         throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!");
955                 }
956         }
957 }
958
959
960
961