1
3 package jminusminus;
4
5 import java.util.ArrayList;
6
7 import static jminusminus.CLConstants.*;
8
9
12 class JMethodDeclaration extends JAST implements JMember {
13
16 protected ArrayList<String> mods;
17
18
21 protected String name;
22
23
26 protected Type returnType;
27
28
31 protected ArrayList<JFormalParameter> params;
32
33
36 protected ArrayList<TypeName> exceptions;
37
38
41 protected JBlock body;
42
43
46 protected MethodContext context;
47
48
51 protected String descriptor;
52
53
56 protected boolean isAbstract;
57
58
61 protected boolean isStatic;
62
63
66 protected boolean isPrivate;
67
68
79 public JMethodDeclaration(int line, ArrayList<String> mods, String name, Type returnType,
80 ArrayList<JFormalParameter> params,
81 ArrayList<TypeName> exceptions, JBlock body) {
82 super(line);
83 this.mods = mods;
84 this.name = name;
85 this.returnType = returnType;
86 this.params = params;
87 this.exceptions = exceptions;
88 this.body = body;
89 isAbstract = mods.contains("abstract");
90 isStatic = mods.contains("static");
91 isPrivate = mods.contains("private");
92 }
93
94
97 public void preAnalyze(Context context, CLEmitter partial) {
98 for (JFormalParameter param : params) {
100 param.setType(param.type().resolve(context));
101 }
102
103 returnType = returnType.resolve(context);
105
106 if (isAbstract && body != null) {
108 JAST.compilationUnit.reportSemanticError(line(), "abstract method cannot have a body");
109 } else if (body == null && !isAbstract) {
110 JAST.compilationUnit.reportSemanticError(line(),
111 "Method without body must be abstract");
112 } else if (isAbstract && isPrivate) {
113 JAST.compilationUnit.reportSemanticError(line(), "private method cannot be abstract");
114 } else if (isAbstract && isStatic) {
115 JAST.compilationUnit.reportSemanticError(line(), "static method cannot be abstract");
116 }
117
118 descriptor = "(";
120 for (JFormalParameter param : params) {
121 descriptor += param.type().toDescriptor();
122 }
123 descriptor += ")" + returnType.toDescriptor();
124
125 partialCodegen(context, partial);
127 }
128
129
132 public JAST analyze(Context context) {
133 MethodContext methodContext = new MethodContext(context, isStatic, returnType);
134 this.context = methodContext;
135
136 if (!isStatic) {
137 this.context.nextOffset();
139 }
140
141 for (JFormalParameter param : params) {
144 LocalVariableDefn defn = new LocalVariableDefn(param.type(), this.context.nextOffset());
145 defn.initialize();
146 this.context.addEntry(param.line(), param.name(), defn);
147 }
148
149 if (body != null) {
150 body = body.analyze(this.context);
151 if (returnType != Type.VOID && !methodContext.methodHasReturn()) {
152 JAST.compilationUnit.reportSemanticError(line(),
153 "Non-void method must have a return statement");
154 }
155 }
156 return this;
157 }
158
159
162 public void partialCodegen(Context context, CLEmitter partial) {
163 partial.addMethod(mods, name, descriptor, null, false);
164 if (returnType == Type.VOID) {
165 partial.addNoArgInstruction(RETURN);
166 } else if (returnType == Type.INT || returnType == Type.BOOLEAN ||
167 returnType == Type.CHAR) {
168 partial.addNoArgInstruction(ICONST_0);
169 partial.addNoArgInstruction(IRETURN);
170 } else {
171 partial.addNoArgInstruction(ACONST_NULL);
172 partial.addNoArgInstruction(ARETURN);
173 }
174 }
175
176
179 public void codegen(CLEmitter output) {
180 output.addMethod(mods, name, descriptor, null, false);
181 if (body != null) {
182 body.codegen(output);
183 }
184 if (returnType == Type.VOID) {
185 output.addNoArgInstruction(RETURN);
186 }
187 }
188
189
192 public void toJSON(JSONElement json) {
193 JSONElement e = new JSONElement();
194 json.addChild("JMethodDeclaration:" + line, e);
195 e.addAttribute("name", name);
196 e.addAttribute("returnType", returnType.toString());
197 if (mods != null) {
198 ArrayList<String> value = new ArrayList<String>();
199 for (String mod : mods) {
200 value.add(String.format("\"%s\"", mod));
201 }
202 e.addAttribute("modifiers", value);
203 }
204 if (params != null) {
205 ArrayList<String> value = new ArrayList<String>();
206 for (JFormalParameter param : params) {
207 value.add(String.format("[\"%s\", \"%s\"]", param.name(),
208 param.type() == null ? "" : param.type().toString()));
209 }
210 e.addAttribute("parameters", value);
211 }
212 if (exceptions != null) {
213 ArrayList<String> value = new ArrayList<String>();
214 for (TypeName exception : exceptions) {
215 value.add(String.format("\"%s\"", exception.toString()));
216 }
217 e.addAttribute("throws", value);
218 }
219 if (context != null) {
220 context.toJSON(e);
221 }
222 if (body != null) {
223 body.toJSON(e);
224 }
225 }
226 }
227