1
3 package jminusminus;
4
5 import java.util.Hashtable;
6
7 import static jminusminus.CLConstants.*;
8
9
12 class JCastOp extends JExpression {
13 private Type cast;
15
16 private JExpression expr;
18
19 private static Conversions conversions;
21
22 private Converter converter;
24
25
32 public JCastOp(int line, Type cast, JExpression expr) {
33 super(line);
34 this.cast = cast;
35 this.expr = expr;
36 conversions = new Conversions();
37 }
38
39
42 public JExpression analyze(Context context) {
43 expr = (JExpression) expr.analyze(context);
44 type = cast = cast.resolve(context);
45 if (cast.equals(expr.type())) {
46 converter = Converter.Identity;
47 } else if (cast.isJavaAssignableFrom(expr.type())) {
48 converter = Converter.WidenReference;
49 } else if (expr.type().isJavaAssignableFrom(cast)) {
50 converter = new NarrowReference(cast);
51 } else if (conversions.get(expr.type(), cast) != null) {
52 converter = conversions.get(expr.type(), cast);
53 } else {
54 JAST.compilationUnit.reportSemanticError(line,
55 "Cannot cast a " + expr.type().toString() + " to a " + cast.toString());
56 }
57 return this;
58 }
59
60
63 public void codegen(CLEmitter output) {
64 expr.codegen(output);
65 converter.codegen(output);
66 }
67
68
71 public void toJSON(JSONElement json) {
72 JSONElement e = new JSONElement();
73 json.addChild("JCastOp:" + line, e);
74 e.addAttribute("type", cast == null ? "" : cast.toString());
75 JSONElement e1 = new JSONElement();
76 e.addChild("Expression", e1);
77 expr.toJSON(e1);
78 }
79 }
80
81
84 class Conversions {
85 private Hashtable<String, Converter> table;
87
88
91 public Conversions() {
92 table = new Hashtable<String, Converter>();
93
94 put(Type.CHAR, Type.INT, Converter.Identity);
96 put(Type.INT, Type.CHAR, new I2C());
97
98 put(Type.CHAR, Type.BOXED_CHAR, new Boxing(Type.CHAR, Type.BOXED_CHAR));
100 put(Type.INT, Type.BOXED_INT, new Boxing(Type.INT, Type.BOXED_INT));
101 put(Type.BOOLEAN, Type.BOXED_BOOLEAN, new Boxing(Type.BOOLEAN, Type.BOXED_BOOLEAN));
102
103 put(Type.BOXED_CHAR, Type.CHAR, new UnBoxing(Type.BOXED_CHAR, Type.CHAR, "charValue"));
105 put(Type.BOXED_INT, Type.INT, new UnBoxing(Type.BOXED_INT, Type.INT, "intValue"));
106 put(Type.BOXED_BOOLEAN, Type.BOOLEAN, new UnBoxing(Type.BOXED_BOOLEAN, Type.BOOLEAN,
107 "booleanValue"));
108 }
109
110
117 public Converter get(Type source, Type target) {
118 return table.get(source.toDescriptor() + "2" + target.toDescriptor());
119 }
120
121 private void put(Type source, Type target, Converter c) {
123 table.put(source.toDescriptor() + "2" + target.toDescriptor(), c);
124 }
125 }
126
127
130 interface Converter {
131
134 public static Converter Identity = new Identity();
135
136
139 public static Converter WidenReference = Identity;
140
141
146 public void codegen(CLEmitter output);
147 }
148
149
152 class Identity implements Converter {
153
156 public void codegen(CLEmitter output) {
157 }
159 }
160
161
164 class NarrowReference implements Converter {
165 private Type target;
167
168
173 public NarrowReference(Type target) {
174 this.target = target;
175 }
176
177
180 public void codegen(CLEmitter output) {
181 output.addReferenceInstruction(CHECKCAST, target.jvmName());
182 }
183 }
184
185
188 class Boxing implements Converter {
189 private Type source;
191
192 private Type target;
194
195
201 public Boxing(Type source, Type target) {
202 this.source = source;
203 this.target = target;
204 }
205
206
209 public void codegen(CLEmitter output) {
210 output.addMemberAccessInstruction(INVOKESTATIC, target.jvmName(), "valueOf",
211 "(" + source.toDescriptor() + ")" + target.toDescriptor());
212 }
213 }
214
215
218 class UnBoxing implements Converter {
219 private Type source;
221
222 private Type target;
224
225 private String methodName;
227
228
235 public UnBoxing(Type source, Type target, String methodName) {
236 this.source = source;
237 this.target = target;
238 this.methodName = methodName;
239 }
240
241
244 public void codegen(CLEmitter output) {
245 output.addMemberAccessInstruction(INVOKEVIRTUAL, source.jvmName(), methodName,
246 "()" + target.toDescriptor());
247 }
248 }
249
250
253 class I2C implements Converter {
254
257 public void codegen(CLEmitter output) {
258 output.addNoArgInstruction(I2C);
259 }
260 }
261