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: DecimalFormatting.java,v 1.14 2004/02/24 03:55:47 zongaro Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.compiler;
  20. import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  21. import com.sun.org.apache.bcel.internal.generic.GETSTATIC;
  22. import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  23. import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  24. import com.sun.org.apache.bcel.internal.generic.InstructionList;
  25. import com.sun.org.apache.bcel.internal.generic.NEW;
  26. import com.sun.org.apache.bcel.internal.generic.PUSH;
  27. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  28. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  29. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  30. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  31. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  32. import com.sun.org.apache.xml.internal.utils.XMLChar;
  33. /**
  34. * @author Jacek Ambroziak
  35. * @author Santiago Pericas-Geertsen
  36. * @author Morten Jorgensen
  37. */
  38. final class DecimalFormatting extends TopLevelElement {
  39. private static final String DFS_CLASS = "java.text.DecimalFormatSymbols";
  40. private static final String DFS_SIG = "Ljava/text/DecimalFormatSymbols;";
  41. private QName _name = null;
  42. /**
  43. * No type check needed for the <xsl:decimal-formatting/> element
  44. */
  45. public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  46. return Type.Void;
  47. }
  48. /**
  49. * Parse the name of the <xsl:decimal-formatting/> element
  50. */
  51. public void parseContents(Parser parser) {
  52. // Get the name of these decimal formatting symbols
  53. final String name = getAttribute("name");
  54. if (name.length() > 0) {
  55. if (!XMLChar.isValidQName(name)){
  56. ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this);
  57. parser.reportError(Constants.ERROR, err);
  58. }
  59. }
  60. _name = parser.getQNameIgnoreDefaultNs(name);
  61. if (_name == null) {
  62. _name = parser.getQNameIgnoreDefaultNs(EMPTYSTRING);
  63. }
  64. // Check if a set of symbols has already been registered under this name
  65. SymbolTable stable = parser.getSymbolTable();
  66. if (stable.getDecimalFormatting(_name) != null) {
  67. reportWarning(this, parser, ErrorMsg.SYMBOLS_REDEF_ERR,
  68. _name.toString());
  69. }
  70. else {
  71. stable.addDecimalFormatting(_name, this);
  72. }
  73. }
  74. /**
  75. * This method is called when the constructor is compiled in
  76. * Stylesheet.compileConstructor() and not as the syntax tree is traversed.
  77. */
  78. public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  79. ConstantPoolGen cpg = classGen.getConstantPool();
  80. InstructionList il = methodGen.getInstructionList();
  81. // DecimalFormatSymbols.<init>(Locale);
  82. // xsl:decimal-format - except for the NaN and infinity attributes.
  83. final int init = cpg.addMethodref(DFS_CLASS, "<init>",
  84. "("+LOCALE_SIG+")V");
  85. // Push the format name on the stack for call to addDecimalFormat()
  86. il.append(classGen.loadTranslet());
  87. il.append(new PUSH(cpg, _name.toString()));
  88. // Manufacture a DecimalFormatSymbols on the stack
  89. // for call to addDecimalFormat()
  90. // Use the US Locale as the default, as most of its settings
  91. // are equivalent to the default settings required of
  92. il.append(new NEW(cpg.addClass(DFS_CLASS)));
  93. il.append(DUP);
  94. il.append(new GETSTATIC(cpg.addFieldref(LOCALE_CLASS, "US",
  95. LOCALE_SIG)));
  96. il.append(new INVOKESPECIAL(init));
  97. String tmp = getAttribute("NaN");
  98. if ((tmp == null) || (tmp.equals(EMPTYSTRING))) {
  99. int nan = cpg.addMethodref(DFS_CLASS,
  100. "setNaN", "(Ljava/lang/String;)V");
  101. il.append(DUP);
  102. il.append(new PUSH(cpg, "NaN"));
  103. il.append(new INVOKEVIRTUAL(nan));
  104. }
  105. tmp = getAttribute("infinity");
  106. if ((tmp == null) || (tmp.equals(EMPTYSTRING))) {
  107. int inf = cpg.addMethodref(DFS_CLASS,
  108. "setInfinity",
  109. "(Ljava/lang/String;)V");
  110. il.append(DUP);
  111. il.append(new PUSH(cpg, "Infinity"));
  112. il.append(new INVOKEVIRTUAL(inf));
  113. }
  114. final int nAttributes = _attributes.getLength();
  115. for (int i = 0; i < nAttributes; i++) {
  116. final String name = _attributes.getQName(i);
  117. final String value = _attributes.getValue(i);
  118. boolean valid = true;
  119. int method = 0;
  120. if (name.equals("decimal-separator")) {
  121. // DecimalFormatSymbols.setDecimalSeparator();
  122. method = cpg.addMethodref(DFS_CLASS,
  123. "setDecimalSeparator", "(C)V");
  124. }
  125. else if (name.equals("grouping-separator")) {
  126. method = cpg.addMethodref(DFS_CLASS,
  127. "setGroupingSeparator", "(C)V");
  128. }
  129. else if (name.equals("minus-sign")) {
  130. method = cpg.addMethodref(DFS_CLASS,
  131. "setMinusSign", "(C)V");
  132. }
  133. else if (name.equals("percent")) {
  134. method = cpg.addMethodref(DFS_CLASS,
  135. "setPercent", "(C)V");
  136. }
  137. else if (name.equals("per-mille")) {
  138. method = cpg.addMethodref(DFS_CLASS,
  139. "setPerMill", "(C)V");
  140. }
  141. else if (name.equals("zero-digit")) {
  142. method = cpg.addMethodref(DFS_CLASS,
  143. "setZeroDigit", "(C)V");
  144. }
  145. else if (name.equals("digit")) {
  146. method = cpg.addMethodref(DFS_CLASS,
  147. "setDigit", "(C)V");
  148. }
  149. else if (name.equals("pattern-separator")) {
  150. method = cpg.addMethodref(DFS_CLASS,
  151. "setPatternSeparator", "(C)V");
  152. }
  153. else if (name.equals("NaN")) {
  154. method = cpg.addMethodref(DFS_CLASS,
  155. "setNaN", "(Ljava/lang/String;)V");
  156. il.append(DUP);
  157. il.append(new PUSH(cpg, value));
  158. il.append(new INVOKEVIRTUAL(method));
  159. valid = false;
  160. }
  161. else if (name.equals("infinity")) {
  162. method = cpg.addMethodref(DFS_CLASS,
  163. "setInfinity",
  164. "(Ljava/lang/String;)V");
  165. il.append(DUP);
  166. il.append(new PUSH(cpg, value));
  167. il.append(new INVOKEVIRTUAL(method));
  168. valid = false;
  169. }
  170. else {
  171. valid = false;
  172. }
  173. if (valid) {
  174. il.append(DUP);
  175. il.append(new PUSH(cpg, value.charAt(0)));
  176. il.append(new INVOKEVIRTUAL(method));
  177. }
  178. }
  179. final int put = cpg.addMethodref(TRANSLET_CLASS,
  180. "addDecimalFormat",
  181. "("+STRING_SIG+DFS_SIG+")V");
  182. il.append(new INVOKEVIRTUAL(put));
  183. }
  184. /**
  185. * Creates the default, nameless, DecimalFormat object in
  186. * AbstractTranslet's format_symbols hashtable.
  187. * This should be called for every stylesheet, and the entry
  188. * may be overridden by later nameless xsl:decimal-format instructions.
  189. */
  190. public static void translateDefaultDFS(ClassGenerator classGen,
  191. MethodGenerator methodGen) {
  192. ConstantPoolGen cpg = classGen.getConstantPool();
  193. InstructionList il = methodGen.getInstructionList();
  194. final int init = cpg.addMethodref(DFS_CLASS, "<init>",
  195. "("+LOCALE_SIG+")V");
  196. // Push the format name, which is empty, on the stack
  197. // for call to addDecimalFormat()
  198. il.append(classGen.loadTranslet());
  199. il.append(new PUSH(cpg, EMPTYSTRING));
  200. // Manufacture a DecimalFormatSymbols on the stack for
  201. // call to addDecimalFormat(). Use the US Locale as the
  202. // default, as most of its settings are equivalent to
  203. // the default settings required of xsl:decimal-format -
  204. // except for the NaN and infinity attributes.
  205. il.append(new NEW(cpg.addClass(DFS_CLASS)));
  206. il.append(DUP);
  207. il.append(new GETSTATIC(cpg.addFieldref(LOCALE_CLASS, "US",
  208. LOCALE_SIG)));
  209. il.append(new INVOKESPECIAL(init));
  210. int nan = cpg.addMethodref(DFS_CLASS,
  211. "setNaN", "(Ljava/lang/String;)V");
  212. il.append(DUP);
  213. il.append(new PUSH(cpg, "NaN"));
  214. il.append(new INVOKEVIRTUAL(nan));
  215. int inf = cpg.addMethodref(DFS_CLASS,
  216. "setInfinity",
  217. "(Ljava/lang/String;)V");
  218. il.append(DUP);
  219. il.append(new PUSH(cpg, "Infinity"));
  220. il.append(new INVOKEVIRTUAL(inf));
  221. final int put = cpg.addMethodref(TRANSLET_CLASS,
  222. "addDecimalFormat",
  223. "("+STRING_SIG+DFS_SIG+")V");
  224. il.append(new INVOKEVIRTUAL(put));
  225. }
  226. }