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