1
3 package jminusminus;
4
5 import java.util.Hashtable;
6 import static jminusminus.CLConstants.*;
7
8
12
13 class JCastOp extends JExpression {
14
15
16 private Type cast;
17
18
19 private JExpression expr;
20
21
22 private static Conversions conversions;
23
24
25 private Converter converter;
26
27
38
39 public JCastOp(int line, Type cast, JExpression expr) {
40 super(line);
41 this.cast = cast;
42 this.expr = expr;
43 conversions = new Conversions();
44 }
45
46
55
56 public JExpression analyze(Context context) {
57 expr = (JExpression) expr.analyze(context);
58 type = cast = cast.resolve(context);
59 if (cast.equals(expr.type())) {
60 converter = Converter.Identity;
61 } else if (cast.isJavaAssignableFrom(expr.type())) {
62 converter = Converter.WidenReference;
63 } else if (expr.type().isJavaAssignableFrom(cast)) {
64 converter = new NarrowReference(cast);
65 } else if ((converter = conversions.get(expr.type(), cast)) != null) {
66 } else {
67 JAST.compilationUnit.reportSemanticError(line, "Cannot cast a "
68 + expr.type().toString() + " to a " + cast.toString());
69 }
70 return this;
71 }
72
73
81
82 public void codegen(CLEmitter output) {
83 expr.codegen(output);
84 converter.codegen(output);
85 }
86
87
90
91 public void writeToStdOut(PrettyPrinter p) {
92 p.printf("<JCastOp line=\"%d\" type=\"%s\"/>\n", line(),
93 ((cast == null) ? "" : cast.toString()));
94 p.indentRight();
95 if (expr != null) {
96 p.println("<Expression>");
97 p.indentRight();
98 expr.writeToStdOut(p);
99 p.indentLeft();
100 p.println("</Expression>");
101 }
102 p.indentLeft();
103 p.println("</JCastOp>");
104 }
105
106 }
107
108
111
112 class Conversions {
113
114
118 private Hashtable<String, Converter> table;
119
120
123
124 public Conversions() {
125 table = new Hashtable<String, Converter>();
126
127
129 put(Type.CHAR, Type.INT, Converter.Identity);
130 put(Type.INT, Type.CHAR, new I2C());
131
132 put(Type.CHAR, Type.BOXED_CHAR, new Boxing(Type.CHAR, Type.BOXED_CHAR));
134 put(Type.INT, Type.BOXED_INT, new Boxing(Type.INT, Type.BOXED_INT));
135 put(Type.BOOLEAN, Type.BOXED_BOOLEAN, new Boxing(Type.BOOLEAN,
136 Type.BOXED_BOOLEAN));
137
138 put(Type.BOXED_CHAR, Type.CHAR, new UnBoxing(Type.BOXED_CHAR,
140 Type.CHAR, "charValue"));
141 put(Type.BOXED_INT, Type.INT, new UnBoxing(Type.BOXED_INT, Type.INT,
142 "intValue"));
143 put(Type.BOXED_BOOLEAN, Type.BOOLEAN, new UnBoxing(Type.BOXED_BOOLEAN,
144 Type.BOOLEAN, "booleanValue"));
145 }
146
147
157
158 private void put(Type source, Type target, Converter c) {
159 table.put(source.toDescriptor() + "2" + target.toDescriptor(), c);
160 }
161
162
173
174 public Converter get(Type source, Type target) {
175 return table.get(source.toDescriptor() + "2" + target.toDescriptor());
176 }
177
178 }
179
180
184
185 interface Converter {
186
187
188 public static Converter Identity = new Identity();
189
190
191 public static Converter WidenReference = Identity;
192
193
200
201 public void codegen(CLEmitter output);
202
203 }
204
205
208
209 class Identity implements Converter {
210
211
214
215 public void codegen(CLEmitter output) {
216 }
218
219 }
220
221
225
226 class NarrowReference implements Converter {
227
228
229 private Type target;
230
231
237
238 public NarrowReference(Type target) {
239 this.target = target;
240 }
241
242
245
246 public void codegen(CLEmitter output) {
247 output.addReferenceInstruction(CHECKCAST, target.jvmName());
248 }
249
250 }
251
252
256
257 class Boxing implements Converter {
258
259
260 private Type source;
261
262
263 private Type target;
264
265
273
274 public Boxing(Type source, Type target) {
275 this.source = source;
276 this.target = target;
277 }
278
279
282
283 public void codegen(CLEmitter output) {
284 output.addMemberAccessInstruction(INVOKESTATIC, target.jvmName(),
285 "valueOf", "(" + source.toDescriptor() + ")"
286 + target.toDescriptor());
287 }
288
289 }
290
291
295
296 class UnBoxing implements Converter {
297
298
299 private Type source;
300
301
302 private Type target;
303
304
305 private String methodName;
306
307
317
318 public UnBoxing(Type source, Type target, String methodName) {
319 this.source = source;
320 this.target = target;
321 this.methodName = methodName;
322 }
323
324
327
328 public void codegen(CLEmitter output) {
329 output.addMemberAccessInstruction(INVOKEVIRTUAL, source.jvmName(),
330 methodName, "()" + target.toDescriptor());
331 }
332
333 }
334
335
338
339 class I2C implements Converter {
340
341
344
345 public void codegen(CLEmitter output) {
346 output.addNoArgInstruction(I2C);
347 }
348
349 }
350