| 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