001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: RealType.java 468649 2006-10-28 07:00:55Z minchau $
020     */
021    
022    package org.apache.xalan.xsltc.compiler.util;
023    
024    import org.apache.bcel.generic.BranchHandle;
025    import org.apache.bcel.generic.CHECKCAST;
026    import org.apache.bcel.generic.ConstantPoolGen;
027    import org.apache.bcel.generic.DLOAD;
028    import org.apache.bcel.generic.DSTORE;
029    import org.apache.bcel.generic.GOTO;
030    import org.apache.bcel.generic.IFEQ;
031    import org.apache.bcel.generic.IFNE;
032    import org.apache.bcel.generic.INVOKESPECIAL;
033    import org.apache.bcel.generic.INVOKESTATIC;
034    import org.apache.bcel.generic.INVOKEVIRTUAL;
035    import org.apache.bcel.generic.Instruction;
036    import org.apache.bcel.generic.InstructionConstants;
037    import org.apache.bcel.generic.InstructionList;
038    import org.apache.bcel.generic.LocalVariableGen;
039    import org.apache.bcel.generic.NEW;
040    import org.apache.xalan.xsltc.compiler.Constants;
041    import org.apache.xalan.xsltc.compiler.FlowList;
042    
043    /**
044     * @author Jacek Ambroziak
045     * @author Santiago Pericas-Geertsen
046     */
047    public final class RealType extends NumberType {
048        protected RealType() {}
049    
050        public String toString() {
051            return "real";
052        }
053    
054        public boolean identicalTo(Type other) {
055            return this == other;
056        }
057    
058        public String toSignature() {
059            return "D";
060        }
061    
062        public org.apache.bcel.generic.Type toJCType() {
063            return org.apache.bcel.generic.Type.DOUBLE;
064        }
065    
066        /**
067         * @see     org.apache.xalan.xsltc.compiler.util.Type#distanceTo
068         */
069        public int distanceTo(Type type) {
070            if (type == this) {
071                return 0;
072            }
073            else if (type == Type.Int) {
074                return 1;
075            }
076            else {
077                return Integer.MAX_VALUE;
078            }
079        }
080    
081        /**
082         * Translates a real into an object of internal type <code>type</code>. The
083         * translation to int is undefined since reals are never converted to ints.
084         *
085         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
086         */
087        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 
088                                Type type) {
089            if (type == Type.String) {
090                translateTo(classGen, methodGen, (StringType) type);
091            }
092            else if (type == Type.Boolean) {
093                translateTo(classGen, methodGen, (BooleanType) type);
094            }
095            else if (type == Type.Reference) {
096                translateTo(classGen, methodGen, (ReferenceType) type);
097            }
098            else if (type == Type.Int) {
099                translateTo(classGen, methodGen, (IntType) type);
100            }
101            else {
102                ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
103                                            toString(), type.toString());
104                classGen.getParser().reportError(Constants.FATAL, err);
105            }
106        }
107    
108        /**
109         * Expects a real on the stack and pushes its string value by calling
110         * <code>Double.toString(double d)</code>.
111         *
112         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
113         */
114        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 
115                                StringType type) {
116            final ConstantPoolGen cpg = classGen.getConstantPool();
117            final InstructionList il = methodGen.getInstructionList();
118            il.append(new INVOKESTATIC(cpg.addMethodref(BASIS_LIBRARY_CLASS,
119                                                        "realToString",
120                                                        "(D)" + STRING_SIG)));
121        }
122    
123        /**
124         * Expects a real on the stack and pushes a 0 if that number is 0.0 and
125         * a 1 otherwise.
126         *
127         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
128         */
129        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 
130                                BooleanType type) {
131            final InstructionList il = methodGen.getInstructionList();
132            FlowList falsel = translateToDesynthesized(classGen, methodGen, type);
133            il.append(ICONST_1);
134            final BranchHandle truec = il.append(new GOTO(null));
135            falsel.backPatch(il.append(ICONST_0));
136            truec.setTarget(il.append(NOP));
137        }
138    
139        /**
140         * Expects a real on the stack and pushes a truncated integer value
141         *
142         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
143         */
144        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 
145                                IntType type) {
146            final ConstantPoolGen cpg = classGen.getConstantPool();
147            final InstructionList il = methodGen.getInstructionList();
148            il.append(new INVOKESTATIC(cpg.addMethodref(BASIS_LIBRARY_CLASS,
149                                                        "realToInt","(D)I")));
150        }
151    
152        /**
153         * Translates a real into a non-synthesized boolean. It does not push a 
154         * 0 or a 1 but instead returns branchhandle list to be appended to the 
155         * false list. A NaN must be converted to "false".
156         *
157         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateToDesynthesized
158         */
159        public FlowList translateToDesynthesized(ClassGenerator classGen, 
160                                                 MethodGenerator methodGen, 
161                                                 BooleanType type) {
162            LocalVariableGen local;
163            final FlowList flowlist = new FlowList();
164            final ConstantPoolGen cpg = classGen.getConstantPool();
165            final InstructionList il = methodGen.getInstructionList();
166    
167            // Store real into a local variable
168            il.append(DUP2);
169            local = methodGen.addLocalVariable("real_to_boolean_tmp", 
170                                               org.apache.bcel.generic.Type.DOUBLE,
171                                               null, null);
172            local.setStart(il.append(new DSTORE(local.getIndex())));
173    
174            // Compare it to 0.0
175            il.append(DCONST_0);
176            il.append(DCMPG);
177            flowlist.add(il.append(new IFEQ(null)));
178    
179            //!!! call isNaN
180            // Compare it to itself to see if NaN
181            il.append(new DLOAD(local.getIndex()));
182            local.setEnd(il.append(new DLOAD(local.getIndex())));
183            il.append(DCMPG);
184            flowlist.add(il.append(new IFNE(null)));        // NaN != NaN
185            return flowlist;
186        }
187    
188        /**
189         * Expects a double on the stack and pushes a boxed double. Boxed 
190         * double are represented by an instance of <code>java.lang.Double</code>.
191         *
192         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
193         */
194        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 
195                                ReferenceType type) {
196            final ConstantPoolGen cpg = classGen.getConstantPool();
197            final InstructionList il = methodGen.getInstructionList();
198            il.append(new NEW(cpg.addClass(DOUBLE_CLASS)));
199            il.append(DUP_X2);
200            il.append(DUP_X2);
201            il.append(POP);
202            il.append(new INVOKESPECIAL(cpg.addMethodref(DOUBLE_CLASS,
203                                                         "<init>", "(D)V")));
204        }
205    
206        /**
207         * Translates a real into the Java type denoted by <code>clazz</code>. 
208         * Expects a real on the stack and pushes a number of the appropriate
209         * type after coercion.
210         */
211        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 
212                                final Class clazz) {
213            final InstructionList il = methodGen.getInstructionList();
214            if (clazz == Character.TYPE) {
215                il.append(D2I);
216                il.append(I2C);
217            }
218            else if (clazz == Byte.TYPE) {
219                il.append(D2I);
220                il.append(I2B);
221            }
222            else if (clazz == Short.TYPE) {
223                il.append(D2I);
224                il.append(I2S);
225            }
226            else if (clazz == Integer.TYPE) {
227                il.append(D2I);
228            }
229            else if (clazz == Long.TYPE) {
230                il.append(D2L);
231            }
232            else if (clazz == Float.TYPE) {
233                il.append(D2F);
234            }
235            else if (clazz == Double.TYPE) {
236                il.append(NOP);
237            }
238            // Is Double <: clazz? I.e. clazz in { Double, Number, Object }
239            else if (clazz.isAssignableFrom(java.lang.Double.class)) {
240                translateTo(classGen, methodGen, Type.Reference);
241            }
242            else {
243                ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
244                                            toString(), clazz.getName());
245                classGen.getParser().reportError(Constants.FATAL, err);
246            }
247        }
248    
249        /**
250         * Translates an external (primitive) Java type into a real. Expects a java 
251         * object on the stack and pushes a real (i.e., a double).
252         */
253        public void translateFrom(ClassGenerator classGen, MethodGenerator methodGen, 
254                                  Class clazz) {
255            InstructionList il = methodGen.getInstructionList();
256    
257            if (clazz == Character.TYPE || clazz == Byte.TYPE ||
258                clazz == Short.TYPE || clazz == Integer.TYPE) {
259                il.append(I2D);
260            }
261            else if (clazz == Long.TYPE) {
262                il.append(L2D);
263            }
264            else if (clazz == Float.TYPE) {
265                il.append(F2D);
266            }
267            else if (clazz == Double.TYPE) {
268                il.append(NOP);
269            }
270            else {
271                ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
272                                            toString(), clazz.getName());
273                classGen.getParser().reportError(Constants.FATAL, err);
274            }
275        }
276    
277        /**
278         * Translates an object of this type to its boxed representation.
279         */ 
280        public void translateBox(ClassGenerator classGen,
281                                 MethodGenerator methodGen) {
282            translateTo(classGen, methodGen, Type.Reference);
283        }
284    
285        /**
286         * Translates an object of this type to its unboxed representation.
287         */ 
288        public void translateUnBox(ClassGenerator classGen,
289                                   MethodGenerator methodGen) {
290            final ConstantPoolGen cpg = classGen.getConstantPool();
291            final InstructionList il = methodGen.getInstructionList();
292            il.append(new CHECKCAST(cpg.addClass(DOUBLE_CLASS)));
293            il.append(new INVOKEVIRTUAL(cpg.addMethodref(DOUBLE_CLASS,
294                                                         DOUBLE_VALUE, 
295                                                         DOUBLE_VALUE_SIG)));
296        }
297    
298        public Instruction ADD() {
299            return InstructionConstants.DADD;
300        }
301    
302        public Instruction SUB() {
303            return InstructionConstants.DSUB;
304        }
305    
306        public Instruction MUL() {
307            return InstructionConstants.DMUL;
308        }
309    
310        public Instruction DIV() {
311            return InstructionConstants.DDIV;
312        }
313    
314        public Instruction REM() {
315            return InstructionConstants.DREM;
316        }
317    
318        public Instruction NEG() {
319            return InstructionConstants.DNEG;
320        }
321    
322        public Instruction LOAD(int slot) {
323            return new DLOAD(slot);
324        }
325            
326        public Instruction STORE(int slot) {
327            return new DSTORE(slot);
328        }
329    
330        public Instruction POP() {
331            return POP2;
332        }
333        
334        public Instruction CMP(boolean less) {
335            return less ? InstructionConstants.DCMPG : InstructionConstants.DCMPL;
336        }
337    
338        public Instruction DUP() {
339            return DUP2;
340        }
341    }
342