6a6f073806d6f19c28a24c447f72fb4e0603f41f
[charm.git] / src / langs / charj / src / charj / translator / Translator.java
1
2 package charj.translator;
3
4 import java.io.*;
5 import java.nio.*;
6 import java.nio.channels.*;
7 import java.nio.charset.*;
8 import java.util.*;
9 import org.antlr.runtime.*;
10 import org.antlr.runtime.tree.*;
11 import org.antlr.stringtemplate.*;
12
13
14 /**
15  * Driver class for lexing, parsing, and output.
16  * Takes in file names, parses them and generates code
17  * for .ci and .cc files in a .charj directory. Invokes
18  * charmc on these outputs and moves any resulting .o file 
19  * to the appropriate directory.
20  */
21 public class Translator {
22
23     public static final String templateFile = "charj/translator/Charj.stg";
24
25     // variables controlled by command-line arguments
26     private String m_charmc;
27     private boolean m_debug;
28     private boolean m_verbose;
29     private boolean m_errorCondition;
30     private boolean m_printAST;
31     private boolean m_translate_only;
32
33     // library locations to search for classes
34     private String m_stdlib;
35     private List<String> m_usrlibs;
36
37     private String m_basename;
38     private SymbolTable m_symtab;
39     private CommonTree m_ast;
40     private CommonTreeNodeStream m_nodes;
41     private CommonTokenStream m_tokens;
42
43     public Translator(
44             String _charmc,
45             boolean _debug,
46             boolean _verbose,
47             boolean _printAST,
48             boolean _translate_only,
49             String _stdlib,
50             List<String> _usrlibs)
51     {
52         m_charmc = _charmc;
53         m_debug = _debug;
54         m_verbose = _verbose;
55         m_printAST = _printAST;
56         m_translate_only = _translate_only;
57         m_stdlib = _stdlib;
58         m_usrlibs = _usrlibs;
59         m_symtab = new SymbolTable(this);
60         m_errorCondition = false;
61     }
62
63     public boolean debug()      { return m_debug; }
64     public boolean verbose()    { return m_verbose; }
65     public String basename()    { return m_basename; }
66
67     public static TreeAdaptor m_adaptor = new CommonTreeAdaptor() {
68         public Object create(Token token) {
69             return new CharjAST(token);
70         }
71         
72         public Object dupNode(Object t) {
73             if (t == null) {
74                 return null;
75             }
76             return create(((CharjAST)t).token);
77         }
78     };
79
80     public String translate(String filename) throws Exception {
81         m_basename = filename.substring(0, filename.lastIndexOf("."));
82         m_basename = m_basename.substring(m_basename.lastIndexOf("/") + 1);
83
84         ANTLRFileStream input = new ANTLRFileStream(filename);
85             
86         CharjLexer lexer = new CharjLexer(input);
87         m_tokens = new CommonTokenStream(lexer);
88
89         // Use lexer tokens to feed tree parser
90         CharjParser parser = new CharjParser(m_tokens);
91         parser.setTreeAdaptor(m_adaptor);
92         CharjParser.charjSource_return r = parser.charjSource();
93
94         // Create node stream for AST traversals
95         m_ast = (CommonTree)r.getTree();
96         m_nodes = new CommonTreeNodeStream(m_ast);
97         m_nodes.setTokenStream(m_tokens);
98         m_nodes.setTreeAdaptor(m_adaptor);
99
100         // do AST rewriting and semantic checking
101         if (m_printAST) printAST("Before PreSemantics Pass", "before_presem.html");
102         preSemanticPass();
103         if (m_printAST) printAST("After PreSemantics Pass", "after_presem.html");
104
105         resolveTypes();
106         if (m_printAST) printAST("After Type Resolution", "after_types.html");
107
108         initPupCollect();
109         if (m_printAST) printAST("After Collector Pass", "after_collector.html");
110
111         postSemanticPass();
112         if (m_printAST) printAST("After PostSemantics Pass", "after_postsem.html");
113
114         m_nodes = new CommonTreeNodeStream(m_ast);
115         m_nodes.setTokenStream(m_tokens);
116         m_nodes.setTreeAdaptor(m_adaptor);
117
118         // emit code for .ci, .h, and .cc based on rewritten AST
119         String ciOutput = translationPass(OutputMode.ci);
120         writeTempFile(filename, ciOutput, OutputMode.ci);
121
122         String hOutput = translationPass(OutputMode.h);
123         writeTempFile(filename, hOutput, OutputMode.h);
124         
125         String ccOutput = translationPass(OutputMode.cc);
126         writeTempFile(filename, ccOutput, OutputMode.cc);
127
128         if (!m_translate_only) compileTempFiles(filename, m_charmc);
129
130         // Build a string representing all emitted code. This will be printed
131         // by the main driver if requested via command-line argument. 
132         String ciHeader = "-----CI----------------------------\n";
133         String hHeader  = "-----H-----------------------------\n";
134         String ccHeader = "-----CC----------------------------\n";
135         String footer   = "-----------------------------------\n";
136         return ciHeader + ciOutput + hHeader + hOutput + 
137             ccHeader + ccOutput + footer;
138     }
139
140     private void preSemanticPass() throws
141         RecognitionException, IOException, InterruptedException
142     {
143         m_nodes.reset();
144         CharjASTModifier mod = new CharjASTModifier(m_nodes);
145         mod.setTreeAdaptor(m_adaptor);
146         m_ast = (CommonTree)mod.charjSource().getTree();
147         m_nodes = new CommonTreeNodeStream(m_ast);
148         m_nodes.setTokenStream(m_tokens);
149         m_nodes.setTreeAdaptor(m_adaptor);
150     }
151
152     private void postSemanticPass() throws
153         RecognitionException, IOException, InterruptedException
154     {
155         m_nodes.reset();
156         CharjASTModifier2 mod = new CharjASTModifier2(m_nodes);
157         mod.setTreeAdaptor(m_adaptor);
158         //m_ast = (CommonTree)mod.charjSource(m_symtab).getTree();
159         mod.charjSource(m_symtab);
160         m_nodes = new CommonTreeNodeStream(m_ast);
161         m_nodes.setTokenStream(m_tokens);
162         m_nodes.setTreeAdaptor(m_adaptor);
163     }
164
165     private ClassSymbol semanticPass() throws
166         RecognitionException, IOException, InterruptedException
167     {
168         m_nodes.reset();
169         CharjSemantics sem = new CharjSemantics(m_nodes);
170         return sem.charjSource(m_symtab);
171     }
172
173     private void resolveTypes() throws
174         RecognitionException, IOException, InterruptedException
175     {
176         m_nodes.reset();
177         if (m_verbose) System.out.println("\nDefiner Phase\n----------------");
178         SymbolDefiner definer = new SymbolDefiner(m_nodes, m_symtab);
179         definer.downup(m_ast);
180         m_nodes.reset();
181         definer.downup(m_ast);
182         if (m_verbose) System.out.println("\nResolver Phase\n----------------");
183         if (m_printAST) printAST("After Type Definition", "after_definition.html");
184         m_nodes.reset();
185         SymbolResolver resolver = new SymbolResolver(m_nodes, m_symtab);
186         resolver.downup(m_ast);
187     }
188
189     private void initPupCollect() throws
190         RecognitionException, IOException, InterruptedException
191     {
192         m_nodes.reset();
193         if (m_verbose) System.out.println("\nInitPupCollector Phase\n----------------");
194         InitPUPCollector collector = new InitPUPCollector(m_nodes);
195         collector.downup(m_ast);
196     }
197
198     private String translationPass(OutputMode m) throws
199         RecognitionException, IOException, InterruptedException
200     {
201         m_nodes.reset();
202         CharjEmitter emitter = new CharjEmitter(m_nodes);
203         StringTemplateGroup templates = getTemplates(templateFile);
204         emitter.setTemplateLib(templates);
205         StringTemplate st = 
206             (StringTemplate)emitter.charjSource(m_symtab, m).getTemplate();
207         return st.toString();
208     }
209
210     public static StringTemplateGroup getTemplates(String templateFile) {
211         StringTemplateGroup templates = null;
212         try {
213             ClassLoader loader = Thread.currentThread().getContextClassLoader();
214             InputStream istream = loader.getResourceAsStream(templateFile);
215             BufferedReader reader = 
216                 new BufferedReader(new InputStreamReader(istream));
217             templates = new StringTemplateGroup(reader);
218             reader.close();
219         } catch(IOException ex) {
220             System.err.println(ex.getMessage());
221             ex.printStackTrace(System.err);
222         }
223         return templates;
224     }
225
226     public File findPackage(String packageName) {
227         String packageDir = packageName.replace(".", "/");
228         File p = new File(packageDir);
229         if ( debug() ) System.out.println(
230                 " [charj] findPackage " + packageName + 
231                 " trying " + p.getAbsoluteFile());
232        
233         // check current directory
234         if ( p.exists() ) {
235             return p;
236         }
237
238         // look in user libs if any
239         if ( m_usrlibs != null ) {
240             for (String lib : m_usrlibs) {
241                 p = new File(lib, packageDir);
242                 if (debug() ) System.out.println(
243                         " \tnot found, now trying " + p.getAbsoluteFile());
244                 if ( p.exists() ) {
245                     return p;
246                 }
247             }
248         }
249
250         // look in standard lib
251         p = new File(m_stdlib, packageDir);
252         if ( debug() ) System.out.println(
253                 " \tnot found, now trying " + p.getAbsoluteFile());
254         if ( p.exists() ) {
255             return p;
256         }
257
258         return null;
259     }
260
261     /** Load a class from disk looking in lib/package
262      *  Side-effect: add class to symtab. This is used by ClassSymbol to
263      *  load unknown types from disk. packageName comes from the output
264      *  of PackageScope.getFullyQualifiedName
265      */
266     public ClassSymbol loadType(String packageName, String typeName) {
267         if (debug()) System.out.println(
268                 " [charj] loadType(" + typeName + ") from " + packageName);
269         
270         ClassSymbol cs = null;
271         try {
272             String packageDir = ".";
273             if ( packageName!=null ) {
274                 packageDir = packageName.replace(".", "/");
275             }
276             String fullName = packageDir + "/" + typeName + ".cj";
277                 
278             ClassLoader cl = Thread.currentThread().getContextClassLoader();
279             boolean fileExists = (cl.getResource(fullName) != null);
280             if (!fileExists) {
281                 if (debug()) System.out.println(
282                         " \tloadType(" + typeName + "): not found");
283                 return null;
284             }
285
286             if (debug()) System.out.println(
287                     " \tloadType(" + typeName + "): parsing " + 
288                     packageName + "." + typeName);
289             
290             ANTLRInputStream fs = new ANTLRInputStream(
291                     cl.getResourceAsStream(fullName));
292             fs.name = packageDir + "/" + typeName + ".cj";
293             CharjLexer lexer = new CharjLexer(fs);
294             
295             cs = semanticPass();
296         } catch (Exception e) {
297             e.printStackTrace();
298         }
299         return cs;
300     }
301
302     /**
303      * Read the given file name in as a string.
304      */
305     public static String readFile(String path) throws IOException {
306       FileInputStream stream = new FileInputStream(new File(path));
307       try {
308         FileChannel fc = stream.getChannel();
309         MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
310         return Charset.defaultCharset().decode(bb).toString();
311       }
312       finally {
313         stream.close();
314       }
315     }
316
317     /**
318      * Utility function to write a generated .ci, .cc, or .h
319      * file to disk. Takes a .cj filename and writes a .cc,
320      * .ci, or .h file to the .charj directory depending on
321      * the OutputMode.
322      */
323     private void writeTempFile(
324             String filename, 
325             String output,
326             OutputMode m) throws
327         IOException
328     {
329         int lastDot = filename.lastIndexOf(".");
330         filename = filename.substring(0, lastDot) + m.extension();
331         writeTempFile(filename, output);
332         return;
333     }
334
335     private void writeTempFile(
336             String filename,
337             String output) throws
338         IOException
339     {
340         if (m_verbose) System.out.println(" [charjc] create: " + filename);
341         FileWriter fw = new FileWriter(filename);
342         fw.write(output);
343         fw.close();
344         return;
345     }
346
347     /**
348      * Compiles the .cc and .ci files generated from the given filename.
349      * The given charmc string includes all options to be passed to charmc.
350      * Any generated .o file is moved back to the initial directory.
351      */
352     private void compileTempFiles(
353             String filename,
354             String charmc) throws
355         IOException, InterruptedException
356     {
357         int lastDot = filename.lastIndexOf(".");
358         int lastSlash = filename.lastIndexOf("/");
359         String baseDirectory = filename.substring(0, lastSlash + 1);
360         if (baseDirectory.equals("")) {
361             baseDirectory = "./";
362         }
363         String moduleName = filename.substring(lastSlash + 1, lastDot);
364         String baseTempFilename = moduleName;
365
366         // Compile interface file
367         String cmd = charmc + " " + baseTempFilename + ".ci";
368         File currentDir = new File(".");
369         int retVal = exec(cmd, currentDir);
370         if (retVal != 0) {
371             error("Could not compile generated interface file.");
372             return;
373         }
374
375         // Move decl.h and def.h into temp directory.
376         // charmxi/charmc doesn't offer control over where to generate these
377         cmd = "touch " + baseTempFilename + ".decl.h " +
378             baseTempFilename + ".def.h";
379         retVal = exec(cmd, currentDir);
380         if (retVal != 0) {
381             error("Could not touch .decl.h and .def.h files.");
382             return;
383         }
384
385         // Compile c++ output
386         cmd = charmc + " -I" + m_stdlib + "/charj/libs -c " +
387             baseTempFilename + ".cc" + " -o " + baseTempFilename + ".o";
388         retVal = exec(cmd, currentDir);
389         if (retVal != 0) {
390             error("Could not compile generated C++ file");
391             return;
392         }
393     }
394
395     /**
396      * Utility function to execute a given command line.
397      */
398     private int exec(String cmd, File outputDir) throws
399         IOException, InterruptedException
400     {
401         if (m_verbose) System.out.println(" [charjc] exec: " + cmd);
402         Process p = Runtime.getRuntime().exec(cmd, null, outputDir);
403         StreamEmitter stdout = new StreamEmitter(
404                 p.getInputStream(), System.out);
405         StreamEmitter stderr = new StreamEmitter(
406                 p.getErrorStream(), System.err);
407         stdout.start();
408         stderr.start();
409         p.waitFor();
410         stdout.join();
411         stderr.join();
412         int retVal = p.exitValue();
413         return retVal;
414     }
415
416     /**
417      * Print a representation of the Charj AST. If message is not null,
418      * it is printed, along with an ASCII representation of the tree,
419      * to stdout. If filename is not null, an html temp file containin
420      * the representation is printed to filename.
421      */
422     public void printAST(String message, String filename) throws IOException
423     {
424         if (filename != null) {
425             ASTHTMLPrinter htmlPrinter = new ASTHTMLPrinter();
426             TreeTraverser.visit((CharjAST)m_ast, htmlPrinter);
427             writeTempFile(filename, htmlPrinter.output());
428         }
429
430         if (message != null) {
431             String header = "----------\n" + "AST: " + message + "\n----------\n";
432             String footer = "\n----------\n";
433             String body = null;
434             if (m_ast != null) {
435                 body = m_ast.toStringTree();
436             } else {
437                 body = "Null tree, no AST available";
438             }
439             System.out.println(header + body + footer);
440         }
441     }
442     
443     public void error(
444             BaseRecognizer recog, 
445             String msg, 
446             CharjAST node) 
447     {
448         String sourceName = "";
449         if (recog == null) {
450             sourceName = "<anonymous>";
451         } else {
452             sourceName = recog.getSourceName();
453         }
454         error(sourceName, msg, node);
455     } 
456
457     private void error(
458             String sourceName, 
459             String msg, 
460             CharjAST node) 
461     {
462         m_errorCondition = true;
463         String linecol = ":";
464         if ( node!=null ) {
465             CommonToken t = (CommonToken)node.getToken();
466             linecol = ": line " + t.getLine() + ":" + 
467                 t.getCharPositionInLine();
468         }
469         System.err.println(sourceName + linecol + " " + msg);
470         System.err.flush();
471     }
472
473     private void error(
474             String sourceName, 
475             String msg) {
476         error(sourceName, msg, (CharjAST)null);
477     }
478
479
480     public void error(String msg) {
481         error(" [charjc] error", msg, (CharjAST)null);
482     }
483
484
485     public void error(
486             String msg, 
487             Exception e) {
488         error(msg);
489         e.printStackTrace(System.err);
490     }
491 }