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