1
3 package jminusminus;
4
5 import java.util.ArrayList;
6 import static jminusminus.CLConstants.*;
7
8
14
15 class JClassDeclaration extends JAST implements JTypeDecl {
16
17
18 private ArrayList<String> mods;
19
20
21 private String name;
22
23
24 private ArrayList<JMember> classBlock;
25
26
27 private Type superType;
28
29
30 private Type thisType;
31
32
33 private ClassContext context;
34
35
36 private boolean hasExplicitConstructor;
37
38
39 private ArrayList<JFieldDeclaration> instanceFieldInitializations;
40
41
42 private ArrayList<JFieldDeclaration> staticFieldInitializations;
43
44
60
61 public JClassDeclaration(int line, ArrayList<String> mods, String name,
62 Type superType, ArrayList<JMember> classBlock) {
63 super(line);
64 this.mods = mods;
65 this.name = name;
66 this.superType = superType;
67 this.classBlock = classBlock;
68 hasExplicitConstructor = false;
69 instanceFieldInitializations = new ArrayList<JFieldDeclaration>();
70 staticFieldInitializations = new ArrayList<JFieldDeclaration>();
71 }
72
73
78
79 public String name() {
80 return name;
81 }
82
83
88
89 public Type superType() {
90 return superType;
91 }
92
93
98
99 public Type thisType() {
100 return thisType;
101 }
102
103
109
110 public ArrayList<JFieldDeclaration> instanceFieldInitializations() {
111 return instanceFieldInitializations;
112 }
113
114
120
121 public void declareThisType(Context context) {
122 String qualifiedName = JAST.compilationUnit.packageName() == "" ? name
123 : JAST.compilationUnit.packageName() + "/" + name;
124 CLEmitter partial = new CLEmitter(false);
125 partial.addClass(mods, qualifiedName, Type.OBJECT.jvmName(), null,
126 false); thisType = Type.typeFor(partial.toClass());
128 context.addType(line, thisType);
129 }
130
131
139
140 public void preAnalyze(Context context) {
141 this.context = new ClassContext(this, context);
143
144 superType = superType.resolve(this.context);
146
147 thisType.checkAccess(line, superType);
151 if (superType.isFinal()) {
152 JAST.compilationUnit.reportSemanticError(line,
153 "Cannot extend a final type: %s", superType.toString());
154 }
155
156 CLEmitter partial = new CLEmitter(false);
158
159 String qualifiedName = JAST.compilationUnit.packageName() == "" ? name
161 : JAST.compilationUnit.packageName() + "/" + name;
162 partial.addClass(mods, qualifiedName, superType.jvmName(), null, false);
163
164 for (JMember member : classBlock) {
167 member.preAnalyze(this.context, partial);
168 if (member instanceof JConstructorDeclaration
169 && ((JConstructorDeclaration) member).params.size() == 0) {
170 hasExplicitConstructor = true;
171 }
172 }
173
174 if (!hasExplicitConstructor) {
176 codegenPartialImplicitConstructor(partial);
177 }
178
179 Type id = this.context.lookupType(name);
183 if (id != null && !JAST.compilationUnit.errorHasOccurred()) {
184 id.setClassRep(partial.toClass());
185 }
186 }
187
188
197
198 public JAST analyze(Context context) {
199 for (JMember member : classBlock) {
201 ((JAST) member).analyze(this.context);
202 }
203
204 for (JMember member : classBlock) {
206 if (member instanceof JFieldDeclaration) {
207 JFieldDeclaration fieldDecl = (JFieldDeclaration) member;
208 if (fieldDecl.mods().contains("static")) {
209 staticFieldInitializations.add(fieldDecl);
210 } else {
211 instanceFieldInitializations.add(fieldDecl);
212 }
213 }
214 }
215
216 if (!thisType.isAbstract() && thisType.abstractMethods().size() > 0) {
219 String methods = "";
220 for (Method method : thisType.abstractMethods()) {
221 methods += "\n" + method;
222 }
223 JAST.compilationUnit.reportSemanticError(line,
224 "Class must be declared abstract since it defines "
225 + "the following abstract methods: %s", methods);
226
227 }
228 return this;
229 }
230
231
238
239 public void codegen(CLEmitter output) {
240 String qualifiedName = JAST.compilationUnit.packageName() == "" ? name
242 : JAST.compilationUnit.packageName() + "/" + name;
243 output.addClass(mods, qualifiedName, superType.jvmName(), null, false);
244
245 if (!hasExplicitConstructor) {
247 codegenImplicitConstructor(output);
248 }
249
250 for (JMember member : classBlock) {
252 ((JAST) member).codegen(output);
253 }
254
255 if (staticFieldInitializations.size() > 0) {
257 codegenClassInit(output);
258 }
259 }
260
261
264
265 public void writeToStdOut(PrettyPrinter p) {
266 p.printf("<JClassDeclaration line=\"%d\" name=\"%s\""
267 + " super=\"%s\">\n", line(), name, superType.toString());
268 p.indentRight();
269 if (context != null) {
270 context.writeToStdOut(p);
271 }
272 if (mods != null) {
273 p.println("<Modifiers>");
274 p.indentRight();
275 for (String mod : mods) {
276 p.printf("<Modifier name=\"%s\"/>\n", mod);
277 }
278 p.indentLeft();
279 p.println("</Modifiers>");
280 }
281 if (classBlock != null) {
282 p.println("<ClassBlock>");
283 for (JMember member : classBlock) {
284 ((JAST) member).writeToStdOut(p);
285 }
286 p.println("</ClassBlock>");
287 }
288 p.indentLeft();
289 p.println("</JClassDeclaration>");
290 }
291
292
300
301 private void codegenPartialImplicitConstructor(CLEmitter partial) {
302 ArrayList<String> mods = new ArrayList<String>();
304 mods.add("public");
305 partial.addMethod(mods, "<init>", "()V", null, false);
306 partial.addNoArgInstruction(ALOAD_0);
307 partial.addMemberAccessInstruction(INVOKESPECIAL, superType.jvmName(),
308 "<init>", "()V");
309
310 partial.addNoArgInstruction(RETURN);
312 }
313
314
322
323 private void codegenImplicitConstructor(CLEmitter output) {
324 ArrayList<String> mods = new ArrayList<String>();
326 mods.add("public");
327 output.addMethod(mods, "<init>", "()V", null, false);
328 output.addNoArgInstruction(ALOAD_0);
329 output.addMemberAccessInstruction(INVOKESPECIAL, superType.jvmName(),
330 "<init>", "()V");
331
332 for (JFieldDeclaration instanceField : instanceFieldInitializations) {
335 instanceField.codegenInitializations(output);
336 }
337
338 output.addNoArgInstruction(RETURN);
340 }
341
342
350
351 private void codegenClassInit(CLEmitter output) {
352 ArrayList<String> mods = new ArrayList<String>();
353 mods.add("public");
354 mods.add("static");
355 output.addMethod(mods, "<clinit>", "()V", null, false);
356
357 for (JFieldDeclaration staticField : staticFieldInitializations) {
360 staticField.codegenInitializations(output);
361 }
362
363 output.addNoArgInstruction(RETURN);
365 }
366
367 }
368