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