CastExpr.java revision 628:2bfaf29cc90b
1219019Sgabor/*
2219019Sgabor * reserved comment block
3219019Sgabor * DO NOT REMOVE OR ALTER!
4219019Sgabor */
5219019Sgabor/*
6219019Sgabor * Copyright 2001-2004 The Apache Software Foundation.
7219019Sgabor *
8219019Sgabor * Licensed under the Apache License, Version 2.0 (the "License");
9219019Sgabor * you may not use this file except in compliance with the License.
10219019Sgabor * You may obtain a copy of the License at
11219019Sgabor *
12219019Sgabor *     http://www.apache.org/licenses/LICENSE-2.0
13219019Sgabor *
14219019Sgabor * Unless required by applicable law or agreed to in writing, software
15219019Sgabor * distributed under the License is distributed on an "AS IS" BASIS,
16219019Sgabor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17219019Sgabor * See the License for the specific language governing permissions and
18219019Sgabor * limitations under the License.
19219019Sgabor */
20219019Sgabor/*
21219019Sgabor * $Id: CastExpr.java,v 1.2.4.1 2005/09/12 10:06:35 pvedula Exp $
22219019Sgabor */
23219019Sgabor
24219019Sgaborpackage com.sun.org.apache.xalan.internal.xsltc.compiler;
25219019Sgabor
26219019Sgaborimport com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
27219019Sgaborimport com.sun.org.apache.bcel.internal.generic.IF_ICMPNE;
28219019Sgaborimport com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
29219019Sgaborimport com.sun.org.apache.bcel.internal.generic.InstructionList;
30219019Sgaborimport com.sun.org.apache.bcel.internal.generic.SIPUSH;
31219019Sgaborimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
32219019Sgaborimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
33219019Sgaborimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
34219019Sgaborimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
35219019Sgaborimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.MultiHashtable;
36219019Sgaborimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType;
37219019Sgaborimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.ResultTreeType;
38219019Sgaborimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
39219019Sgaborimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
40219019Sgaborimport com.sun.org.apache.xml.internal.dtm.Axis;
41219019Sgabor
42219019Sgabor/**
43219019Sgabor * @author Jacek Ambroziak
44219019Sgabor * @author Santiago Pericas-Geertsen
45219019Sgabor * @author Morten Jorgensen
46219019Sgabor * @author Erwin Bolwidt <ejb@klomp.org>
47219019Sgabor */
48219019Sgaborfinal class CastExpr extends Expression {
49219019Sgabor    private final Expression _left;
50219019Sgabor
51219019Sgabor    /**
52219019Sgabor     * Legal conversions between internal types.
53219019Sgabor     */
54219019Sgabor    static private MultiHashtable InternalTypeMap = new MultiHashtable();
55219019Sgabor
56219019Sgabor    static {
57219019Sgabor        // Possible type conversions between internal types
58219019Sgabor        InternalTypeMap.put(Type.Boolean, Type.Boolean);
59219019Sgabor        InternalTypeMap.put(Type.Boolean, Type.Real);
60219019Sgabor        InternalTypeMap.put(Type.Boolean, Type.String);
61219019Sgabor        InternalTypeMap.put(Type.Boolean, Type.Reference);
62219019Sgabor        InternalTypeMap.put(Type.Boolean, Type.Object);
63219019Sgabor
64219019Sgabor        InternalTypeMap.put(Type.Real, Type.Real);
65219019Sgabor        InternalTypeMap.put(Type.Real, Type.Int);
66219019Sgabor        InternalTypeMap.put(Type.Real, Type.Boolean);
67219019Sgabor        InternalTypeMap.put(Type.Real, Type.String);
68219019Sgabor        InternalTypeMap.put(Type.Real, Type.Reference);
69219019Sgabor        InternalTypeMap.put(Type.Real, Type.Object);
70219019Sgabor
71219019Sgabor        InternalTypeMap.put(Type.Int, Type.Int);
72219019Sgabor        InternalTypeMap.put(Type.Int, Type.Real);
73219019Sgabor        InternalTypeMap.put(Type.Int, Type.Boolean);
74219019Sgabor        InternalTypeMap.put(Type.Int, Type.String);
75219019Sgabor        InternalTypeMap.put(Type.Int, Type.Reference);
76219019Sgabor        InternalTypeMap.put(Type.Int, Type.Object);
77219019Sgabor
78219019Sgabor        InternalTypeMap.put(Type.String, Type.String);
79219019Sgabor        InternalTypeMap.put(Type.String, Type.Boolean);
80219019Sgabor        InternalTypeMap.put(Type.String, Type.Real);
81219019Sgabor        InternalTypeMap.put(Type.String, Type.Reference);
82219019Sgabor        InternalTypeMap.put(Type.String, Type.Object);
83219019Sgabor
84219019Sgabor        InternalTypeMap.put(Type.NodeSet, Type.NodeSet);
85219019Sgabor        InternalTypeMap.put(Type.NodeSet, Type.Boolean);
86219019Sgabor        InternalTypeMap.put(Type.NodeSet, Type.Real);
87219019Sgabor        InternalTypeMap.put(Type.NodeSet, Type.String);
88219019Sgabor        InternalTypeMap.put(Type.NodeSet, Type.Node);
89219019Sgabor        InternalTypeMap.put(Type.NodeSet, Type.Reference);
90219019Sgabor        InternalTypeMap.put(Type.NodeSet, Type.Object);
91219019Sgabor
92219019Sgabor        InternalTypeMap.put(Type.Node, Type.Node);
93219019Sgabor        InternalTypeMap.put(Type.Node, Type.Boolean);
94219019Sgabor        InternalTypeMap.put(Type.Node, Type.Real);
95219019Sgabor        InternalTypeMap.put(Type.Node, Type.String);
96219019Sgabor        InternalTypeMap.put(Type.Node, Type.NodeSet);
97219019Sgabor        InternalTypeMap.put(Type.Node, Type.Reference);
98219019Sgabor        InternalTypeMap.put(Type.Node, Type.Object);
99219019Sgabor
100219019Sgabor        InternalTypeMap.put(Type.ResultTree, Type.ResultTree);
101219019Sgabor        InternalTypeMap.put(Type.ResultTree, Type.Boolean);
102219019Sgabor        InternalTypeMap.put(Type.ResultTree, Type.Real);
103219019Sgabor        InternalTypeMap.put(Type.ResultTree, Type.String);
104219019Sgabor        InternalTypeMap.put(Type.ResultTree, Type.NodeSet);
105219019Sgabor        InternalTypeMap.put(Type.ResultTree, Type.Reference);
106219019Sgabor        InternalTypeMap.put(Type.ResultTree, Type.Object);
107219019Sgabor
108219019Sgabor        InternalTypeMap.put(Type.Reference, Type.Reference);
109219019Sgabor        InternalTypeMap.put(Type.Reference, Type.Boolean);
110219019Sgabor        InternalTypeMap.put(Type.Reference, Type.Int);
111219019Sgabor        InternalTypeMap.put(Type.Reference, Type.Real);
112219019Sgabor        InternalTypeMap.put(Type.Reference, Type.String);
113219019Sgabor        InternalTypeMap.put(Type.Reference, Type.Node);
114219019Sgabor        InternalTypeMap.put(Type.Reference, Type.NodeSet);
115219019Sgabor        InternalTypeMap.put(Type.Reference, Type.ResultTree);
116219019Sgabor        InternalTypeMap.put(Type.Reference, Type.Object);
117219019Sgabor
118219019Sgabor        InternalTypeMap.put(Type.Object, Type.String);
119219019Sgabor
120219019Sgabor        InternalTypeMap.put(Type.Void, Type.String);
121219019Sgabor    }
122263986Stijl
123219019Sgabor    private boolean _typeTest = false;
124219019Sgabor
125219019Sgabor    /**
126219019Sgabor     * Construct a cast expression and check that the conversion is
127219019Sgabor     * valid by calling typeCheck().
128219019Sgabor     */
129219019Sgabor    public CastExpr(Expression left, Type type) throws TypeCheckError {
130219019Sgabor        _left = left;
131219019Sgabor        _type = type;           // use inherited field
132219019Sgabor
133219019Sgabor        if ((_left instanceof Step) && (_type == Type.Boolean)) {
134219019Sgabor            Step step = (Step)_left;
135219019Sgabor            if ((step.getAxis() == Axis.SELF) && (step.getNodeType() != -1))
136219019Sgabor                _typeTest = true;
137219019Sgabor        }
138219019Sgabor
139260003Sdim        // check if conversion is valid
140219019Sgabor        setParser(left.getParser());
141219019Sgabor        setParent(left.getParent());
142219019Sgabor        left.setParent(this);
143219019Sgabor        typeCheck(left.getParser().getSymbolTable());
144219019Sgabor    }
145219019Sgabor
146219019Sgabor    public Expression getExpr() {
147219019Sgabor        return _left;
148219019Sgabor    }
149219019Sgabor
150219019Sgabor    /**
151219019Sgabor     * Returns true if this expressions contains a call to position(). This is
152219019Sgabor     * needed for context changes in node steps containing multiple predicates.
153219019Sgabor     */
154219019Sgabor    public boolean hasPositionCall() {
155219019Sgabor        return(_left.hasPositionCall());
156219019Sgabor    }
157260003Sdim
158219019Sgabor    public boolean hasLastCall() {
159219019Sgabor        return(_left.hasLastCall());
160219019Sgabor    }
161219019Sgabor
162219019Sgabor    public String toString() {
163219019Sgabor        return "cast(" + _left + ", " + _type + ")";
164219019Sgabor    }
165219019Sgabor
166219019Sgabor    /**
167219019Sgabor     * Type checking a cast expression amounts to verifying that the
168219019Sgabor     * type conversion is legal. Cast expressions are created during
169219019Sgabor     * type checking, but typeCheck() is usually not called on them.
170219019Sgabor     * As a result, this method is called from the constructor.
171219019Sgabor     */
172219019Sgabor    public Type typeCheck(SymbolTable stable) throws TypeCheckError {
173219019Sgabor        Type tleft = _left.getType();
174219019Sgabor        if (tleft == null) {
175219019Sgabor            tleft = _left.typeCheck(stable);
176219019Sgabor        }
177219019Sgabor        if (tleft instanceof NodeType) {
178219019Sgabor            tleft = Type.Node;  // multiple instances
179281550Stijl        }
180219019Sgabor        else if (tleft instanceof ResultTreeType) {
181219019Sgabor            tleft = Type.ResultTree; // multiple instances
182281550Stijl        }
183219019Sgabor        if (InternalTypeMap.maps(tleft, _type) != null) {
184219019Sgabor            return _type;
185219019Sgabor        }
186219019Sgabor        // throw new TypeCheckError(this);
187219019Sgabor        throw new TypeCheckError(new ErrorMsg(
188219019Sgabor            ErrorMsg.DATA_CONVERSION_ERR, tleft.toString(), _type.toString()));
189219019Sgabor    }
190219019Sgabor
191219019Sgabor    public void translateDesynthesized(ClassGenerator classGen,
192219019Sgabor                                       MethodGenerator methodGen) {
193219019Sgabor        FlowList fl;
194219019Sgabor        final Type ltype = _left.getType();
195219019Sgabor
196219019Sgabor        // This is a special case for the self:: axis. Instead of letting
197219019Sgabor        // the Step object create and iterator that we cast back to a single
198219019Sgabor        // node, we simply ask the DOM for the node type.
199219019Sgabor        if (_typeTest) {
200219019Sgabor            final ConstantPoolGen cpg = classGen.getConstantPool();
201219019Sgabor            final InstructionList il = methodGen.getInstructionList();
202219019Sgabor
203219019Sgabor            final int idx = cpg.addInterfaceMethodref(DOM_INTF,
204219019Sgabor                                                      "getExpandedTypeID",
205219019Sgabor                                                      "(I)I");
206219019Sgabor            il.append(new SIPUSH((short)((Step)_left).getNodeType()));
207219019Sgabor            il.append(methodGen.loadDOM());
208219019Sgabor            il.append(methodGen.loadContextNode());
209219019Sgabor            il.append(new INVOKEINTERFACE(idx, 2));
210219019Sgabor            _falseList.add(il.append(new IF_ICMPNE(null)));
211219019Sgabor        }
212219019Sgabor        else {
213219019Sgabor
214219019Sgabor            _left.translate(classGen, methodGen);
215219019Sgabor            if (_type != ltype) {
216219019Sgabor                _left.startIterator(classGen, methodGen);
217219019Sgabor                if (_type instanceof BooleanType) {
218219019Sgabor                    fl = ltype.translateToDesynthesized(classGen, methodGen,
219219019Sgabor                                                        _type);
220219019Sgabor                    if (fl != null) {
221219019Sgabor                        _falseList.append(fl);
222219019Sgabor                    }
223219019Sgabor                }
224219019Sgabor                else {
225219019Sgabor                    ltype.translateTo(classGen, methodGen, _type);
226219019Sgabor                }
227219019Sgabor            }
228219019Sgabor        }
229219019Sgabor    }
230219019Sgabor
231219019Sgabor    public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
232219019Sgabor        final Type ltype = _left.getType();
233219019Sgabor        _left.translate(classGen, methodGen);
234219019Sgabor        if (_type.identicalTo(ltype) == false) {
235219019Sgabor            _left.startIterator(classGen, methodGen);
236219019Sgabor            ltype.translateTo(classGen, methodGen, _type);
237219019Sgabor        }
238219019Sgabor    }
239219019Sgabor}
240219019Sgabor