1
3 package jminusminus;
4
5 import java.util.ArrayList;
6
7 import static jminusminus.CLConstants.*;
8
9
13 class JMessageExpression extends JExpression {
14 private JExpression target;
16
17 private AmbiguousName ambiguousPart;
19
20 private String messageName;
22
23 private ArrayList<JExpression> arguments;
25
26 private Type[] argTypes;
28
29 private Method method;
31
32
40 public JMessageExpression(int line, JExpression target, String messageName,
41 ArrayList<JExpression> arguments) {
42 this(line, target, null, messageName, arguments);
43 }
44
45
54 public JMessageExpression(int line, JExpression target, AmbiguousName ambiguousPart,
55 String messageName, ArrayList<JExpression> arguments) {
56 super(line);
57 this.target = target;
58 this.ambiguousPart = ambiguousPart;
59 this.messageName = messageName;
60 this.arguments = arguments;
61 }
62
63
66 public JExpression analyze(Context context) {
67 if (ambiguousPart != null) {
69 JExpression expr = ambiguousPart.reclassify(context);
70 if (expr != null) {
71 if (target == null) {
72 target = expr;
73 } else {
74 JAST.compilationUnit.reportSemanticError(line(), "Badly formed suffix");
76 }
77 }
78 }
79
80 argTypes = new Type[arguments.size()];
82 for (int i = 0; i < arguments.size(); i++) {
83 arguments.set(i, (JExpression) arguments.get(i).analyze(context));
84 argTypes[i] = arguments.get(i).type();
85 }
86
87 Type thisType = ((JTypeDecl) context.classContext.definition()).thisType();
89
90 if (target == null) {
92 if (!context.methodContext().isStatic()) {
94 target = new JThis(line()).analyze(context);
95 } else {
96 target = new JVariable(line(), context.definingType().toString()).analyze(context);
97 }
98 } else {
99 target = (JExpression) target.analyze(context);
100 if (target.type().isPrimitive()) {
101 JAST.compilationUnit.reportSemanticError(line(),
102 "Cannot invoke a message on a primitive type: " + target.type());
103 }
104 }
105
106 method = target.type().methodFor(messageName, argTypes);
108 if (method == null) {
109 JAST.compilationUnit.reportSemanticError(line(),
110 "Cannot find method for: " + Type.signatureFor(messageName, argTypes));
111 type = Type.ANY;
112 } else {
113 context.definingType().checkAccess(line, (Member) method);
114 type = method.returnType();
115
116 if (!method.isStatic()) {
118 if (target instanceof JVariable &&
119 ((JVariable) target).iDefn() instanceof TypeNameDefn) {
120 JAST.compilationUnit.reportSemanticError(line(),
121 "Non-static method " + Type.signatureFor(messageName, argTypes) +
122 " cannot be referenced from a static context");
123 }
124 }
125 }
126 return this;
127 }
128
129
132 public void codegen(CLEmitter output) {
133 if (!method.isStatic()) {
134 target.codegen(output);
135 }
136 for (JExpression argument : arguments) {
137 argument.codegen(output);
138 }
139 int mnemonic = method.isStatic() ? INVOKESTATIC : target.type().isInterface() ?
140 INVOKEINTERFACE : INVOKEVIRTUAL;
141 output.addMemberAccessInstruction(mnemonic, target.type().jvmName(), messageName,
142 method.toDescriptor());
143 if (isStatementExpression && type != Type.VOID) {
144 output.addNoArgInstruction(POP);
146 }
147 }
148
149
152 public void codegen(CLEmitter output, String targetLabel, boolean onTrue) {
153 codegen(output);
154 if (onTrue) {
155 output.addBranchInstruction(IFNE, targetLabel);
156 } else {
157 output.addBranchInstruction(IFEQ, targetLabel);
158 }
159 }
160
161
164 public void toJSON(JSONElement json) {
165 JSONElement e = new JSONElement();
166 json.addChild("JMessageExpression:" + line, e);
167 e.addAttribute("ambiguousPart", ambiguousPart == null ? "null" : ambiguousPart.toString());
168 e.addAttribute("name", messageName);
169 if (target != null) {
170 JSONElement e1 = new JSONElement();
171 e.addChild("Target", e1);
172 target.toJSON(e1);
173 }
174 if (arguments != null) {
175 for (JExpression argument : arguments) {
176 JSONElement e1 = new JSONElement();
177 e.addChild("Argument", e1);
178 argument.toJSON(e1);
179 }
180 }
181 }
182 }
183