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 }