JCompilationUnit.java |
1 // Copyright 2013 Bill Campbell, Swami Iyer and Bahar Akbal-Delibas 2 3 package jminusminus; 4 5 import java.util.ArrayList; 6 7 /** 8 * The abstract syntax tree (AST) node representing a compilation unit, and so 9 * the root of the AST. 10 * 11 * It keeps track of the name of the source file, its package name, a list of 12 * imported types, a list of type (eg class) declarations, and a flag indicating 13 * if a semantic error has been detected in analysis or code generation. It also 14 * maintains a CompilationUnitContext (built in pre-analysis) for declaring both 15 * imported and declared types. 16 * 17 * The AST is produced by the Parser. Once the AST has been built, three 18 * successive methods are invoked: 19 * 20 * (1) Method preAnalyze() is invoked for making a first pass at type analysis, 21 * recursively reaching down to the member headers for declaring types and 22 * member interfaces in the environment (contexts). preAnalyze() also creates a 23 * partial class file (in memory) for recording member header information, using 24 * the partialCodegen() method. 25 * 26 * (2) Method analyze() is invoked for type-checking field initializations and 27 * method bodies, and determining the types of all expressions. A certain amount 28 * of tree surgery is also done here. And stack frame offsets are computed for 29 * method parameters and local variables. 30 * 31 * (3) Method codegen() is invoked for generating code for the compilation unit 32 * to a class file. For each type declaration, it instantiates a CLEmmiter 33 * object (an abstraction of the class file) and then invokes methods on that 34 * CLEmitter for generating instructions. At the end of each type declaration, a 35 * method is invoked on the CLEmitter which writes the class out to the file 36 * system either as .class file or as a .s (SPIM) file. Of course, codegen() 37 * makes recursive calls down the tree, to the codegen() methods at each node, 38 * for generating the appropriate instructions. 39 */ 40 41 class JCompilationUnit extends JAST { 42 43 /** Name of the source file. */ 44 private String fileName; 45 46 /** Package name. */ 47 private TypeName packageName; 48 49 /** List of imports. */ 50 private ArrayList<TypeName> imports; 51 52 /** List of type declarations. */ 53 private ArrayList<JAST> typeDeclarations; 54 55 /** 56 * List of CLFile objects corresponding to the type declarations in this 57 * compilation unit. 58 */ 59 private ArrayList<CLFile> clFiles; 60 61 /** For imports and type declarations. */ 62 private CompilationUnitContext context; 63 64 /** Whether a semantic error has been found. */ 65 private boolean isInError; 66 67 /** 68 * Construct an AST node for a compilation unit given a file name, class 69 * directory, line number, package name, list of imports, and type 70 * declarations. 71 * 72 * @param fileName 73 * the name of the source file. 74 * @param line 75 * line in which the compilation unit occurs in the source file. 76 * @param packageName 77 * package name. 78 * @param imports 79 * a list of imports. 80 * @param typeDeclarations 81 * type declarations. 82 */ 83 84 public JCompilationUnit(String fileName, int line, TypeName packageName, 85 ArrayList<TypeName> imports, ArrayList<JAST> typeDeclarations) { 86 super(line); 87 this.fileName = fileName; 88 this.packageName = packageName; 89 this.imports = imports; 90 this.typeDeclarations = typeDeclarations; 91 clFiles = new ArrayList<CLFile>(); 92 compilationUnit = this; 93 } 94 95 /** 96 * The package in which this compilation unit is defined. 97 * 98 * @return the package name. 99 */ 100 101 public String packageName() { 102 return packageName == null ? "" : packageName.toString(); 103 } 104 105 /** 106 * Has a semantic error occurred up to now? 107 * 108 * @return true or false. 109 */ 110 111 public boolean errorHasOccurred() { 112 return isInError; 113 } 114 115 /** 116 * Report a semantic error. 117 * 118 * @param line 119 * line in which the error occurred in the source file. 120 * @param message 121 * message identifying the error. 122 * @param arguments 123 * related values. 124 */ 125 126 public void reportSemanticError(int line, String message, 127 Object... arguments) { 128 isInError = true; 129 System.err.printf("%s:%d: ", fileName, line); 130 System.err.printf(message, arguments); 131 System.err.println(); 132 } 133 134 /** 135 * Construct a context for the compilation unit, initializing it with 136 * imported types. Then pre-analyze the unit's type declarations, adding 137 * their types to the context. 138 */ 139 140 public void preAnalyze() { 141 context = new CompilationUnitContext(); 142 143 // Declare the two implicit types java.lang.Object and 144 // java.lang.String 145 context.addType(0, Type.OBJECT); 146 context.addType(0, Type.STRING); 147 148 // Declare any imported types 149 for (TypeName imported : imports) { 150 try { 151 Class<?> classRep = Class.forName(imported.toString()); 152 context.addType(imported.line(), Type.typeFor(classRep)); 153 } catch (Exception e) { 154 JAST.compilationUnit.reportSemanticError(imported.line(), 155 "Unable to find %s", imported.toString()); 156 } 157 } 158 159 // Declare the locally declared type(s) 160 CLEmitter.initializeByteClassLoader(); 161 for (JAST typeDeclaration : typeDeclarations) { 162 ((JTypeDecl) typeDeclaration).declareThisType(context); 163 } 164 165 // Pre-analyze the locally declared type(s). Generate 166 // (partial) Class instances, reflecting only the member 167 // interface type information 168 CLEmitter.initializeByteClassLoader(); 169 for (JAST typeDeclaration : typeDeclarations) { 170 ((JTypeDecl) typeDeclaration).preAnalyze(context); 171 } 172 } 173 174 /** 175 * Perform semantic analysis on the AST in the specified context. 176 * 177 * @param context 178 * context in which names are resolved (ignored here). 179 * @return the analyzed (and possibly rewritten) AST subtree. 180 */ 181 182 public JAST analyze(Context context) { 183 for (JAST typeDeclaration : typeDeclarations) { 184 typeDeclaration.analyze(this.context); 185 } 186 return this; 187 } 188 189 /** 190 * Generating code for a compilation unit means generating code for each of 191 * the type declarations. 192 * 193 * @param output 194 * the code emitter (basically an abstraction for producing the 195 * .class file). 196 */ 197 198 public void codegen(CLEmitter output) { 199 for (JAST typeDeclaration : typeDeclarations) { 200 typeDeclaration.codegen(output); 201 output.write(); 202 clFiles.add(output.clFile()); 203 } 204 } 205 206 /** 207 * Return the list of CLFile objects corresponding to the type declarations 208 * in this compilation unit. 209 * 210 * @return list of CLFile objects. 211 */ 212 213 public ArrayList<CLFile> clFiles() { 214 return clFiles; 215 } 216 217 /** 218 * @inheritDoc 219 */ 220 221 public void writeToStdOut(PrettyPrinter p) { 222 p.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); 223 p.printf("<JCompilationUnit line=\"%d\">\n", line()); 224 p.indentRight(); 225 p.printf("<Source fileName=\"%s\"/>\n", fileName); 226 if (context != null) { 227 context.writeToStdOut(p); 228 } 229 if (packageName != null) { 230 p.printf("<Package name=\"%s\"/>\n", packageName()); 231 } 232 if (imports != null) { 233 p.println("<Imports>"); 234 p.indentRight(); 235 for (TypeName imported : imports) { 236 p.printf("<Import name=\"%s\"/>\n", imported.toString()); 237 } 238 p.indentLeft(); 239 p.println("</Imports>"); 240 } 241 if (typeDeclarations != null) { 242 p.println("<TypeDeclarations>"); 243 p.indentRight(); 244 for (JAST typeDeclaration : typeDeclarations) { 245 typeDeclaration.writeToStdOut(p); 246 } 247 p.indentLeft(); 248 p.println("</TypeDeclarations>"); 249 } 250 p.indentLeft(); 251 p.println("</JCompilationUnit>"); 252 } 253 254 } 255