153dfa24770786258b9e0cab3f050530cdd50525
[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         if (m_verbose) System.out.println("\nResolver Phase\n----------------");
181         if (m_printAST) printAST("After Type Definition", "after_definition.html");
182         m_nodes.reset();
183         SymbolResolver resolver = new SymbolResolver(m_nodes, m_symtab);
184         resolver.downup(m_ast);
185     }
186
187     private void initPupCollect() throws
188         RecognitionException, IOException, InterruptedException
189     {
190         m_nodes.reset();
191         if (m_verbose) System.out.println("\nInitPupCollector Phase\n----------------");
192         InitPUPCollector collector = new InitPUPCollector(m_nodes);
193         collector.downup(m_ast);
194     }
195
196     private String translationPass(OutputMode m) throws
197         RecognitionException, IOException, InterruptedException
198     {
199         m_nodes.reset();
200         CharjEmitter emitter = new CharjEmitter(m_nodes);
201         StringTemplateGroup templates = getTemplates(templateFile);
202         emitter.setTemplateLib(templates);
203         StringTemplate st = 
204             (StringTemplate)emitter.charjSource(m_symtab, m).getTemplate();
205         return st.toString();
206     }
207
208     public static StringTemplateGroup getTemplates(String templateFile) {
209         StringTemplateGroup templates = null;
210         try {
211             ClassLoader loader = Thread.currentThread().getContextClassLoader();
212             InputStream istream = loader.getResourceAsStream(templateFile);
213             BufferedReader reader = 
214                 new BufferedReader(new InputStreamReader(istream));
215             templates = new StringTemplateGroup(reader);
216             reader.close();
217         } catch(IOException ex) {
218             System.err.println(ex.getMessage());
219             ex.printStackTrace(System.err);
220         }
221         return templates;
222     }
223
224     public File findPackage(String packageName) {
225         String packageDir = packageName.replace(".", "/");
226         File p = new File(packageDir);
227         if ( debug() ) System.out.println(
228                 " [charj] findPackage " + packageName + 
229                 " trying " + p.getAbsoluteFile());
230        
231         // check current directory
232         if ( p.exists() ) {
233             return p;
234         }
235
236         // look in user libs if any
237         if ( m_usrlibs != null ) {
238             for (String lib : m_usrlibs) {
239                 p = new File(lib, packageDir);
240                 if (debug() ) System.out.println(
241                         " \tnot found, now trying " + p.getAbsoluteFile());
242                 if ( p.exists() ) {
243                     return p;
244                 }
245             }
246         }
247
248         // look in standard lib
249         p = new File(m_stdlib, packageDir);
250         if ( debug() ) System.out.println(
251                 " \tnot found, now trying " + p.getAbsoluteFile());
252         if ( p.exists() ) {
253             return p;
254         }
255
256         return null;
257     }
258
259     /** Load a class from disk looking in lib/package
260      *  Side-effect: add class to symtab. This is used by ClassSymbol to
261      *  load unknown types from disk. packageName comes from the output
262      *  of PackageScope.getFullyQualifiedName
263      */
264     public ClassSymbol loadType(String packageName, String typeName) {
265         if (debug()) System.out.println(
266                 " [charj] loadType(" + typeName + ") from " + packageName);
267         
268         ClassSymbol cs = null;
269         try {
270             String packageDir = ".";
271             if ( packageName!=null ) {
272                 packageDir = packageName.replace(".", "/");
273             }
274             String fullName = packageDir + "/" + typeName + ".cj";
275                 
276             ClassLoader cl = Thread.currentThread().getContextClassLoader();
277             boolean fileExists = (cl.getResource(fullName) != null);
278             if (!fileExists) {
279                 if (debug()) System.out.println(
280                         " \tloadType(" + typeName + "): not found");
281                 return null;
282             }
283
284             if (debug()) System.out.println(
285                     " \tloadType(" + typeName + "): parsing " + 
286                     packageName + "." + typeName);
287             
288             ANTLRInputStream fs = new ANTLRInputStream(
289                     cl.getResourceAsStream(fullName));
290             fs.name = packageDir + "/" + typeName + ".cj";
291             CharjLexer lexer = new CharjLexer(fs);
292             
293             cs = semanticPass();
294         } catch (Exception e) {
295             e.printStackTrace();
296         }
297         return cs;
298     }
299
300     /**
301      * Read the given file name in as a string.
302      */
303     public static String readFile(String path) throws IOException {
304       FileInputStream stream = new FileInputStream(new File(path));
305       try {
306         FileChannel fc = stream.getChannel();
307         MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
308         return Charset.defaultCharset().decode(bb).toString();
309       }
310       finally {
311         stream.close();
312       }
313     }
314
315     /**
316      * Utility function to write a generated .ci, .cc, or .h
317      * file to disk. Takes a .cj filename and writes a .cc,
318      * .ci, or .h file to the .charj directory depending on
319      * the OutputMode.
320      */
321     private void writeTempFile(
322             String filename, 
323             String output,
324             OutputMode m) throws
325         IOException
326     {
327         int lastDot = filename.lastIndexOf(".");
328         filename = filename.substring(0, lastDot) + m.extension();
329         writeTempFile(filename, output);
330         return;
331     }
332
333     private void writeTempFile(
334             String filename,
335             String output) throws
336         IOException
337     {
338         if (m_verbose) System.out.println(" [charjc] create: " + filename);
339         FileWriter fw = new FileWriter(filename);
340         fw.write(output);
341         fw.close();
342         return;
343     }
344
345     /**
346      * Compiles the .cc and .ci files generated from the given filename.
347      * The given charmc string includes all options to be passed to charmc.
348      * Any generated .o file is moved back to the initial directory.
349      */
350     private void compileTempFiles(
351             String filename,
352             String charmc) throws
353         IOException, InterruptedException
354     {
355         int lastDot = filename.lastIndexOf(".");
356         int lastSlash = filename.lastIndexOf("/");
357         String baseDirectory = filename.substring(0, lastSlash + 1);
358         if (baseDirectory.equals("")) {
359             baseDirectory = "./";
360         }
361         String moduleName = filename.substring(lastSlash + 1, lastDot);
362         String baseTempFilename = moduleName;
363
364         // Compile interface file
365         String cmd = charmc + " " + baseTempFilename + ".ci";
366         File currentDir = new File(".");
367         int retVal = exec(cmd, currentDir);
368         if (retVal != 0) {
369             error("Could not compile generated interface file.");
370             return;
371         }
372
373         // Move decl.h and def.h into temp directory.
374         // charmxi/charmc doesn't offer control over where to generate these
375         cmd = "touch " + baseTempFilename + ".decl.h " +
376             baseTempFilename + ".def.h";
377         retVal = exec(cmd, currentDir);
378         if (retVal != 0) {
379             error("Could not touch .decl.h and .def.h files.");
380             return;
381         }
382
383         // Compile c++ output
384         cmd = charmc + " -I" + m_stdlib + "/charj/libs -c " +
385             baseTempFilename + ".cc" + " -o " + baseTempFilename + ".o";
386         retVal = exec(cmd, currentDir);
387         if (retVal != 0) {
388             error("Could not compile generated C++ file");
389             return;
390         }
391     }
392
393     /**
394      * Utility function to execute a given command line.
395      */
396     private int exec(String cmd, File outputDir) throws
397         IOException, InterruptedException
398     {
399         if (m_verbose) System.out.println(" [charjc] exec: " + cmd);
400         Process p = Runtime.getRuntime().exec(cmd, null, outputDir);
401         StreamEmitter stdout = new StreamEmitter(
402                 p.getInputStream(), System.out);
403         StreamEmitter stderr = new StreamEmitter(
404                 p.getErrorStream(), System.err);
405         stdout.start();
406         stderr.start();
407         p.waitFor();
408         stdout.join();
409         stderr.join();
410         int retVal = p.exitValue();
411         return retVal;
412     }
413
414     /**
415      * Print a representation of the Charj AST. If message is not null,
416      * it is printed, along with an ASCII representation of the tree,
417      * to stdout. If filename is not null, an html temp file containin
418      * the representation is printed to filename.
419      */
420     public void printAST(String message, String filename) throws IOException
421     {
422         if (filename != null) {
423             ASTHTMLPrinter htmlPrinter = new ASTHTMLPrinter();
424             TreeTraverser.visit((CharjAST)m_ast, htmlPrinter);
425             writeTempFile(filename, htmlPrinter.output());
426         }
427
428         if (message != null) {
429             String header = "----------\n" + "AST: " + message + "\n----------\n";
430             String footer = "\n----------\n";
431             String body = null;
432             if (m_ast != null) {
433                 body = m_ast.toStringTree();
434             } else {
435                 body = "Null tree, no AST available";
436             }
437             System.out.println(header + body + footer);
438         }
439     }
440     
441     public void error(
442             BaseRecognizer recog, 
443             String msg, 
444             CharjAST node) 
445     {
446         String sourceName = "";
447         if (recog == null) {
448             sourceName = "<anonymous>";
449         } else {
450             sourceName = recog.getSourceName();
451         }
452         error(sourceName, msg, node);
453     } 
454
455     private void error(
456             String sourceName, 
457             String msg, 
458             CharjAST node) 
459     {
460         m_errorCondition = true;
461         String linecol = ":";
462         if ( node!=null ) {
463             CommonToken t = (CommonToken)node.getToken();
464             linecol = ": line " + t.getLine() + ":" + 
465                 t.getCharPositionInLine();
466         }
467         System.err.println(sourceName + linecol + " " + msg);
468         System.err.flush();
469     }
470
471     private void error(
472             String sourceName, 
473             String msg) {
474         error(sourceName, msg, (CharjAST)null);
475     }
476
477
478     public void error(String msg) {
479         error(" [charjc] error", msg, (CharjAST)null);
480     }
481
482
483     public void error(
484             String msg, 
485             Exception e) {
486         error(msg);
487         e.printStackTrace(System.err);
488     }
489 }