*** empty log message ***
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / ArrayReference.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
18 import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
20 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
21
22 public class ArrayReference extends Reference {
23         
24         public Expression receiver;
25         public Expression position;
26
27         public TypeBinding arrayElementBinding;
28
29         public ArrayReference(Expression rec, Expression pos) {
30                 this.receiver = rec;
31                 this.position = pos;
32                 sourceStart = rec.sourceStart;
33         }
34
35         public FlowInfo analyseAssignment(
36                 BlockScope currentScope,
37                 FlowContext flowContext,
38                 FlowInfo flowInfo,
39                 Assignment assignment,
40                 boolean compoundAssignment) {
41
42                 if (assignment.expression == null) {
43                         return analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
44                 } else {
45                         return assignment
46                                 .expression
47                                 .analyseCode(
48                                         currentScope,
49                                         flowContext,
50                                         analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
51                                 .unconditionalInits();
52                 }
53         }
54
55         public FlowInfo analyseCode(
56                 BlockScope currentScope,
57                 FlowContext flowContext,
58                 FlowInfo flowInfo) {
59
60                 return position.analyseCode(
61                         currentScope,
62                         flowContext,
63                         receiver.analyseCode(currentScope, flowContext, flowInfo));
64         }
65
66         public void generateAssignment(
67                 BlockScope currentScope,
68                 CodeStream codeStream,
69                 Assignment assignment,
70                 boolean valueRequired) {
71
72                 receiver.generateCode(currentScope, codeStream, true);
73                 position.generateCode(currentScope, codeStream, true);
74                 assignment.expression.generateCode(currentScope, codeStream, true);
75                 codeStream.arrayAtPut(arrayElementBinding.id, valueRequired);
76                 if (valueRequired) {
77                         codeStream.generateImplicitConversion(assignment.implicitConversion);
78                 }
79         }
80
81         /**
82          * Code generation for a array reference
83          */
84         public void generateCode(
85                 BlockScope currentScope,
86                 CodeStream codeStream,
87                 boolean valueRequired) {
88
89                 int pc = codeStream.position;
90                 receiver.generateCode(currentScope, codeStream, true);
91                 position.generateCode(currentScope, codeStream, true);
92                 codeStream.arrayAt(arrayElementBinding.id);
93                 // Generating code for the potential runtime type checking
94                 if (valueRequired) {
95                         codeStream.generateImplicitConversion(implicitConversion);
96                 } else {
97                         if (arrayElementBinding == LongBinding
98                                 || arrayElementBinding == DoubleBinding) {
99                                 codeStream.pop2();
100                         } else {
101                                 codeStream.pop();
102                         }
103                 }
104                 codeStream.recordPositionsFrom(pc, this.sourceStart);
105         }
106
107         public void generateCompoundAssignment(
108                 BlockScope currentScope,
109                 CodeStream codeStream,
110                 Expression expression,
111                 int operator,
112                 int assignmentImplicitConversion,
113                 boolean valueRequired) {
114
115                 receiver.generateCode(currentScope, codeStream, true);
116                 position.generateCode(currentScope, codeStream, true);
117                 codeStream.dup2();
118                 codeStream.arrayAt(arrayElementBinding.id);
119                 int operationTypeID;
120                 if ((operationTypeID = implicitConversion >> 4) == T_String) {
121                         codeStream.generateStringAppend(currentScope, null, expression);
122                 } else {
123                         // promote the array reference to the suitable operation type
124                         codeStream.generateImplicitConversion(implicitConversion);
125                         // generate the increment value (will by itself  be promoted to the operation value)
126                         if (expression == IntLiteral.One) { // prefix operation
127                                 codeStream.generateConstant(expression.constant, implicitConversion);
128                         } else {
129                                 expression.generateCode(currentScope, codeStream, true);
130                         }
131                         // perform the operation
132                         codeStream.sendOperator(operator, operationTypeID);
133                         // cast the value back to the array reference type
134                         codeStream.generateImplicitConversion(assignmentImplicitConversion);
135                 }
136                 codeStream.arrayAtPut(arrayElementBinding.id, valueRequired);
137         }
138
139         public void generatePostIncrement(
140                 BlockScope currentScope,
141                 CodeStream codeStream,
142                 CompoundAssignment postIncrement,
143                 boolean valueRequired) {
144
145                 receiver.generateCode(currentScope, codeStream, true);
146                 position.generateCode(currentScope, codeStream, true);
147                 codeStream.dup2();
148                 codeStream.arrayAt(arrayElementBinding.id);
149                 if (valueRequired) {
150                         if ((arrayElementBinding == LongBinding)
151                                 || (arrayElementBinding == DoubleBinding)) {
152                                 codeStream.dup2_x2();
153                         } else {
154                                 codeStream.dup_x2();
155                         }
156                 }
157                 codeStream.generateConstant(
158                         postIncrement.expression.constant,
159                         implicitConversion);
160                 codeStream.sendOperator(postIncrement.operator, arrayElementBinding.id);
161                 codeStream.generateImplicitConversion(
162                         postIncrement.assignmentImplicitConversion);
163                 codeStream.arrayAtPut(arrayElementBinding.id, false);
164         }
165
166         public TypeBinding resolveType(BlockScope scope) {
167
168                 constant = Constant.NotAConstant;
169                 TypeBinding arrayTb = receiver.resolveType(scope);
170                 if (arrayTb == null)
171                         return null;
172                 if (!arrayTb.isArrayType()) {
173                         scope.problemReporter().referenceMustBeArrayTypeAt(arrayTb, this);
174                         return null;
175                 }
176                 TypeBinding positionTb = position.resolveTypeExpecting(scope, IntBinding);
177                 if (positionTb == null)
178                         return null;
179                 position.implicitWidening(IntBinding, positionTb);
180                 return arrayElementBinding = ((ArrayBinding) arrayTb).elementsType(scope);
181         }
182
183         public String toStringExpression() {
184
185                 return receiver.toStringExpression() + "[" //$NON-NLS-1$
186                 +position.toStringExpression() + "]"; //$NON-NLS-1$
187         } 
188
189         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
190                 
191                 if (visitor.visit(this, scope)) {
192                         receiver.traverse(visitor, scope);
193                         position.traverse(visitor, scope);
194                 }
195                 visitor.endVisit(this, scope);
196         }
197 }