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: DecimalFormatting.java 468650 2006-10-28 07:03:30Z minchau $
020 */
021
022 package org.apache.xalan.xsltc.compiler;
023
024 import org.apache.bcel.generic.ConstantPoolGen;
025 import org.apache.bcel.generic.GETSTATIC;
026 import org.apache.bcel.generic.INVOKESPECIAL;
027 import org.apache.bcel.generic.INVOKEVIRTUAL;
028 import org.apache.bcel.generic.InstructionList;
029 import org.apache.bcel.generic.NEW;
030 import org.apache.bcel.generic.PUSH;
031 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
032 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
033 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
034 import org.apache.xalan.xsltc.compiler.util.Type;
035 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
036 import org.apache.xml.utils.XML11Char;
037
038 /**
039 * @author Jacek Ambroziak
040 * @author Santiago Pericas-Geertsen
041 * @author Morten Jorgensen
042 */
043 final class DecimalFormatting extends TopLevelElement {
044
045 private static final String DFS_CLASS = "java.text.DecimalFormatSymbols";
046 private static final String DFS_SIG = "Ljava/text/DecimalFormatSymbols;";
047
048 private QName _name = null;
049
050 /**
051 * No type check needed for the <xsl:decimal-formatting/> element
052 */
053 public Type typeCheck(SymbolTable stable) throws TypeCheckError {
054 return Type.Void;
055 }
056
057 /**
058 * Parse the name of the <xsl:decimal-formatting/> element
059 */
060 public void parseContents(Parser parser) {
061 // Get the name of these decimal formatting symbols
062 final String name = getAttribute("name");
063 if (name.length() > 0) {
064 if (!XML11Char.isXML11ValidQName(name)){
065 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this);
066 parser.reportError(Constants.ERROR, err);
067 }
068 }
069 _name = parser.getQNameIgnoreDefaultNs(name);
070 if (_name == null) {
071 _name = parser.getQNameIgnoreDefaultNs(EMPTYSTRING);
072 }
073
074 // Check if a set of symbols has already been registered under this name
075 SymbolTable stable = parser.getSymbolTable();
076 if (stable.getDecimalFormatting(_name) != null) {
077 reportWarning(this, parser, ErrorMsg.SYMBOLS_REDEF_ERR,
078 _name.toString());
079 }
080 else {
081 stable.addDecimalFormatting(_name, this);
082 }
083 }
084
085 /**
086 * This method is called when the constructor is compiled in
087 * Stylesheet.compileConstructor() and not as the syntax tree is traversed.
088 */
089 public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
090
091 ConstantPoolGen cpg = classGen.getConstantPool();
092 InstructionList il = methodGen.getInstructionList();
093
094 // DecimalFormatSymbols.<init>(Locale);
095 // xsl:decimal-format - except for the NaN and infinity attributes.
096 final int init = cpg.addMethodref(DFS_CLASS, "<init>",
097 "("+LOCALE_SIG+")V");
098
099 // Push the format name on the stack for call to addDecimalFormat()
100 il.append(classGen.loadTranslet());
101 il.append(new PUSH(cpg, _name.toString()));
102
103 // Manufacture a DecimalFormatSymbols on the stack
104 // for call to addDecimalFormat()
105 // Use the US Locale as the default, as most of its settings
106 // are equivalent to the default settings required of
107 il.append(new NEW(cpg.addClass(DFS_CLASS)));
108 il.append(DUP);
109 il.append(new GETSTATIC(cpg.addFieldref(LOCALE_CLASS, "US",
110 LOCALE_SIG)));
111 il.append(new INVOKESPECIAL(init));
112
113 String tmp = getAttribute("NaN");
114 if ((tmp == null) || (tmp.equals(EMPTYSTRING))) {
115 int nan = cpg.addMethodref(DFS_CLASS,
116 "setNaN", "(Ljava/lang/String;)V");
117 il.append(DUP);
118 il.append(new PUSH(cpg, "NaN"));
119 il.append(new INVOKEVIRTUAL(nan));
120 }
121
122 tmp = getAttribute("infinity");
123 if ((tmp == null) || (tmp.equals(EMPTYSTRING))) {
124 int inf = cpg.addMethodref(DFS_CLASS,
125 "setInfinity",
126 "(Ljava/lang/String;)V");
127 il.append(DUP);
128 il.append(new PUSH(cpg, "Infinity"));
129 il.append(new INVOKEVIRTUAL(inf));
130 }
131
132 final int nAttributes = _attributes.getLength();
133 for (int i = 0; i < nAttributes; i++) {
134 final String name = _attributes.getQName(i);
135 final String value = _attributes.getValue(i);
136
137 boolean valid = true;
138 int method = 0;
139
140 if (name.equals("decimal-separator")) {
141 // DecimalFormatSymbols.setDecimalSeparator();
142 method = cpg.addMethodref(DFS_CLASS,
143 "setDecimalSeparator", "(C)V");
144 }
145 else if (name.equals("grouping-separator")) {
146 method = cpg.addMethodref(DFS_CLASS,
147 "setGroupingSeparator", "(C)V");
148 }
149 else if (name.equals("minus-sign")) {
150 method = cpg.addMethodref(DFS_CLASS,
151 "setMinusSign", "(C)V");
152 }
153 else if (name.equals("percent")) {
154 method = cpg.addMethodref(DFS_CLASS,
155 "setPercent", "(C)V");
156 }
157 else if (name.equals("per-mille")) {
158 method = cpg.addMethodref(DFS_CLASS,
159 "setPerMill", "(C)V");
160 }
161 else if (name.equals("zero-digit")) {
162 method = cpg.addMethodref(DFS_CLASS,
163 "setZeroDigit", "(C)V");
164 }
165 else if (name.equals("digit")) {
166 method = cpg.addMethodref(DFS_CLASS,
167 "setDigit", "(C)V");
168 }
169 else if (name.equals("pattern-separator")) {
170 method = cpg.addMethodref(DFS_CLASS,
171 "setPatternSeparator", "(C)V");
172 }
173 else if (name.equals("NaN")) {
174 method = cpg.addMethodref(DFS_CLASS,
175 "setNaN", "(Ljava/lang/String;)V");
176 il.append(DUP);
177 il.append(new PUSH(cpg, value));
178 il.append(new INVOKEVIRTUAL(method));
179 valid = false;
180 }
181 else if (name.equals("infinity")) {
182 method = cpg.addMethodref(DFS_CLASS,
183 "setInfinity",
184 "(Ljava/lang/String;)V");
185 il.append(DUP);
186 il.append(new PUSH(cpg, value));
187 il.append(new INVOKEVIRTUAL(method));
188 valid = false;
189 }
190 else {
191 valid = false;
192 }
193
194 if (valid) {
195 il.append(DUP);
196 il.append(new PUSH(cpg, value.charAt(0)));
197 il.append(new INVOKEVIRTUAL(method));
198 }
199
200 }
201
202 final int put = cpg.addMethodref(TRANSLET_CLASS,
203 "addDecimalFormat",
204 "("+STRING_SIG+DFS_SIG+")V");
205 il.append(new INVOKEVIRTUAL(put));
206 }
207
208 /**
209 * Creates the default, nameless, DecimalFormat object in
210 * AbstractTranslet's format_symbols hashtable.
211 * This should be called for every stylesheet, and the entry
212 * may be overridden by later nameless xsl:decimal-format instructions.
213 */
214 public static void translateDefaultDFS(ClassGenerator classGen,
215 MethodGenerator methodGen) {
216
217 ConstantPoolGen cpg = classGen.getConstantPool();
218 InstructionList il = methodGen.getInstructionList();
219 final int init = cpg.addMethodref(DFS_CLASS, "<init>",
220 "("+LOCALE_SIG+")V");
221
222 // Push the format name, which is empty, on the stack
223 // for call to addDecimalFormat()
224 il.append(classGen.loadTranslet());
225 il.append(new PUSH(cpg, EMPTYSTRING));
226
227 // Manufacture a DecimalFormatSymbols on the stack for
228 // call to addDecimalFormat(). Use the US Locale as the
229 // default, as most of its settings are equivalent to
230 // the default settings required of xsl:decimal-format -
231 // except for the NaN and infinity attributes.
232 il.append(new NEW(cpg.addClass(DFS_CLASS)));
233 il.append(DUP);
234 il.append(new GETSTATIC(cpg.addFieldref(LOCALE_CLASS, "US",
235 LOCALE_SIG)));
236 il.append(new INVOKESPECIAL(init));
237
238 int nan = cpg.addMethodref(DFS_CLASS,
239 "setNaN", "(Ljava/lang/String;)V");
240 il.append(DUP);
241 il.append(new PUSH(cpg, "NaN"));
242 il.append(new INVOKEVIRTUAL(nan));
243
244 int inf = cpg.addMethodref(DFS_CLASS,
245 "setInfinity",
246 "(Ljava/lang/String;)V");
247 il.append(DUP);
248 il.append(new PUSH(cpg, "Infinity"));
249 il.append(new INVOKEVIRTUAL(inf));
250
251 final int put = cpg.addMethodref(TRANSLET_CLASS,
252 "addDecimalFormat",
253 "("+STRING_SIG+DFS_SIG+")V");
254 il.append(new INVOKEVIRTUAL(put));
255 }
256 }