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