Separating policy file into main policy and generated interfaces; fixing lexer, parse...
[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.HashMap;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import iotpolicy.parser.Lexer;
13 import iotpolicy.parser.Parser;
14 import iotpolicy.tree.ParseNode;
15 import iotpolicy.tree.ParseNodeVector;
16 import iotpolicy.tree.ParseTreeHandler;
17 import iotpolicy.tree.CapabilityDecl;
18 import iotpolicy.tree.InterfaceDecl;
19 import iotpolicy.tree.RequiresDecl;
20
21 /** Class IoTCompiler is the main stub compiler for
22  *  stub files generation. This class calls helper classes
23  *  such as Parser, Lexer, InterfaceDecl, CapabilityDecl,
24  *  RequiresDecl, ParseTreeHandler, etc.
25  *
26  * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
27  * @version     1.0
28  * @since       2016-09-22
29  */
30 public class IoTCompiler {
31
32         /**
33          * Class properties
34          */
35         private String origInt;
36         private ParseTreeHandler ptHandler;
37         private InterfaceDecl intDecl;
38         private CapabilityDecl capDecl;
39         private RequiresDecl reqDecl;
40         private Map<String,Set<String>> mapCapabMethods;
41         private PrintWriter pw;
42         private String dir;
43
44         /**
45          * Class constants
46          */
47         private final static String OUTPUT_DIRECTORY = "stubfiles";
48
49         /**
50          * Class constructors
51          */
52         public IoTCompiler() {
53
54                 origInt = null;
55                 ptHandler = new ParseTreeHandler();
56                 intDecl = null;
57                 capDecl = null;
58                 capDecl = null;
59                 mapCapabMethods = new HashMap<String,Set<String>>();
60                 pw = null;
61                 dir = OUTPUT_DIRECTORY;
62         }
63
64
65         public IoTCompiler(String _origInt, ParseNode _pnPol, ParseNode _pnReq) {
66
67                 origInt = _origInt;
68                 ptHandler = new ParseTreeHandler(_origInt, _pnPol, _pnReq);
69                 intDecl = null;
70                 capDecl = null;
71                 reqDecl = null;
72                 mapCapabMethods = new HashMap<String,Set<String>>();
73                 pw = null;
74                 dir = OUTPUT_DIRECTORY;
75         }
76
77
78         /**
79          * parsePolicyFile() parses policy file
80          * <p>
81          * It also generates parse tree and
82          * copies useful information from parse tree into
83          * InterfaceDecl, CapabilityDecl, and RequiresDecl 
84          * data structures.
85          * Additionally, the data structure handles are
86          * returned from tree-parsing for further process.
87          *
88          */
89         public void parsePolicyFile() {
90
91                 ptHandler.processInterfaceDecl();
92                 intDecl = ptHandler.getInterfaceDecl();
93
94                 ptHandler.processCapabilityDecl();
95                 capDecl = ptHandler.getCapabilityDecl();
96
97                 ptHandler.processRequiresDecl();
98                 reqDecl = ptHandler.getRequiresDecl();
99         }
100
101
102         /**
103          * getMethodsForIntface() reads for methods in the data structure
104          * <p>
105          * It is going to give list of methods for a certain interface
106          *              based on the declaration of capabilities.
107          */
108         public void getMethodsForIntface() {
109
110                 // Get set of new interfaces, e.g. CameraWithCaptureAndData
111                 // Generate this new interface with all the methods it needs
112                 //              from different capabilities it declares
113                 Set<String> setIntfaces = reqDecl.getInterfaces();
114                 for (String strInt : setIntfaces) {
115
116                         // Initialize a set of methods
117                         Set<String> setMethods = new HashSet<String>();
118                         // Get list of capabilities, e.g. ImageCapture, VideoRecording, etc.
119                         List<String> listCapab = reqDecl.getCapabList(strInt);
120                         for (String strCap : listCapab) {
121
122                                 // Get list of methods for each capability
123                                 List<String> listCapabMeth = capDecl.getMethods(strCap);
124                                 for (String strMeth : listCapabMeth) {
125
126                                         // Add methods into setMethods
127                                         // This is to also handle redundancies (say two capabilities
128                                         //              share the same methods)
129                                         setMethods.add(strMeth);
130                                 }
131                         }
132                         // Add interface and methods information into map
133                         mapCapabMethods.put(strInt, setMethods);
134                 }
135         }
136
137
138         /**
139          * generateJavaInterfaces() generate stub interfaces based on the methods list in Java
140          */
141         public void generateJavaInterfaces() throws IOException {
142
143                 // Create a new directory
144                 createDirectory(dir);
145                 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
146
147                         // Open a new file to write into
148                         String newIntface = intMeth.getKey();
149                         FileWriter fw = new FileWriter(dir + "/" + newIntface + ".java");
150                         pw = new PrintWriter(new BufferedWriter(fw));
151                         // Write interface header
152                         println("");
153                         println("public interface " + newIntface + " {");
154                         List<String> meths = intDecl.getMethods();
155
156                         // Write methods
157                         for (String method : intMeth.getValue()) {
158
159                                 List<String> methParams = intDecl.getMethodParams(method);
160                                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
161                                 print("public " + intDecl.getMethodType(method) + " " +
162                                         intDecl.getMethodId(method) + "(");
163                                 for (int i = 0; i < methParams.size(); i++) {
164                                          print(methPrmTypes.get(i) + " " + methParams.get(i));
165                                         // Check if this is the last element (don't print a comma)
166                                         if (i != methParams.size() - 1) {
167                                                 print(", ");
168                                         }
169                                 }
170                                 println(");");
171                         }
172                         println("}");
173                         pw.close();
174                         System.out.println("IoTCompiler: Generated interface " + newIntface + ".java...");
175                 }
176         }
177
178
179         /**
180          * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
181          * <p>
182          * For C++ we use virtual classe as interface
183          */
184         public void generateCPlusInterfaces() throws IOException {
185
186                 // Create a new directory
187                 createDirectory(dir);
188                 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
189
190                         // Open a new file to write into
191                         String newIntface = intMeth.getKey();
192                         FileWriter fw = new FileWriter(dir + "/" + newIntface + ".hpp");
193                         pw = new PrintWriter(new BufferedWriter(fw));
194                         // Write file headers
195                         println("#include<iostream>");
196                         println("");
197                         println("using namespace std;");
198                         println("");
199                         println("class " + newIntface);
200                         println("{");
201                         println("public:");
202                         // Write methods
203                         for (String method : intMeth.getValue()) {
204
205                                 List<String> methParams = intDecl.getMethodParams(method);
206                                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
207                                 print("virtual " + convertType(intDecl.getMethodType(method)) + " " +
208                                         intDecl.getMethodId(method) + "(");
209                                 for (int i = 0; i < methParams.size(); i++) {
210                                          print(convertType(methPrmTypes.get(i)) + " " + methParams.get(i));
211                                         // Check if this is the last element (don't print a comma)
212                                         if (i != methParams.size() - 1) {
213                                                 print(", ");
214                                         }
215                                 }
216                                 println(") = 0;");
217                         }
218                         print("}");
219                         println(";");
220                         pw.close();
221                         System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
222                 }
223         }
224
225
226         /**
227          * generateJavaStubClasses() generate stubs based on the methods list in Java
228          */
229         public void generateJavaStubClasses() throws IOException {
230
231                 // Create a new directory
232                 createDirectory(dir);
233                 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
234
235                         // Open a new file to write into
236                         String newIntface = intMeth.getKey();
237                         String newStubClass = newIntface + "_Stub";
238                         FileWriter fw = new FileWriter(dir + "/" + newStubClass + ".java");
239                         pw = new PrintWriter(new BufferedWriter(fw));
240                         // Write interface header
241                         println("");
242                         println("public class " + newStubClass + " implements " + newIntface + " {");
243                         println("");
244                         // Write methods
245                         for (String method : intMeth.getValue()) {
246
247                                 List<String> methParams = intDecl.getMethodParams(method);
248                                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
249                                 print("public " + intDecl.getMethodType(method) + " " +
250                                         intDecl.getMethodId(method) + "(");
251                                 for (int i = 0; i < methParams.size(); i++) {
252                                          print(methPrmTypes.get(i) + " " + methParams.get(i));
253                                         // Check if this is the last element (don't print a comma)
254                                         if (i != methParams.size() - 1) {
255                                                 print(", ");
256                                         }
257                                 }
258                                 println(") {");
259                                 // Check if this is not "void"
260                                 if (!intDecl.getMethodType(method).equals("void")) {
261                                         String retStmt = generateReturnStmt(intDecl.getMethodType(method));
262                                         println("return " + retStmt + ";");
263                                 }
264                                 println("}");
265                                 println("");
266                         }
267                         println("}");
268                         pw.close();
269                         System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
270                 }
271         }
272
273
274         /**
275          * generateCPlusStubClasses() generate stubs based on the methods list in C++
276          */
277         public void generateCPlusStubClasses() throws IOException {
278
279                 // Create a new directory
280                 createDirectory(dir);
281                 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
282
283                         // Open a new file to write into
284                         String newIntface = intMeth.getKey();
285                         String newStubClass = newIntface + "_Stub";
286                         FileWriter fw = new FileWriter(dir + "/" + newStubClass + ".hpp");
287                         pw = new PrintWriter(new BufferedWriter(fw));
288                         // Write file headers
289                         println("#include<iostream>");
290                         println("#include \"" + newIntface + ".hpp\""); println("");            
291                         println("using namespace std;"); println("");
292                         println("class " + newStubClass + " : public " + newIntface);
293                         println("{");
294                         println("public:"); println("");
295                         // Add default constructor and destructor
296                         println(newStubClass + "() { }"); println("");
297                         println("~" + newStubClass + "() { }"); println("");            
298                         // Write methods
299                         for (String method : intMeth.getValue()) {
300
301                                 List<String> methParams = intDecl.getMethodParams(method);
302                                 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
303                                 print(convertType(intDecl.getMethodType(method)) + " " +
304                                         intDecl.getMethodId(method) + "(");
305                                 for (int i = 0; i < methParams.size(); i++) {
306                                          print(convertType(methPrmTypes.get(i)) + " " + methParams.get(i));
307                                         // Check if this is the last element (don't print a comma)
308                                         if (i != methParams.size() - 1) {
309                                                 print(", ");
310                                         }
311                                 }
312                                 println(") { ");
313                                 // Check if this is not "void"
314                                 if (!intDecl.getMethodType(method).equals("void")) {
315                                         String retStmt = generateReturnStmt(intDecl.getMethodType(method));
316                                         if (retStmt.equals("null")) { // null = NULL in C++
317                                                 retStmt = "NULL";
318                                         }
319                                         println("return " + retStmt + ";");
320                                 }
321                                 println("}"); println("");
322                         }
323                         print("}"); println(";");
324                         pw.close();
325                         System.out.println("IoTCompiler: Generated stub class " + newIntface + ".hpp...");
326                 }
327         }
328
329
330         /**
331          * generateReturnStmt() generate return statement based on methType
332          */
333         public String generateReturnStmt(String methType) {
334
335                 // Generate dummy returns for now
336                 if (methType.equals("short")||
337                         methType.equals("int")  ||
338                         methType.equals("long") ||
339                         methType.equals("float")||
340                         methType.equals("double")) {
341
342                         return "1";
343                 } else if ( methType.equals("String") ||
344                                         methType.equals("byte")) {
345   
346                         return "\"a\"";
347                 } else if ( methType.equals("char")) {
348
349                         return "\'a\'";
350                 } else if ( methType.equals("boolean")) {
351
352                         return "true";
353                 } else {
354                         return "null";
355                 }
356         }
357
358
359         /**
360          * setDirectory() set a new directory for stub files
361          */
362         public void setDirectory(String _dir) {
363
364                 dir = _dir;
365         }
366
367
368         /**
369          * printUsage() prints the usage of this compiler
370          */
371         public static void printUsage() {
372
373                 System.out.println();
374                 System.out.println("Sentinel interface and stub compiler version 1.0");
375                 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
376                 System.out.println("All rights reserved.");
377                 System.out.println("Usage:");
378                 System.out.println("\tjava IoTCompiler --help / -h\t\t\t\t\tDisplay this help texts");
379                 System.out.println("\tjava IoTCompiler <main-policy-file> <req-policy-file>\t\tGenerate both Java and C++ stub files");
380                 System.out.println("\tjava IoTCompiler <main-policy-file> <req-policy-file> [options]");
381                 System.out.println("Options:");
382                 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
383                 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
384                 System.out.println();
385         }
386
387
388         /**================================================
389          * Helper functions to write stub codes into files
390          **================================================
391          */
392         boolean newline=true;
393         int tablevel=0;
394
395         private void print(String str) {
396                 if (newline) {
397                         int tab=tablevel;
398                         if (str.equals("}"))
399                                 tab--;
400                         for(int i=0; i<tab; i++)
401                                 pw.print("\t");
402                 }
403                 pw.print(str);
404                 updatetabbing(str);
405                 newline=false;
406         }
407
408         /**
409          * This function converts Java to C++ type for compilation
410          */
411         private String convertType(String jType) {
412
413                 // Generate dummy returns for now
414                 if (jType.equals("short")||
415                         jType.equals("int")  ||
416                         jType.equals("long") ||
417                         jType.equals("char") ||
418                         jType.equals("float")||
419                         jType.equals("double")) {
420
421                         return jType;
422                 } else if ( jType.equals("String")) {
423   
424                         return "string";
425                 } else if ( jType.equals("byte")) {
426
427                         return "char";
428                 } else if ( jType.equals("boolean")) {
429
430                         return "bool";
431                 } else {
432                         return jType;
433                 }       
434         }
435
436
437         private void println(String str) {
438                 if (newline) {
439                         int tab = tablevel;
440                         if (str.equals("}"))
441                                 tab--;
442                         for(int i=0; i<tab; i++)
443                                 pw.print("\t");
444                 }
445                 pw.println(str);
446                 updatetabbing(str);
447                 newline = true;
448         }
449
450
451         private void updatetabbing(String str) {
452                 tablevel+=count(str,'{')-count(str,'}');
453         }
454
455
456         private int count(String str, char key) {
457                 char[] array = str.toCharArray();
458                 int count = 0;
459                 for(int i=0; i<array.length; i++) {
460                         if (array[i] == key)
461                                 count++;
462                 }
463                 return count;
464         }
465
466
467         private void createDirectory(String dirName) {
468
469                 File file = new File(dirName);
470                 if (!file.exists()) {
471                         if (file.mkdir()) {
472                                 System.out.println("IoTCompiler: Directory " + dirName + " has been created!");
473                         } else {
474                                 System.out.println("IoTCompiler: Failed to create directory " + dirName + "!");
475                         }
476                 } else {
477                         System.out.println("IoTCompiler: Directory " + dirName + " exists...");
478                 }
479         }
480
481
482         public static void main(String[] args) throws Exception {
483
484                 // Runtime options
485                 if (args.length != 0) {
486                         // Display help
487                         if ((args[0].equals("--help") ||
488                                 (args[0].equals("-h")))) {
489                                 IoTCompiler.printUsage();
490                         } else {
491                                 // Parse main policy file
492                                 ComplexSymbolFactory csfPol = new ComplexSymbolFactory();
493                                 ScannerBuffer lexerPol = 
494                                         new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(args[0])),csfPol));
495                                 Parser parsePol = new Parser(lexerPol,csfPol);
496                                 ParseNode pnPol = (ParseNode) parsePol.parse().value;
497                                 // Parse "requires" policy file
498                                 ComplexSymbolFactory csfReq = new ComplexSymbolFactory();
499                                 ScannerBuffer lexerReq = 
500                                         new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(args[1])),csfReq));
501                                 Parser parseReq = new Parser(lexerReq,csfReq);
502                                 ParseNode pnReq = (ParseNode) parseReq.parse().value;
503                                 // Get interface name
504                                 String intFace = ParseTreeHandler.getOrigIntface(pnPol);
505                                 //System.out.println("IoTCompiler: Original interface: " + intFace);
506                                 IoTCompiler comp = new IoTCompiler(intFace, pnPol, pnReq);
507                                 // Generate all policy files if just policy file is provided
508                                 comp.parsePolicyFile();
509                                 comp.getMethodsForIntface();
510                                 if (args.length == 2) {
511                                         comp.generateJavaInterfaces();
512                                         comp.generateJavaStubClasses();
513                                         comp.generateCPlusInterfaces();
514                                         comp.generateCPlusStubClasses();
515                                 } else {
516                                 // Check other options
517                                         int i = 2;
518                                         while(i < args.length) {
519                                                 // Check whether <directory> is provided
520                                                 if ((i + 1) < args.length) {
521                                                         comp.setDirectory(args[i+1]);
522                                                 } else
523                                                         throw new Error("IoTCompiler: ERROR - please provide <directory> after option: " + args[i]);
524                                                 if (args[i].equals("-java")) {
525                                                         comp.generateJavaInterfaces();
526                                                         comp.generateJavaStubClasses();
527                                                 } else if (args[i].equals("-cplus")) {
528                                                         comp.generateCPlusInterfaces();
529                                                         comp.generateCPlusStubClasses();
530                                                 } else
531                                                         throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i]);
532                                                 i = i + 2;
533                                         }
534                                 }
535                         }
536
537                 } else {
538                 // Need at least the policy file name
539                         IoTCompiler.printUsage();
540                         throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!");
541                 }
542         }
543 }
544
545
546
547