JCompilationUnit.java |
1 // Copyright 2012- 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 the root of the AST. 9 * <p> 10 * The AST is produced by the Parser. Once the AST has been built, three successive methods are 11 * invoked: 12 * <ol> 13 * <li>Method preAnalyze() is invoked for making a first pass at type analysis, recursively 14 * reaching down to the member headers for declaring types and member interfaces in the 15 * environment (contexts). preAnalyze() also creates a partial class file (in memory) for 16 * recording member header information.</li> 17 * 18 * <li>Method analyze() is invoked for type-checking field initializations and method bodies, 19 * and determining the types of all expressions. A certain amount of tree surgery is also done 20 * here. And stack frame offsets are computed for method parameters and local variables.</li> 21 * 22 * <li>Method codegen() is invoked for generating code for the compilation unit to a class file. 23 * For each type declaration, it instantiates a CLEmitter object (an abstraction of the class 24 * file) and then invokes methods on that CLEmitter for generating instructions. At the end of 25 * each type declaration, a method is invoked on the CLEmitter which writes the class out to 26 * the file system either as .class file or as a .s (SPIM) file. Of course, codegen() makes 27 * recursive calls down the tree, to the {@code codegen} methods at each node, for generating 28 * the appropriate instructions.</li> 29 * </ol> 30 */ 31 class JCompilationUnit extends JAST { 32 // Name of the source file. 33 private String fileName; 34 35 // Package name. 36 private TypeName packageName; 37 38 // List of imports. 39 private ArrayList<TypeName> imports; 40 41 // List of type declarations. 42 private ArrayList<JAST> typeDeclarations; 43 44 // List of CLFile objects corresponding to the type declarations in this compilation unit. 45 private ArrayList<CLFile> clFiles; 46 47 // For imports and type declarations. 48 private CompilationUnitContext context; 49 50 // Whether a semantic error has been found. 51 private boolean isInError; 52 53 /** 54 * Constructs an AST node for a compilation unit. 55 * 56 * @param fileName the name of the source file. 57 * @param line line in which the compilation unit occurs in the source file. 58 * @param packageName package name. 59 * @param imports a list of imports. 60 * @param typeDeclarations type declarations. 61 */ 62 public JCompilationUnit(String fileName, int line, TypeName packageName, 63 ArrayList<TypeName> imports, ArrayList<JAST> typeDeclarations) { 64 super(line); 65 this.fileName = fileName; 66 this.packageName = packageName; 67 this.imports = imports; 68 this.typeDeclarations = typeDeclarations; 69 clFiles = new ArrayList<CLFile>(); 70 compilationUnit = this; 71 } 72 73 /** 74 * Returns the package in which this compilation unit is defined. 75 * 76 * @return the package in which this compilation unit is defined. 77 */ 78 public String packageName() { 79 return packageName == null ? "" : packageName.toString().replace(".", "/"); 80 } 81 82 /** 83 * Returns the list of CLFile objects corresponding to the type declarations in this 84 * compilation unit. 85 * 86 * @return the list of CLFile objects corresponding to the type declarations in this 87 * compilation unit. 88 */ 89 public ArrayList<CLFile> clFiles() { 90 return clFiles; 91 } 92 93 /** 94 * Returns true if a semantic error has occurred up to now, and false otherwise. 95 * 96 * @return true if a semantic error has occurred up to now, and false otherwise.. 97 */ 98 public boolean errorHasOccurred() { 99 return isInError; 100 } 101 102 /** 103 * Reports a semantic error. 104 * 105 * @param line line in which the error occurred in the source file. 106 * @param message message identifying the error. 107 * @param arguments related values. 108 */ 109 public void reportSemanticError(int line, String message, Object... arguments) { 110 isInError = true; 111 System.err.printf("%s:%d: error: ", fileName, line); 112 System.err.printf(message, arguments); 113 System.err.println(); 114 } 115 116 /** 117 * Constructs a context for the compilation unit, initializing it with imported types. Then 118 * pre-analyzes the unit's type declarations, adding their types to the context. 119 */ 120 public void preAnalyze() { 121 context = new CompilationUnitContext(); 122 123 // Declare the two implicit types java.lang.Object and java.lang.String. 124 context.addType(0, Type.OBJECT); 125 context.addType(0, Type.STRING); 126 127 // Declare any imported types. 128 for (TypeName imported : imports) { 129 try { 130 Class<?> classRep = Class.forName(imported.toString()); 131 context.addType(imported.line(), Type.typeFor(classRep)); 132 } catch (Exception e) { 133 JAST.compilationUnit.reportSemanticError(imported.line(), "Unable to find %s", 134 imported.toString()); 135 } 136 } 137 138 // Declare the locally declared type(s). 139 CLEmitter.initializeByteClassLoader(); 140 for (JAST typeDeclaration : typeDeclarations) { 141 ((JTypeDecl) typeDeclaration).declareThisType(context); 142 } 143 144 // Pre-analyze the locally declared type(s). Generate (partial) Class instances, 145 // reflecting only the member declaration information. 146 CLEmitter.initializeByteClassLoader(); 147 for (JAST typeDeclaration : typeDeclarations) { 148 ((JTypeDecl) typeDeclaration).preAnalyze(context); 149 } 150 } 151 152 /** 153 * {@inheritDoc} 154 */ 155 public JAST analyze(Context context) { 156 for (JAST typeDeclaration : typeDeclarations) { 157 typeDeclaration.analyze(this.context); 158 } 159 return this; 160 } 161 162 /** 163 * {@inheritDoc} 164 */ 165 public void codegen(CLEmitter output) { 166 for (JAST typeDeclaration : typeDeclarations) { 167 typeDeclaration.codegen(output); 168 output.write(); 169 clFiles.add(output.clFile()); 170 } 171 } 172 173 /** 174 * {@inheritDoc} 175 */ 176 public void toJSON(JSONElement json) { 177 JSONElement e = new JSONElement(); 178 json.addChild("JCompilationUnit:" + line, e); 179 e.addAttribute("source", fileName); 180 if (packageName != null) { 181 e.addAttribute("package", packageName()); 182 } 183 if (imports != null) { 184 ArrayList<String> value = new ArrayList<String>(); 185 for (TypeName imported : imports) { 186 value.add(String.format("\"%s\"", imported.toString())); 187 } 188 e.addAttribute("imports", value); 189 } 190 if (context != null) { 191 context.toJSON(e); 192 } 193 if (typeDeclarations != null) { 194 for (JAST typeDeclaration : typeDeclarations) { 195 typeDeclaration.toJSON(e); 196 } 197 } 198 } 199 } 200