1/*
2 * Copyright (c) 2017, 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
21package com.sun.org.apache.xalan.internal.xsltc.compiler.util;
22
23import com.sun.org.apache.bcel.internal.generic.BranchHandle;
24import com.sun.org.apache.bcel.internal.generic.CHECKCAST;
25import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
26import com.sun.org.apache.bcel.internal.generic.DLOAD;
27import com.sun.org.apache.bcel.internal.generic.DSTORE;
28import com.sun.org.apache.bcel.internal.generic.GOTO;
29import com.sun.org.apache.bcel.internal.generic.IFEQ;
30import com.sun.org.apache.bcel.internal.generic.IFNE;
31import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
32import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
33import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
34import com.sun.org.apache.bcel.internal.generic.Instruction;
35import com.sun.org.apache.bcel.internal.generic.InstructionConst;
36import com.sun.org.apache.bcel.internal.generic.InstructionList;
37import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
38import com.sun.org.apache.bcel.internal.generic.NEW;
39import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
40import com.sun.org.apache.xalan.internal.xsltc.compiler.FlowList;
41
42/**
43 * @author Jacek Ambroziak
44 * @author Santiago Pericas-Geertsen
45 */
46public final class RealType extends NumberType {
47    protected RealType() {}
48
49    public String toString() {
50        return "real";
51    }
52
53    public boolean identicalTo(Type other) {
54        return this == other;
55    }
56
57    public String toSignature() {
58        return "D";
59    }
60
61    public com.sun.org.apache.bcel.internal.generic.Type toJCType() {
62        return com.sun.org.apache.bcel.internal.generic.Type.DOUBLE;
63    }
64
65    /**
66     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#distanceTo
67     */
68    public int distanceTo(Type type) {
69        if (type == this) {
70            return 0;
71        }
72        else if (type == Type.Int) {
73            return 1;
74        }
75        else {
76            return Integer.MAX_VALUE;
77        }
78    }
79
80    /**
81     * Translates a real into an object of internal type <code>type</code>. The
82     * translation to int is undefined since reals are never converted to ints.
83     *
84     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
85     */
86    public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
87                            Type type) {
88        if (type == Type.String) {
89            translateTo(classGen, methodGen, (StringType) type);
90        }
91        else if (type == Type.Boolean) {
92            translateTo(classGen, methodGen, (BooleanType) type);
93        }
94        else if (type == Type.Reference) {
95            translateTo(classGen, methodGen, (ReferenceType) type);
96        }
97        else if (type == Type.Int) {
98            translateTo(classGen, methodGen, (IntType) type);
99        }
100        else {
101            ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
102                                        toString(), type.toString());
103            classGen.getParser().reportError(Constants.FATAL, err);
104        }
105    }
106
107    /**
108     * Expects a real on the stack and pushes its string value by calling
109     * <code>Double.toString(double d)</code>.
110     *
111     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
112     */
113    public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
114                            StringType type) {
115        final ConstantPoolGen cpg = classGen.getConstantPool();
116        final InstructionList il = methodGen.getInstructionList();
117        il.append(new INVOKESTATIC(cpg.addMethodref(BASIS_LIBRARY_CLASS,
118                                                    "realToString",
119                                                    "(D)" + STRING_SIG)));
120    }
121
122    /**
123     * Expects a real on the stack and pushes a 0 if that number is 0.0 and
124     * a 1 otherwise.
125     *
126     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
127     */
128    public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
129                            BooleanType type) {
130        final InstructionList il = methodGen.getInstructionList();
131        FlowList falsel = translateToDesynthesized(classGen, methodGen, type);
132        il.append(ICONST_1);
133        final BranchHandle truec = il.append(new GOTO(null));
134        falsel.backPatch(il.append(ICONST_0));
135        truec.setTarget(il.append(NOP));
136    }
137
138    /**
139     * Expects a real on the stack and pushes a truncated integer value
140     *
141     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
142     */
143    public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
144                            IntType type) {
145        final ConstantPoolGen cpg = classGen.getConstantPool();
146        final InstructionList il = methodGen.getInstructionList();
147        il.append(new INVOKESTATIC(cpg.addMethodref(BASIS_LIBRARY_CLASS,
148                                                    "realToInt","(D)I")));
149    }
150
151    /**
152     * Translates a real into a non-synthesized boolean. It does not push a
153     * 0 or a 1 but instead returns branchhandle list to be appended to the
154     * false list. A NaN must be converted to "false".
155     *
156     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateToDesynthesized
157     */
158    public FlowList translateToDesynthesized(ClassGenerator classGen,
159                                             MethodGenerator methodGen,
160                                             BooleanType type) {
161        LocalVariableGen local;
162        final FlowList flowlist = new FlowList();
163        final ConstantPoolGen cpg = classGen.getConstantPool();
164        final InstructionList il = methodGen.getInstructionList();
165
166        // Store real into a local variable
167        il.append(DUP2);
168        local = methodGen.addLocalVariable("real_to_boolean_tmp",
169                                           com.sun.org.apache.bcel.internal.generic.Type.DOUBLE,
170                                           null, null);
171        local.setStart(il.append(new DSTORE(local.getIndex())));
172
173        // Compare it to 0.0
174        il.append(DCONST_0);
175        il.append(DCMPG);
176        flowlist.add(il.append(new IFEQ(null)));
177
178        //!!! call isNaN
179        // Compare it to itself to see if NaN
180        il.append(new DLOAD(local.getIndex()));
181        local.setEnd(il.append(new DLOAD(local.getIndex())));
182        il.append(DCMPG);
183        flowlist.add(il.append(new IFNE(null)));        // NaN != NaN
184        return flowlist;
185    }
186
187    /**
188     * Expects a double on the stack and pushes a boxed double. Boxed
189     * double are represented by an instance of <code>java.lang.Double</code>.
190     *
191     * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
192     */
193    public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
194                            ReferenceType type) {
195        final ConstantPoolGen cpg = classGen.getConstantPool();
196        final InstructionList il = methodGen.getInstructionList();
197        il.append(new NEW(cpg.addClass(DOUBLE_CLASS)));
198        il.append(DUP_X2);
199        il.append(DUP_X2);
200        il.append(POP);
201        il.append(new INVOKESPECIAL(cpg.addMethodref(DOUBLE_CLASS,
202                                                     "<init>", "(D)V")));
203    }
204
205    /**
206     * Translates a real into the Java type denoted by <code>clazz</code>.
207     * Expects a real on the stack and pushes a number of the appropriate
208     * type after coercion.
209     */
210    public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
211                            final Class clazz) {
212        final InstructionList il = methodGen.getInstructionList();
213        if (clazz == Character.TYPE) {
214            il.append(D2I);
215            il.append(I2C);
216        }
217        else if (clazz == Byte.TYPE) {
218            il.append(D2I);
219            il.append(I2B);
220        }
221        else if (clazz == Short.TYPE) {
222            il.append(D2I);
223            il.append(I2S);
224        }
225        else if (clazz == Integer.TYPE) {
226            il.append(D2I);
227        }
228        else if (clazz == Long.TYPE) {
229            il.append(D2L);
230        }
231        else if (clazz == Float.TYPE) {
232            il.append(D2F);
233        }
234        else if (clazz == Double.TYPE) {
235            il.append(NOP);
236        }
237        // Is Double <: clazz? I.e. clazz in { Double, Number, Object }
238        else if (clazz.isAssignableFrom(java.lang.Double.class)) {
239            translateTo(classGen, methodGen, Type.Reference);
240        }
241        else {
242            ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
243                                        toString(), clazz.getName());
244            classGen.getParser().reportError(Constants.FATAL, err);
245        }
246    }
247
248    /**
249     * Translates an external (primitive) Java type into a real. Expects a java
250     * object on the stack and pushes a real (i.e., a double).
251     */
252    public void translateFrom(ClassGenerator classGen, MethodGenerator methodGen,
253                              Class clazz) {
254        InstructionList il = methodGen.getInstructionList();
255
256        if (clazz == Character.TYPE || clazz == Byte.TYPE ||
257            clazz == Short.TYPE || clazz == Integer.TYPE) {
258            il.append(I2D);
259        }
260        else if (clazz == Long.TYPE) {
261            il.append(L2D);
262        }
263        else if (clazz == Float.TYPE) {
264            il.append(F2D);
265        }
266        else if (clazz == Double.TYPE) {
267            il.append(NOP);
268        }
269        else {
270            ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
271                                        toString(), clazz.getName());
272            classGen.getParser().reportError(Constants.FATAL, err);
273        }
274    }
275
276    /**
277     * Translates an object of this type to its boxed representation.
278     */
279    public void translateBox(ClassGenerator classGen,
280                             MethodGenerator methodGen) {
281        translateTo(classGen, methodGen, Type.Reference);
282    }
283
284    /**
285     * Translates an object of this type to its unboxed representation.
286     */
287    public void translateUnBox(ClassGenerator classGen,
288                               MethodGenerator methodGen) {
289        final ConstantPoolGen cpg = classGen.getConstantPool();
290        final InstructionList il = methodGen.getInstructionList();
291        il.append(new CHECKCAST(cpg.addClass(DOUBLE_CLASS)));
292        il.append(new INVOKEVIRTUAL(cpg.addMethodref(DOUBLE_CLASS,
293                                                     DOUBLE_VALUE,
294                                                     DOUBLE_VALUE_SIG)));
295    }
296
297    public Instruction ADD() {
298        return InstructionConst.DADD;
299    }
300
301    public Instruction SUB() {
302        return InstructionConst.DSUB;
303    }
304
305    public Instruction MUL() {
306        return InstructionConst.DMUL;
307    }
308
309    public Instruction DIV() {
310        return InstructionConst.DDIV;
311    }
312
313    public Instruction REM() {
314        return InstructionConst.DREM;
315    }
316
317    public Instruction NEG() {
318        return InstructionConst.DNEG;
319    }
320
321    public Instruction LOAD(int slot) {
322        return new DLOAD(slot);
323    }
324
325    public Instruction STORE(int slot) {
326        return new DSTORE(slot);
327    }
328
329    public Instruction POP() {
330        return POP2;
331    }
332
333    public Instruction CMP(boolean less) {
334        return less ? InstructionConst.DCMPG : InstructionConst.DCMPL;
335    }
336
337    public Instruction DUP() {
338        return DUP2;
339    }
340}
341