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