001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: CastExpr.java 468650 2006-10-28 07:03:30Z minchau $
020 */
021
022 package org.apache.xalan.xsltc.compiler;
023
024 import org.apache.bcel.generic.ConstantPoolGen;
025 import org.apache.bcel.generic.IF_ICMPNE;
026 import org.apache.bcel.generic.INVOKEINTERFACE;
027 import org.apache.bcel.generic.InstructionList;
028 import org.apache.bcel.generic.SIPUSH;
029 import org.apache.xalan.xsltc.compiler.util.BooleanType;
030 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
031 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
032 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
033 import org.apache.xalan.xsltc.compiler.util.MultiHashtable;
034 import org.apache.xalan.xsltc.compiler.util.NodeType;
035 import org.apache.xalan.xsltc.compiler.util.ResultTreeType;
036 import org.apache.xalan.xsltc.compiler.util.Type;
037 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
038 import org.apache.xml.dtm.Axis;
039
040 /**
041 * @author Jacek Ambroziak
042 * @author Santiago Pericas-Geertsen
043 * @author Morten Jorgensen
044 * @author Erwin Bolwidt <ejb@klomp.org>
045 */
046 final class CastExpr extends Expression {
047 private final Expression _left;
048
049 /**
050 * Legal conversions between internal types.
051 */
052 static private MultiHashtable InternalTypeMap = new MultiHashtable();
053
054 static {
055 // Possible type conversions between internal types
056 InternalTypeMap.put(Type.Boolean, Type.Boolean);
057 InternalTypeMap.put(Type.Boolean, Type.Real);
058 InternalTypeMap.put(Type.Boolean, Type.String);
059 InternalTypeMap.put(Type.Boolean, Type.Reference);
060 InternalTypeMap.put(Type.Boolean, Type.Object);
061
062 InternalTypeMap.put(Type.Real, Type.Real);
063 InternalTypeMap.put(Type.Real, Type.Int);
064 InternalTypeMap.put(Type.Real, Type.Boolean);
065 InternalTypeMap.put(Type.Real, Type.String);
066 InternalTypeMap.put(Type.Real, Type.Reference);
067 InternalTypeMap.put(Type.Real, Type.Object);
068
069 InternalTypeMap.put(Type.Int, Type.Int);
070 InternalTypeMap.put(Type.Int, Type.Real);
071 InternalTypeMap.put(Type.Int, Type.Boolean);
072 InternalTypeMap.put(Type.Int, Type.String);
073 InternalTypeMap.put(Type.Int, Type.Reference);
074 InternalTypeMap.put(Type.Int, Type.Object);
075
076 InternalTypeMap.put(Type.String, Type.String);
077 InternalTypeMap.put(Type.String, Type.Boolean);
078 InternalTypeMap.put(Type.String, Type.Real);
079 InternalTypeMap.put(Type.String, Type.Reference);
080 InternalTypeMap.put(Type.String, Type.Object);
081
082 InternalTypeMap.put(Type.NodeSet, Type.NodeSet);
083 InternalTypeMap.put(Type.NodeSet, Type.Boolean);
084 InternalTypeMap.put(Type.NodeSet, Type.Real);
085 InternalTypeMap.put(Type.NodeSet, Type.String);
086 InternalTypeMap.put(Type.NodeSet, Type.Node);
087 InternalTypeMap.put(Type.NodeSet, Type.Reference);
088 InternalTypeMap.put(Type.NodeSet, Type.Object);
089
090 InternalTypeMap.put(Type.Node, Type.Node);
091 InternalTypeMap.put(Type.Node, Type.Boolean);
092 InternalTypeMap.put(Type.Node, Type.Real);
093 InternalTypeMap.put(Type.Node, Type.String);
094 InternalTypeMap.put(Type.Node, Type.NodeSet);
095 InternalTypeMap.put(Type.Node, Type.Reference);
096 InternalTypeMap.put(Type.Node, Type.Object);
097
098 InternalTypeMap.put(Type.ResultTree, Type.ResultTree);
099 InternalTypeMap.put(Type.ResultTree, Type.Boolean);
100 InternalTypeMap.put(Type.ResultTree, Type.Real);
101 InternalTypeMap.put(Type.ResultTree, Type.String);
102 InternalTypeMap.put(Type.ResultTree, Type.NodeSet);
103 InternalTypeMap.put(Type.ResultTree, Type.Reference);
104 InternalTypeMap.put(Type.ResultTree, Type.Object);
105
106 InternalTypeMap.put(Type.Reference, Type.Reference);
107 InternalTypeMap.put(Type.Reference, Type.Boolean);
108 InternalTypeMap.put(Type.Reference, Type.Int);
109 InternalTypeMap.put(Type.Reference, Type.Real);
110 InternalTypeMap.put(Type.Reference, Type.String);
111 InternalTypeMap.put(Type.Reference, Type.Node);
112 InternalTypeMap.put(Type.Reference, Type.NodeSet);
113 InternalTypeMap.put(Type.Reference, Type.ResultTree);
114 InternalTypeMap.put(Type.Reference, Type.Object);
115
116 InternalTypeMap.put(Type.Object, Type.String);
117
118 InternalTypeMap.put(Type.Void, Type.String);
119 }
120
121 private boolean _typeTest = false;
122
123 /**
124 * Construct a cast expression and check that the conversion is
125 * valid by calling typeCheck().
126 */
127 public CastExpr(Expression left, Type type) throws TypeCheckError {
128 _left = left;
129 _type = type; // use inherited field
130
131 if ((_left instanceof Step) && (_type == Type.Boolean)) {
132 Step step = (Step)_left;
133 if ((step.getAxis() == Axis.SELF) && (step.getNodeType() != -1))
134 _typeTest = true;
135 }
136
137 // check if conversion is valid
138 setParser(left.getParser());
139 setParent(left.getParent());
140 left.setParent(this);
141 typeCheck(left.getParser().getSymbolTable());
142 }
143
144 public Expression getExpr() {
145 return _left;
146 }
147
148 /**
149 * Returns true if this expressions contains a call to position(). This is
150 * needed for context changes in node steps containing multiple predicates.
151 */
152 public boolean hasPositionCall() {
153 return(_left.hasPositionCall());
154 }
155
156 public boolean hasLastCall() {
157 return(_left.hasLastCall());
158 }
159
160 public String toString() {
161 return "cast(" + _left + ", " + _type + ")";
162 }
163
164 /**
165 * Type checking a cast expression amounts to verifying that the
166 * type conversion is legal. Cast expressions are created during
167 * type checking, but typeCheck() is usually not called on them.
168 * As a result, this method is called from the constructor.
169 */
170 public Type typeCheck(SymbolTable stable) throws TypeCheckError {
171 Type tleft = _left.getType();
172 if (tleft == null) {
173 tleft = _left.typeCheck(stable);
174 }
175 if (tleft instanceof NodeType) {
176 tleft = Type.Node; // multiple instances
177 }
178 else if (tleft instanceof ResultTreeType) {
179 tleft = Type.ResultTree; // multiple instances
180 }
181 if (InternalTypeMap.maps(tleft, _type) != null) {
182 return _type;
183 }
184 // throw new TypeCheckError(this);
185 throw new TypeCheckError(new ErrorMsg(
186 ErrorMsg.DATA_CONVERSION_ERR, tleft.toString(), _type.toString()));
187 }
188
189 public void translateDesynthesized(ClassGenerator classGen,
190 MethodGenerator methodGen) {
191 FlowList fl;
192 final Type ltype = _left.getType();
193
194 // This is a special case for the self:: axis. Instead of letting
195 // the Step object create and iterator that we cast back to a single
196 // node, we simply ask the DOM for the node type.
197 if (_typeTest) {
198 final ConstantPoolGen cpg = classGen.getConstantPool();
199 final InstructionList il = methodGen.getInstructionList();
200
201 final int idx = cpg.addInterfaceMethodref(DOM_INTF,
202 "getExpandedTypeID",
203 "(I)I");
204 il.append(new SIPUSH((short)((Step)_left).getNodeType()));
205 il.append(methodGen.loadDOM());
206 il.append(methodGen.loadContextNode());
207 il.append(new INVOKEINTERFACE(idx, 2));
208 _falseList.add(il.append(new IF_ICMPNE(null)));
209 }
210 else {
211
212 _left.translate(classGen, methodGen);
213 if (_type != ltype) {
214 _left.startIterator(classGen, methodGen);
215 if (_type instanceof BooleanType) {
216 fl = ltype.translateToDesynthesized(classGen, methodGen,
217 _type);
218 if (fl != null) {
219 _falseList.append(fl);
220 }
221 }
222 else {
223 ltype.translateTo(classGen, methodGen, _type);
224 }
225 }
226 }
227 }
228
229 public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
230 final Type ltype = _left.getType();
231 _left.translate(classGen, methodGen);
232 if (_type.identicalTo(ltype) == false) {
233 _left.startIterator(classGen, methodGen);
234 ltype.translateTo(classGen, methodGen, _type);
235 }
236 }
237 }