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