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