1
3 package jminusminus;
4
5 import java.util.ArrayList;
6
7 import static jminusminus.CLConstants.*;
8
9
12 class JClassDeclaration extends JAST implements JTypeDecl {
13 private ArrayList<String> mods;
15
16 private String name;
18
19 private Type thisType;
21
22 private Type superType;
24
25 private ArrayList<TypeName> superInterfaces;
27
28 private ArrayList<JMember> classBlock;
30
31 private ClassContext context;
33
34 private boolean hasExplicitConstructor;
36
37 private ArrayList<JFieldDeclaration> instanceFieldInitializations;
39
40 private ArrayList<JFieldDeclaration> staticFieldInitializations;
42
43
53 public JClassDeclaration(int line, ArrayList<String> mods, String name, Type superType,
54 ArrayList<TypeName> superInterfaces, ArrayList<JMember> classBlock) {
55 super(line);
56 this.mods = mods;
57 this.name = name;
58 this.superType = superType;
59 this.superInterfaces = superInterfaces;
60 this.classBlock = classBlock;
61 hasExplicitConstructor = false;
62 instanceFieldInitializations = new ArrayList<JFieldDeclaration>();
63 staticFieldInitializations = new ArrayList<JFieldDeclaration>();
64 }
65
66
71 public ArrayList<JFieldDeclaration> instanceFieldInitializations() {
72 return instanceFieldInitializations;
73 }
74
75
78 public void declareThisType(Context context) {
79 String qualifiedName = JAST.compilationUnit.packageName() == "" ?
80 name : JAST.compilationUnit.packageName() + "/" + name;
81 CLEmitter partial = new CLEmitter(false);
82 partial.addClass(mods, qualifiedName, Type.OBJECT.jvmName(), null, false);
83 thisType = Type.typeFor(partial.toClass());
84 context.addType(line, thisType);
85 }
86
87
90 public void preAnalyze(Context context) {
91 this.context = new ClassContext(this, context);
93
94 superType = superType.resolve(this.context);
96
97 thisType.checkAccess(line, superType);
100 if (superType.isFinal()) {
101 JAST.compilationUnit.reportSemanticError(line, "Cannot extend a final type: %s",
102 superType.toString());
103 }
104
105 CLEmitter partial = new CLEmitter(false);
107
108 String qualifiedName = JAST.compilationUnit.packageName() == "" ?
110 name : JAST.compilationUnit.packageName() + "/" + name;
111 partial.addClass(mods, qualifiedName, superType.jvmName(), null, false);
112
113 for (JMember member : classBlock) {
115 member.preAnalyze(this.context, partial);
116 hasExplicitConstructor =
117 hasExplicitConstructor || member instanceof JConstructorDeclaration;
118 }
119
120 if (!hasExplicitConstructor) {
122 codegenPartialImplicitConstructor(partial);
123 }
124
125 Type id = this.context.lookupType(name);
127 if (id != null && !JAST.compilationUnit.errorHasOccurred()) {
128 id.setClassRep(partial.toClass());
129 }
130 }
131
132
135 public String name() {
136 return name;
137 }
138
139
142 public Type thisType() {
143 return thisType;
144 }
145
146
149 public Type superType() {
150 return superType;
151 }
152
153
156 public ArrayList<TypeName> superInterfaces() {
157 return superInterfaces;
158 }
159
160
163 public JAST analyze(Context context) {
164 for (JMember member : classBlock) {
166 ((JAST) member).analyze(this.context);
167 }
168
169 for (JMember member : classBlock) {
171 if (member instanceof JFieldDeclaration) {
172 JFieldDeclaration fieldDecl = (JFieldDeclaration) member;
173 if (fieldDecl.mods().contains("static")) {
174 staticFieldInitializations.add(fieldDecl);
175 } else {
176 instanceFieldInitializations.add(fieldDecl);
177 }
178 }
179 }
180
181 if (!thisType.isAbstract() && thisType.abstractMethods().size() > 0) {
183 String methods = "";
184 for (Method method : thisType.abstractMethods()) {
185 methods += "\n" + method;
186 }
187 JAST.compilationUnit.reportSemanticError(line,
188 "Class must be abstract since it defines abstract methods: %s", methods);
189 }
190 return this;
191 }
192
193
196 public void codegen(CLEmitter output) {
197 String qualifiedName = JAST.compilationUnit.packageName() == "" ?
199 name : JAST.compilationUnit.packageName() + "/" + name;
200 output.addClass(mods, qualifiedName, superType.jvmName(), null, false);
201
202 if (!hasExplicitConstructor) {
204 codegenImplicitConstructor(output);
205 }
206
207 for (JMember member : classBlock) {
209 ((JAST) member).codegen(output);
210 }
211
212 if (staticFieldInitializations.size() > 0) {
214 codegenClassInit(output);
215 }
216 }
217
218
221 public void toJSON(JSONElement json) {
222 JSONElement e = new JSONElement();
223 json.addChild("JClassDeclaration:" + line, e);
224 if (mods != null) {
225 ArrayList<String> value = new ArrayList<String>();
226 for (String mod : mods) {
227 value.add(String.format("\"%s\"", mod));
228 }
229 e.addAttribute("modifiers", value);
230 }
231 e.addAttribute("name", name);
232 e.addAttribute("super", superType == null ? "" : superType.toString());
233 if (superInterfaces != null) {
234 ArrayList<String> value = new ArrayList<String>();
235 for (TypeName impl : superInterfaces) {
236 value.add(String.format("\"%s\"", impl.toString()));
237 }
238 e.addAttribute("implements", value);
239 }
240 if (context != null) {
241 context.toJSON(e);
242 }
243 if (classBlock != null) {
244 for (JMember member : classBlock) {
245 ((JAST) member).toJSON(e);
246 }
247 }
248 }
249
250 private void codegenPartialImplicitConstructor(CLEmitter partial) {
253 ArrayList<String> mods = new ArrayList<String>();
254 mods.add("public");
255 partial.addMethod(mods, "<init>", "()V", null, false);
256 partial.addNoArgInstruction(ALOAD_0);
257 partial.addMemberAccessInstruction(INVOKESPECIAL, superType.jvmName(), "<init>", "()V");
258 partial.addNoArgInstruction(RETURN);
259 }
260
261 private void codegenImplicitConstructor(CLEmitter output) {
264 ArrayList<String> mods = new ArrayList<String>();
265 mods.add("public");
266 output.addMethod(mods, "<init>", "()V", null, false);
267 output.addNoArgInstruction(ALOAD_0);
268 output.addMemberAccessInstruction(INVOKESPECIAL, superType.jvmName(), "<init>", "()V");
269
270 for (JFieldDeclaration instanceField : instanceFieldInitializations) {
272 instanceField.codegenInitializations(output);
273 }
274
275 output.addNoArgInstruction(RETURN);
276 }
277
278 private void codegenClassInit(CLEmitter output) {
280 ArrayList<String> mods = new ArrayList<String>();
281 mods.add("public");
282 mods.add("static");
283 output.addMethod(mods, "<clinit>", "()V", null, false);
284
285 for (JFieldDeclaration staticField : staticFieldInitializations) {
287 staticField.codegenInitializations(output);
288 }
289
290 output.addNoArgInstruction(RETURN);
291 }
292 }
293