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 }