first scanner /parser copied from the jdt java version
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / Assignment.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.*;
15 import net.sourceforge.phpdt.internal.compiler.flow.*;
16 import net.sourceforge.phpdt.internal.compiler.lookup.*;
17
18 public class Assignment extends Expression {
19
20         public Reference lhs;
21         public Expression expression;
22         public TypeBinding lhsType;
23         
24         public Assignment(Expression lhs, Expression expression, int sourceEnd) {
25                 //lhs is always a reference by construction ,
26                 //but is build as an expression ==> the checkcast cannot fail
27
28                 this.lhs = (Reference) lhs;
29                 this.expression = expression;
30
31                 this.sourceStart = lhs.sourceStart;
32                 this.sourceEnd = sourceEnd;
33         }
34
35         public FlowInfo analyseCode(
36                 BlockScope currentScope,
37                 FlowContext flowContext,
38                 FlowInfo flowInfo) {
39                 // record setting a variable: various scenarii are possible, setting an array reference, 
40                 // a field reference, a blank final field reference, a field of an enclosing instance or 
41                 // just a local variable.
42
43                 return lhs
44                         .analyseAssignment(currentScope, flowContext, flowInfo, this, false)
45                         .unconditionalInits();
46         }
47
48         public void generateCode(
49                 BlockScope currentScope,
50                 CodeStream codeStream,
51                 boolean valueRequired) {
52
53                 // various scenarii are possible, setting an array reference, 
54                 // a field reference, a blank final field reference, a field of an enclosing instance or 
55                 // just a local variable.
56
57                 int pc = codeStream.position;
58                 lhs.generateAssignment(currentScope, codeStream, this, valueRequired);
59                 // variable may have been optimized out
60                 // the lhs is responsible to perform the implicitConversion generation for the assignment since optimized for unused local assignment.
61                 codeStream.recordPositionsFrom(pc, this.sourceStart);
62         }
63
64         public TypeBinding resolveType(BlockScope scope) {
65
66                 // due to syntax lhs may be only a NameReference, a FieldReference or an ArrayReference
67                 constant = NotAConstant;
68                 this.lhsType = lhs.resolveType(scope);
69                 TypeBinding expressionTb = expression.resolveType(scope);
70                 if (this.lhsType == null || expressionTb == null)
71                         return null;
72
73                 // Compile-time conversion of base-types : implicit narrowing integer into byte/short/character
74                 // may require to widen the rhs expression at runtime
75                 if ((expression.isConstantValueOfTypeAssignableToType(expressionTb, this.lhsType)
76                         || (this.lhsType.isBaseType() && BaseTypeBinding.isWidening(this.lhsType.id, expressionTb.id)))
77                         || (scope.areTypesCompatible(expressionTb, this.lhsType))) {
78                         expression.implicitWidening(this.lhsType, expressionTb);
79                         return this.lhsType;
80                 }
81                 scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
82                         expression,
83                         expressionTb,
84                         this.lhsType);
85                 return null;
86         }
87
88         public String toString(int tab) {
89
90                 //no () when used as a statement 
91                 return tabString(tab) + toStringExpressionNoParenthesis();
92         }
93
94         public String toStringExpression() {
95
96                 //subclass redefine toStringExpressionNoParenthesis()
97                 return "(" + toStringExpressionNoParenthesis() + ")"; //$NON-NLS-2$ //$NON-NLS-1$
98         } 
99         
100         public String toStringExpressionNoParenthesis() {
101
102                 return lhs.toStringExpression() + " " //$NON-NLS-1$
103                         + "=" //$NON-NLS-1$
104                         + ((expression.constant != null) && (expression.constant != NotAConstant)
105                                 ? " /*cst:" + expression.constant.toString() + "*/ " //$NON-NLS-1$ //$NON-NLS-2$
106                                 : " ")  //$NON-NLS-1$
107                         + expression.toStringExpression();
108         }
109         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
110                 
111                 if (visitor.visit(this, scope)) {
112                         lhs.traverse(visitor, scope);
113                         expression.traverse(visitor, scope);
114                 }
115                 visitor.endVisit(this, scope);
116         }
117 }