View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * 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      static private MultiHashtable InternalTypeMap = new MultiHashtable();
55  
56      static {
57          // Possible type conversions between internal types
58          InternalTypeMap.put(Type.Boolean, Type.Boolean);
59          InternalTypeMap.put(Type.Boolean, Type.Real);
60          InternalTypeMap.put(Type.Boolean, Type.String);
61          InternalTypeMap.put(Type.Boolean, Type.Reference);
62          InternalTypeMap.put(Type.Boolean, Type.Object);
63  
64          InternalTypeMap.put(Type.Real, Type.Real);
65          InternalTypeMap.put(Type.Real, Type.Int);
66          InternalTypeMap.put(Type.Real, Type.Boolean);
67          InternalTypeMap.put(Type.Real, Type.String);
68          InternalTypeMap.put(Type.Real, Type.Reference);
69          InternalTypeMap.put(Type.Real, Type.Object);
70  
71          InternalTypeMap.put(Type.Int, Type.Int);
72          InternalTypeMap.put(Type.Int, Type.Real);
73          InternalTypeMap.put(Type.Int, Type.Boolean);
74          InternalTypeMap.put(Type.Int, Type.String);
75          InternalTypeMap.put(Type.Int, Type.Reference);
76          InternalTypeMap.put(Type.Int, Type.Object);
77  
78          InternalTypeMap.put(Type.String, Type.String);
79          InternalTypeMap.put(Type.String, Type.Boolean);
80          InternalTypeMap.put(Type.String, Type.Real);
81          InternalTypeMap.put(Type.String, Type.Reference);
82          InternalTypeMap.put(Type.String, Type.Object);
83  
84          InternalTypeMap.put(Type.NodeSet, Type.NodeSet);
85          InternalTypeMap.put(Type.NodeSet, Type.Boolean);
86          InternalTypeMap.put(Type.NodeSet, Type.Real);
87          InternalTypeMap.put(Type.NodeSet, Type.String);
88          InternalTypeMap.put(Type.NodeSet, Type.Node);
89          InternalTypeMap.put(Type.NodeSet, Type.Reference);
90          InternalTypeMap.put(Type.NodeSet, Type.Object);
91  
92          InternalTypeMap.put(Type.Node, Type.Node);
93          InternalTypeMap.put(Type.Node, Type.Boolean);
94          InternalTypeMap.put(Type.Node, Type.Real);
95          InternalTypeMap.put(Type.Node, Type.String);
96          InternalTypeMap.put(Type.Node, Type.NodeSet);
97          InternalTypeMap.put(Type.Node, Type.Reference);
98          InternalTypeMap.put(Type.Node, Type.Object);
99  
100         InternalTypeMap.put(Type.ResultTree, Type.ResultTree);
101         InternalTypeMap.put(Type.ResultTree, Type.Boolean);
102         InternalTypeMap.put(Type.ResultTree, Type.Real);
103         InternalTypeMap.put(Type.ResultTree, Type.String);
104         InternalTypeMap.put(Type.ResultTree, Type.NodeSet);
105         InternalTypeMap.put(Type.ResultTree, Type.Reference);
106         InternalTypeMap.put(Type.ResultTree, Type.Object);
107 
108         InternalTypeMap.put(Type.Reference, Type.Reference);
109         InternalTypeMap.put(Type.Reference, Type.Boolean);
110         InternalTypeMap.put(Type.Reference, Type.Int);
111         InternalTypeMap.put(Type.Reference, Type.Real);
112         InternalTypeMap.put(Type.Reference, Type.String);
113         InternalTypeMap.put(Type.Reference, Type.Node);
114         InternalTypeMap.put(Type.Reference, Type.NodeSet);
115         InternalTypeMap.put(Type.Reference, Type.ResultTree);
116         InternalTypeMap.put(Type.Reference, Type.Object);
117 
118         InternalTypeMap.put(Type.Object, Type.String);
119 
120         InternalTypeMap.put(Type.Void, Type.String);
121     }
122 
123     private boolean _typeTest = false;
124 
125     /**
126      * Construct a cast expression and check that the conversion is
127      * valid by calling typeCheck().
128      */
129     public CastExpr(Expression left, Type type) throws TypeCheckError {
130         _left = left;
131         _type = type;           // use inherited field
132 
133         if ((_left instanceof Step) && (_type == Type.Boolean)) {
134             Step step = (Step)_left;
135             if ((step.getAxis() == Axis.SELF) && (step.getNodeType() != -1))
136                 _typeTest = true;
137         }
138 
139         // check if conversion is valid
140         setParser(left.getParser());
141         setParent(left.getParent());
142         left.setParent(this);
143         typeCheck(left.getParser().getSymbolTable());
144     }
145 
146     public Expression getExpr() {
147         return _left;
148     }
149 
150     /**
151      * Returns true if this expressions contains a call to position(). This is
152      * needed for context changes in node steps containing multiple predicates.
153      */
154     public boolean hasPositionCall() {
155         return(_left.hasPositionCall());
156     }
157 
158     public boolean hasLastCall() {
159         return(_left.hasLastCall());
160     }
161 
162     public String toString() {
163         return "cast(" + _left + ", " + _type + ")";
164     }
165 
166     /**
167      * Type checking a cast expression amounts to verifying that the
168      * type conversion is legal. Cast expressions are created during
169      * type checking, but typeCheck() is usually not called on them.
170      * As a result, this method is called from the constructor.
171      */
172     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
173         Type tleft = _left.getType();
174         if (tleft == null) {
175             tleft = _left.typeCheck(stable);
176         }
177         if (tleft instanceof NodeType) {
178             tleft = Type.Node;  // multiple instances
179         }
180         else if (tleft instanceof ResultTreeType) {
181             tleft = Type.ResultTree; // multiple instances
182         }
183         if (InternalTypeMap.maps(tleft, _type) != null) {
184             return _type;
185         }
186         // throw new TypeCheckError(this);
187         throw new TypeCheckError(new ErrorMsg(
188             ErrorMsg.DATA_CONVERSION_ERR, tleft.toString(), _type.toString()));
189     }
190 
191     public void translateDesynthesized(ClassGenerator classGen,
192                                        MethodGenerator methodGen) {
193         FlowList fl;
194         final Type ltype = _left.getType();
195 
196         // This is a special case for the self:: axis. Instead of letting
197         // the Step object create and iterator that we cast back to a single
198         // node, we simply ask the DOM for the node type.
199         if (_typeTest) {
200             final ConstantPoolGen cpg = classGen.getConstantPool();
201             final InstructionList il = methodGen.getInstructionList();
202 
203             final int idx = cpg.addInterfaceMethodref(DOM_INTF,
204                                                       "getExpandedTypeID",
205                                                       "(I)I");
206             il.append(new SIPUSH((short)((Step)_left).getNodeType()));
207             il.append(methodGen.loadDOM());
208             il.append(methodGen.loadContextNode());
209             il.append(new INVOKEINTERFACE(idx, 2));
210             _falseList.add(il.append(new IF_ICMPNE(null)));
211         }
212         else {
213 
214             _left.translate(classGen, methodGen);
215             if (_type != ltype) {
216                 _left.startIterator(classGen, methodGen);
217                 if (_type instanceof BooleanType) {
218                     fl = ltype.translateToDesynthesized(classGen, methodGen,
219                                                         _type);
220                     if (fl != null) {
221                         _falseList.append(fl);
222                     }
223                 }
224                 else {
225                     ltype.translateTo(classGen, methodGen, _type);
226                 }
227             }
228         }
229     }
230 
231     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
232         final Type ltype = _left.getType();
233         _left.translate(classGen, methodGen);
234         if (_type.identicalTo(ltype) == false) {
235             _left.startIterator(classGen, methodGen);
236             ltype.translateTo(classGen, methodGen, _type);
237         }
238     }
239 }