1
3 package jminusminus;
4
5 import static jminusminus.CLConstants.*;
6
7
11 class JFieldSelection extends JExpression implements JLhs {
12
15 protected JExpression target;
16
17 private AmbiguousName ambiguousPart;
19
20 private String fieldName;
22
23 private Field field;
25
26
33 public JFieldSelection(int line, JExpression target, String fieldName) {
34 this(line, null, target, fieldName);
35 }
36
37
45 public JFieldSelection(int line, AmbiguousName ambiguousPart, JExpression target,
46 String fieldName) {
47 super(line);
48 this.ambiguousPart = ambiguousPart;
49 this.target = target;
50 this.fieldName = fieldName;
51 }
52
53
56 public JExpression analyze(Context context) {
57 if (ambiguousPart != null) {
59 JExpression expr = ambiguousPart.reclassify(context);
60 if (expr != null) {
61 if (target == null) {
62 target = expr;
63 } else {
64 JAST.compilationUnit.reportSemanticError(line(), "Badly formed suffix");
66 }
67 }
68 }
69 target = (JExpression) target.analyze(context);
70 Type targetType = target.type();
71
72 if ((targetType.isArray()) && fieldName.equals("length")) {
74 type = Type.INT;
75 } else {
76 if (targetType.isPrimitive()) {
78 JAST.compilationUnit.reportSemanticError(line(),
79 "Target of a field selection must be a reference type");
80 type = Type.ANY;
81 return this;
82 }
83 field = targetType.fieldFor(fieldName);
84 if (field == null) {
85 JAST.compilationUnit.reportSemanticError(line(),
86 "Cannot find a field: " + fieldName);
87 type = Type.ANY;
88 } else {
89 context.definingType().checkAccess(line, (Member) field);
90 type = field.type();
91
92 if (!field.isStatic()) {
94 if (target instanceof JVariable &&
95 ((JVariable) target).iDefn() instanceof TypeNameDefn) {
96 JAST.compilationUnit.reportSemanticError(line(), "Non-static field " +
97 fieldName + " cannot be referenced from a static context");
98 }
99 }
100 }
101 }
102 return this;
103 }
104
105
108 public JExpression analyzeLhs(Context context) {
109 JExpression result = analyze(context);
110 if (field.isFinal()) {
111 JAST.compilationUnit.reportSemanticError(line, "The field " + fieldName + " in type " +
112 target.type.toString() + " is final");
113 }
114 return result;
115 }
116
117
120 public void codegen(CLEmitter output) {
121 target.codegen(output);
122
123 if ((target.type().isArray()) && fieldName.equals("length")) {
125 output.addNoArgInstruction(ARRAYLENGTH);
126 } else {
127 int mnemonic = field.isStatic() ? GETSTATIC : GETFIELD;
128 output.addMemberAccessInstruction(mnemonic, target.type().jvmName(), fieldName,
129 type.toDescriptor());
130 }
131 }
132
133
136 public void codegen(CLEmitter output, String targetLabel, boolean onTrue) {
137 codegen(output);
138 if (onTrue) {
139 output.addBranchInstruction(IFNE, targetLabel);
140 } else {
141 output.addBranchInstruction(IFEQ, targetLabel);
142 }
143 }
144
145
148 public void codegenLoadLhsLvalue(CLEmitter output) {
149 if (!field.isStatic()) {
151 target.codegen(output);
152 }
153 }
154
155
158 public void codegenLoadLhsRvalue(CLEmitter output) {
159 if (field.isStatic()) {
160 output.addMemberAccessInstruction(GETSTATIC, target.type()
161 .jvmName(), fieldName, field.type().toDescriptor());
162 } else {
163 output.addNoArgInstruction(type == Type.STRING ? DUP_X1 : DUP);
164 output.addMemberAccessInstruction(GETFIELD,
165 target.type().jvmName(), fieldName, field.type().toDescriptor());
166 }
167 }
168
169
172 public void codegenDuplicateRvalue(CLEmitter output) {
173 if (field.isStatic()) {
174 output.addNoArgInstruction(DUP);
175 } else {
176 output.addNoArgInstruction(DUP_X1);
177 }
178 }
179
180
183 public void codegenStore(CLEmitter output) {
184 String descriptor = field.type().toDescriptor();
185 if (field.isStatic()) {
186 output.addMemberAccessInstruction(PUTSTATIC, target.type().jvmName(), fieldName,
187 descriptor);
188 } else {
189 output.addMemberAccessInstruction(PUTFIELD, target.type().jvmName(), fieldName,
190 descriptor);
191 }
192 }
193
194
197 public void toJSON(JSONElement json) {
198 JSONElement e = new JSONElement();
199 json.addChild("JFieldSelection:" + line, e);
200 e.addAttribute("ambiguousPart", ambiguousPart == null ? "null" : ambiguousPart.toString());
201 e.addAttribute("name", fieldName);
202 if (target != null) {
203 JSONElement e1 = new JSONElement();
204 e.addChild("Target", e1);
205 target.toJSON(e1);
206 }
207 }
208 }
209