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