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