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