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