1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Licensed to the Apache Software Foundation (ASF) under one or more 6 * contributor license agreements. See the NOTICE file distributed with 7 * this work for additional information regarding copyright ownership. 8 * The ASF licenses this file to You under the Apache License, Version 2.0 9 * (the "License"); you may not use this file except in compliance with 10 * the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 /* 21 * $Id: CastExpr.java,v 1.2.4.1 2005/09/12 10:06:35 pvedula Exp $ 22 */ 23 24 package com.sun.org.apache.xalan.internal.xsltc.compiler; 25 26 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 27 import com.sun.org.apache.bcel.internal.generic.IF_ICMPNE; 28 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; 29 import com.sun.org.apache.bcel.internal.generic.InstructionList; 30 import com.sun.org.apache.bcel.internal.generic.SIPUSH; 31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType; 32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; 33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; 34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; 35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MultiHashtable; 36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType; 37 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ResultTreeType; 38 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; 39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; 40 import com.sun.org.apache.xml.internal.dtm.Axis; 41 42 /** 43 * @author Jacek Ambroziak 44 * @author Santiago Pericas-Geertsen 45 * @author Morten Jorgensen 46 * @author Erwin Bolwidt <ejb@klomp.org> 47 */ 48 final class CastExpr extends Expression { 49 private final Expression _left; 50 51 /** 52 * Legal conversions between internal types. 53 */ 54 private static final MultiHashtable<Type, Type> InternalTypeMap = new MultiHashtable<>(); 55 56 static { 57 // Possible type conversions between internal types InternalTypeMap.put(Type.Boolean, Type.Boolean)58 InternalTypeMap.put(Type.Boolean, Type.Boolean); InternalTypeMap.put(Type.Boolean, Type.Real)59 InternalTypeMap.put(Type.Boolean, Type.Real); InternalTypeMap.put(Type.Boolean, Type.String)60 InternalTypeMap.put(Type.Boolean, Type.String); InternalTypeMap.put(Type.Boolean, Type.Reference)61 InternalTypeMap.put(Type.Boolean, Type.Reference); InternalTypeMap.put(Type.Boolean, Type.Object)62 InternalTypeMap.put(Type.Boolean, Type.Object); 63 InternalTypeMap.put(Type.Real, Type.Real)64 InternalTypeMap.put(Type.Real, Type.Real); InternalTypeMap.put(Type.Real, Type.Int)65 InternalTypeMap.put(Type.Real, Type.Int); InternalTypeMap.put(Type.Real, Type.Boolean)66 InternalTypeMap.put(Type.Real, Type.Boolean); InternalTypeMap.put(Type.Real, Type.String)67 InternalTypeMap.put(Type.Real, Type.String); InternalTypeMap.put(Type.Real, Type.Reference)68 InternalTypeMap.put(Type.Real, Type.Reference); InternalTypeMap.put(Type.Real, Type.Object)69 InternalTypeMap.put(Type.Real, Type.Object); 70 InternalTypeMap.put(Type.Int, Type.Int)71 InternalTypeMap.put(Type.Int, Type.Int); InternalTypeMap.put(Type.Int, Type.Real)72 InternalTypeMap.put(Type.Int, Type.Real); InternalTypeMap.put(Type.Int, Type.Boolean)73 InternalTypeMap.put(Type.Int, Type.Boolean); InternalTypeMap.put(Type.Int, Type.String)74 InternalTypeMap.put(Type.Int, Type.String); InternalTypeMap.put(Type.Int, Type.Reference)75 InternalTypeMap.put(Type.Int, Type.Reference); InternalTypeMap.put(Type.Int, Type.Object)76 InternalTypeMap.put(Type.Int, Type.Object); 77 InternalTypeMap.put(Type.String, Type.String)78 InternalTypeMap.put(Type.String, Type.String); InternalTypeMap.put(Type.String, Type.Boolean)79 InternalTypeMap.put(Type.String, Type.Boolean); InternalTypeMap.put(Type.String, Type.Real)80 InternalTypeMap.put(Type.String, Type.Real); InternalTypeMap.put(Type.String, Type.Reference)81 InternalTypeMap.put(Type.String, Type.Reference); InternalTypeMap.put(Type.String, Type.Object)82 InternalTypeMap.put(Type.String, Type.Object); 83 InternalTypeMap.put(Type.NodeSet, Type.NodeSet)84 InternalTypeMap.put(Type.NodeSet, Type.NodeSet); InternalTypeMap.put(Type.NodeSet, Type.Boolean)85 InternalTypeMap.put(Type.NodeSet, Type.Boolean); InternalTypeMap.put(Type.NodeSet, Type.Real)86 InternalTypeMap.put(Type.NodeSet, Type.Real); InternalTypeMap.put(Type.NodeSet, Type.String)87 InternalTypeMap.put(Type.NodeSet, Type.String); InternalTypeMap.put(Type.NodeSet, Type.Node)88 InternalTypeMap.put(Type.NodeSet, Type.Node); InternalTypeMap.put(Type.NodeSet, Type.Reference)89 InternalTypeMap.put(Type.NodeSet, Type.Reference); InternalTypeMap.put(Type.NodeSet, Type.Object)90 InternalTypeMap.put(Type.NodeSet, Type.Object); 91 InternalTypeMap.put(Type.Node, Type.Node)92 InternalTypeMap.put(Type.Node, Type.Node); InternalTypeMap.put(Type.Node, Type.Boolean)93 InternalTypeMap.put(Type.Node, Type.Boolean); InternalTypeMap.put(Type.Node, Type.Real)94 InternalTypeMap.put(Type.Node, Type.Real); InternalTypeMap.put(Type.Node, Type.String)95 InternalTypeMap.put(Type.Node, Type.String); InternalTypeMap.put(Type.Node, Type.NodeSet)96 InternalTypeMap.put(Type.Node, Type.NodeSet); InternalTypeMap.put(Type.Node, Type.Reference)97 InternalTypeMap.put(Type.Node, Type.Reference); InternalTypeMap.put(Type.Node, Type.Object)98 InternalTypeMap.put(Type.Node, Type.Object); 99 InternalTypeMap.put(Type.ResultTree, Type.ResultTree)100 InternalTypeMap.put(Type.ResultTree, Type.ResultTree); InternalTypeMap.put(Type.ResultTree, Type.Boolean)101 InternalTypeMap.put(Type.ResultTree, Type.Boolean); InternalTypeMap.put(Type.ResultTree, Type.Real)102 InternalTypeMap.put(Type.ResultTree, Type.Real); InternalTypeMap.put(Type.ResultTree, Type.String)103 InternalTypeMap.put(Type.ResultTree, Type.String); InternalTypeMap.put(Type.ResultTree, Type.NodeSet)104 InternalTypeMap.put(Type.ResultTree, Type.NodeSet); InternalTypeMap.put(Type.ResultTree, Type.Reference)105 InternalTypeMap.put(Type.ResultTree, Type.Reference); InternalTypeMap.put(Type.ResultTree, Type.Object)106 InternalTypeMap.put(Type.ResultTree, Type.Object); 107 InternalTypeMap.put(Type.Reference, Type.Reference)108 InternalTypeMap.put(Type.Reference, Type.Reference); InternalTypeMap.put(Type.Reference, Type.Boolean)109 InternalTypeMap.put(Type.Reference, Type.Boolean); InternalTypeMap.put(Type.Reference, Type.Int)110 InternalTypeMap.put(Type.Reference, Type.Int); InternalTypeMap.put(Type.Reference, Type.Real)111 InternalTypeMap.put(Type.Reference, Type.Real); InternalTypeMap.put(Type.Reference, Type.String)112 InternalTypeMap.put(Type.Reference, Type.String); InternalTypeMap.put(Type.Reference, Type.Node)113 InternalTypeMap.put(Type.Reference, Type.Node); InternalTypeMap.put(Type.Reference, Type.NodeSet)114 InternalTypeMap.put(Type.Reference, Type.NodeSet); InternalTypeMap.put(Type.Reference, Type.ResultTree)115 InternalTypeMap.put(Type.Reference, Type.ResultTree); InternalTypeMap.put(Type.Reference, Type.Object)116 InternalTypeMap.put(Type.Reference, Type.Object); 117 InternalTypeMap.put(Type.Object, Type.String)118 InternalTypeMap.put(Type.Object, Type.String); 119 InternalTypeMap.put(Type.Void, Type.String)120 InternalTypeMap.put(Type.Void, Type.String); 121 InternalTypeMap.makeUnmodifiable()122 InternalTypeMap.makeUnmodifiable(); 123 } 124 125 private boolean _typeTest = false; 126 127 /** 128 * Construct a cast expression and check that the conversion is 129 * valid by calling typeCheck(). 130 */ CastExpr(Expression left, Type type)131 public CastExpr(Expression left, Type type) throws TypeCheckError { 132 _left = left; 133 _type = type; // use inherited field 134 135 if ((_left instanceof Step) && (_type == Type.Boolean)) { 136 Step step = (Step)_left; 137 if ((step.getAxis() == Axis.SELF) && (step.getNodeType() != -1)) 138 _typeTest = true; 139 } 140 141 // check if conversion is valid 142 setParser(left.getParser()); 143 setParent(left.getParent()); 144 left.setParent(this); 145 typeCheck(left.getParser().getSymbolTable()); 146 } 147 getExpr()148 public Expression getExpr() { 149 return _left; 150 } 151 152 /** 153 * Returns true if this expressions contains a call to position(). This is 154 * needed for context changes in node steps containing multiple predicates. 155 */ hasPositionCall()156 public boolean hasPositionCall() { 157 return(_left.hasPositionCall()); 158 } 159 hasLastCall()160 public boolean hasLastCall() { 161 return(_left.hasLastCall()); 162 } 163 toString()164 public String toString() { 165 return "cast(" + _left + ", " + _type + ")"; 166 } 167 168 /** 169 * Type checking a cast expression amounts to verifying that the 170 * type conversion is legal. Cast expressions are created during 171 * type checking, but typeCheck() is usually not called on them. 172 * As a result, this method is called from the constructor. 173 */ typeCheck(SymbolTable stable)174 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 175 Type tleft = _left.getType(); 176 if (tleft == null) { 177 tleft = _left.typeCheck(stable); 178 } 179 if (tleft instanceof NodeType) { 180 tleft = Type.Node; // multiple instances 181 } 182 else if (tleft instanceof ResultTreeType) { 183 tleft = Type.ResultTree; // multiple instances 184 } 185 if (InternalTypeMap.maps(tleft, _type) != null) { 186 return _type; 187 } 188 // throw new TypeCheckError(this); 189 throw new TypeCheckError(new ErrorMsg( 190 ErrorMsg.DATA_CONVERSION_ERR, tleft.toString(), _type.toString())); 191 } 192 translateDesynthesized(ClassGenerator classGen, MethodGenerator methodGen)193 public void translateDesynthesized(ClassGenerator classGen, 194 MethodGenerator methodGen) { 195 FlowList fl; 196 final Type ltype = _left.getType(); 197 198 // This is a special case for the self:: axis. Instead of letting 199 // the Step object create and iterator that we cast back to a single 200 // node, we simply ask the DOM for the node type. 201 if (_typeTest) { 202 final ConstantPoolGen cpg = classGen.getConstantPool(); 203 final InstructionList il = methodGen.getInstructionList(); 204 205 final int idx = cpg.addInterfaceMethodref(DOM_INTF, 206 "getExpandedTypeID", 207 "(I)I"); 208 il.append(new SIPUSH((short)((Step)_left).getNodeType())); 209 il.append(methodGen.loadDOM()); 210 il.append(methodGen.loadContextNode()); 211 il.append(new INVOKEINTERFACE(idx, 2)); 212 _falseList.add(il.append(new IF_ICMPNE(null))); 213 } 214 else { 215 216 _left.translate(classGen, methodGen); 217 if (_type != ltype) { 218 _left.startIterator(classGen, methodGen); 219 if (_type instanceof BooleanType) { 220 fl = ltype.translateToDesynthesized(classGen, methodGen, 221 _type); 222 if (fl != null) { 223 _falseList.append(fl); 224 } 225 } 226 else { 227 ltype.translateTo(classGen, methodGen, _type); 228 } 229 } 230 } 231 } 232 translate(ClassGenerator classGen, MethodGenerator methodGen)233 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 234 final Type ltype = _left.getType(); 235 _left.translate(classGen, methodGen); 236 if (_type.identicalTo(ltype) == false) { 237 _left.startIterator(classGen, methodGen); 238 ltype.translateTo(classGen, methodGen, _type); 239 } 240 } 241 } 242