- /*
- * Copyright 2001-2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /*
- * $Id: Number.java,v 1.14 2004/02/24 02:58:42 zongaro Exp $
- */
-
- package com.sun.org.apache.xalan.internal.xsltc.compiler;
-
- import java.util.ArrayList;
-
- import com.sun.org.apache.bcel.internal.classfile.Field;
- import com.sun.org.apache.bcel.internal.generic.ALOAD;
- import com.sun.org.apache.bcel.internal.generic.ASTORE;
- import com.sun.org.apache.bcel.internal.generic.BranchHandle;
- import com.sun.org.apache.bcel.internal.generic.CHECKCAST;
- import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
- import com.sun.org.apache.bcel.internal.generic.GETFIELD;
- import com.sun.org.apache.bcel.internal.generic.GOTO;
- import com.sun.org.apache.bcel.internal.generic.IFNONNULL;
- import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
- import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
- import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
- import com.sun.org.apache.bcel.internal.generic.InstructionList;
- import com.sun.org.apache.bcel.internal.generic.L2I;
- import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
- import com.sun.org.apache.bcel.internal.generic.NEW;
- import com.sun.org.apache.bcel.internal.generic.PUSH;
- import com.sun.org.apache.bcel.internal.generic.PUTFIELD;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MatchGenerator;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeCounterGenerator;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.RealType;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
-
- /**
- * @author Jacek Ambroziak
- * @author Santiago Pericas-Geertsen
- */
- final class Number extends Instruction implements Closure {
- private static final int LEVEL_SINGLE = 0;
- private static final int LEVEL_MULTIPLE = 1;
- private static final int LEVEL_ANY = 2;
-
- static final private String[] ClassNames = {
- "com.sun.org.apache.xalan.internal.xsltc.dom.SingleNodeCounter", // LEVEL_SINGLE
- "com.sun.org.apache.xalan.internal.xsltc.dom.MultipleNodeCounter", // LEVEL_MULTIPLE
- "com.sun.org.apache.xalan.internal.xsltc.dom.AnyNodeCounter" // LEVEL_ANY
- };
-
- static final private String[] FieldNames = {
- "___single_node_counter", // LEVEL_SINGLE
- "___multiple_node_counter", // LEVEL_MULTIPLE
- "___any_node_counter" // LEVEL_ANY
- };
-
- private Pattern _from = null;
- private Pattern _count = null;
- private Expression _value = null;
-
- private AttributeValueTemplate _lang = null;
- private AttributeValueTemplate _format = null;
- private AttributeValueTemplate _letterValue = null;
- private AttributeValueTemplate _groupingSeparator = null;
- private AttributeValueTemplate _groupingSize = null;
-
- private int _level = LEVEL_SINGLE;
- private boolean _formatNeeded = false;
-
- private String _className = null;
- private ArrayList _closureVars = null;
-
- // -- Begin Closure interface --------------------
-
- /**
- * Returns true if this closure is compiled in an inner class (i.e.
- * if this is a real closure).
- */
- public boolean inInnerClass() {
- return (_className != null);
- }
-
- /**
- * Returns a reference to its parent closure or null if outermost.
- */
- public Closure getParentClosure() {
- return null;
- }
-
- /**
- * Returns the name of the auxiliary class or null if this predicate
- * is compiled inside the Translet.
- */
- public String getInnerClassName() {
- return _className;
- }
-
- /**
- * Add new variable to the closure.
- */
- public void addVariable(VariableRefBase variableRef) {
- if (_closureVars == null) {
- _closureVars = new ArrayList();
- }
-
- // Only one reference per variable
- if (!_closureVars.contains(variableRef)) {
- _closureVars.add(variableRef);
- }
- }
-
- // -- End Closure interface ----------------------
-
- public void parseContents(Parser parser) {
- final int count = _attributes.getLength();
-
- for (int i = 0; i < count; i++) {
- final String name = _attributes.getQName(i);
- final String value = _attributes.getValue(i);
-
- if (name.equals("value")) {
- _value = parser.parseExpression(this, name, null);
- }
- else if (name.equals("count")) {
- _count = parser.parsePattern(this, name, null);
- }
- else if (name.equals("from")) {
- _from = parser.parsePattern(this, name, null);
- }
- else if (name.equals("level")) {
- if (value.equals("single")) {
- _level = LEVEL_SINGLE;
- }
- else if (value.equals("multiple")) {
- _level = LEVEL_MULTIPLE;
- }
- else if (value.equals("any")) {
- _level = LEVEL_ANY;
- }
- }
- else if (name.equals("format")) {
- _format = new AttributeValueTemplate(value, parser, this);
- _formatNeeded = true;
- }
- else if (name.equals("lang")) {
- _lang = new AttributeValueTemplate(value, parser, this);
- _formatNeeded = true;
- }
- else if (name.equals("letter-value")) {
- _letterValue = new AttributeValueTemplate(value, parser, this);
- _formatNeeded = true;
- }
- else if (name.equals("grouping-separator")) {
- _groupingSeparator = new AttributeValueTemplate(value, parser, this);
- _formatNeeded = true;
- }
- else if (name.equals("grouping-size")) {
- _groupingSize = new AttributeValueTemplate(value, parser, this);
- _formatNeeded = true;
- }
- }
- }
-
- public Type typeCheck(SymbolTable stable) throws TypeCheckError {
- if (_value != null) {
- Type tvalue = _value.typeCheck(stable);
- if (tvalue instanceof RealType == false) {
- _value = new CastExpr(_value, Type.Real);
- }
- }
- if (_count != null) {
- _count.typeCheck(stable);
- }
- if (_from != null) {
- _from.typeCheck(stable);
- }
- if (_format != null) {
- _format.typeCheck(stable);
- }
- if (_lang != null) {
- _lang.typeCheck(stable);
- }
- if (_letterValue != null) {
- _letterValue.typeCheck(stable);
- }
- if (_groupingSeparator != null) {
- _groupingSeparator.typeCheck(stable);
- }
- if (_groupingSize != null) {
- _groupingSize.typeCheck(stable);
- }
- return Type.Void;
- }
-
- /**
- * True if the has specified a value for this instance of number.
- */
- public boolean hasValue() {
- return _value != null;
- }
-
- /**
- * Returns <tt>true</tt> if this instance of number has neither
- * a from nor a count pattern.
- */
- public boolean isDefault() {
- return _from == null && _count == null;
- }
-
- private void compileDefault(ClassGenerator classGen,
- MethodGenerator methodGen) {
- int index;
- ConstantPoolGen cpg = classGen.getConstantPool();
- InstructionList il = methodGen.getInstructionList();
-
- int[] fieldIndexes = getXSLTC().getNumberFieldIndexes();
-
- if (fieldIndexes[_level] == -1) {
- Field defaultNode = new Field(ACC_PRIVATE,
- cpg.addUtf8(FieldNames[_level]),
- cpg.addUtf8(NODE_COUNTER_SIG),
- null,
- cpg.getConstantPool());
-
- // Add a new private field to this class
- classGen.addField(defaultNode);
-
- // Get a reference to the newly added field
- fieldIndexes[_level] = cpg.addFieldref(classGen.getClassName(),
- FieldNames[_level],
- NODE_COUNTER_SIG);
- }
-
- // Check if field is initialized (runtime)
- il.append(classGen.loadTranslet());
- il.append(new GETFIELD(fieldIndexes[_level]));
- final BranchHandle ifBlock1 = il.append(new IFNONNULL(null));
-
- // Create an instance of DefaultNodeCounter
- index = cpg.addMethodref(ClassNames[_level],
- "getDefaultNodeCounter",
- "(" + TRANSLET_INTF_SIG
- + DOM_INTF_SIG
- + NODE_ITERATOR_SIG
- + ")" + NODE_COUNTER_SIG);
- il.append(classGen.loadTranslet());
- il.append(methodGen.loadDOM());
- il.append(methodGen.loadIterator());
- il.append(new INVOKESTATIC(index));
- il.append(DUP);
-
- // Store the node counter in the field
- il.append(classGen.loadTranslet());
- il.append(SWAP);
- il.append(new PUTFIELD(fieldIndexes[_level]));
- final BranchHandle ifBlock2 = il.append(new GOTO(null));
-
- // Backpatch conditionals
- ifBlock1.setTarget(il.append(classGen.loadTranslet()));
- il.append(new GETFIELD(fieldIndexes[_level]));
-
- ifBlock2.setTarget(il.append(NOP));
- }
-
- /**
- * Compiles a constructor for the class <tt>_className</tt> that
- * inherits from {Any,Single,Multiple}NodeCounter. This constructor
- * simply calls the same constructor in the super class.
- */
- private void compileConstructor(ClassGenerator classGen) {
- MethodGenerator cons;
- final InstructionList il = new InstructionList();
- final ConstantPoolGen cpg = classGen.getConstantPool();
-
- cons = new MethodGenerator(ACC_PUBLIC,
- com.sun.org.apache.bcel.internal.generic.Type.VOID,
- new com.sun.org.apache.bcel.internal.generic.Type[] {
- Util.getJCRefType(TRANSLET_INTF_SIG),
- Util.getJCRefType(DOM_INTF_SIG),
- Util.getJCRefType(NODE_ITERATOR_SIG)
- },
- new String[] {
- "dom",
- "translet",
- "iterator"
- },
- "<init>", _className, il, cpg);
-
- il.append(ALOAD_0); // this
- il.append(ALOAD_1); // translet
- il.append(ALOAD_2); // DOM
- il.append(new ALOAD(3));// iterator
-
- int index = cpg.addMethodref(ClassNames[_level],
- "<init>",
- "(" + TRANSLET_INTF_SIG
- + DOM_INTF_SIG
- + NODE_ITERATOR_SIG
- + ")V");
- il.append(new INVOKESPECIAL(index));
- il.append(RETURN);
-
- cons.stripAttributes(true);
- cons.setMaxLocals();
- cons.setMaxStack();
- classGen.addMethod(cons.getMethod());
- }
-
- /**
- * This method compiles code that is common to matchesFrom() and
- * matchesCount() in the auxillary class.
- */
- private void compileLocals(NodeCounterGenerator nodeCounterGen,
- MatchGenerator matchGen,
- InstructionList il)
- {
- int field;
- LocalVariableGen local;
- ConstantPoolGen cpg = nodeCounterGen.getConstantPool();
-
- // Get NodeCounter._iterator and store locally
- local = matchGen.addLocalVariable("iterator",
- Util.getJCRefType(NODE_ITERATOR_SIG),
- null, null);
- field = cpg.addFieldref(NODE_COUNTER, "_iterator",
- ITERATOR_FIELD_SIG);
- il.append(ALOAD_0); // 'this' pointer on stack
- il.append(new GETFIELD(field));
- il.append(new ASTORE(local.getIndex()));
- matchGen.setIteratorIndex(local.getIndex());
-
- // Get NodeCounter._translet and store locally
- local = matchGen.addLocalVariable("translet",
- Util.getJCRefType(TRANSLET_SIG),
- null, null);
- field = cpg.addFieldref(NODE_COUNTER, "_translet",
- "Lcom/sun/org/apache/xalan/internal/xsltc/Translet;");
- il.append(ALOAD_0); // 'this' pointer on stack
- il.append(new GETFIELD(field));
- il.append(new CHECKCAST(cpg.addClass(TRANSLET_CLASS)));
- il.append(new ASTORE(local.getIndex()));
- nodeCounterGen.setTransletIndex(local.getIndex());
-
- // Get NodeCounter._document and store locally
- local = matchGen.addLocalVariable("document",
- Util.getJCRefType(DOM_INTF_SIG),
- null, null);
- field = cpg.addFieldref(_className, "_document", DOM_INTF_SIG);
- il.append(ALOAD_0); // 'this' pointer on stack
- il.append(new GETFIELD(field));
- // Make sure we have the correct DOM type on the stack!!!
- il.append(new ASTORE(local.getIndex()));
- matchGen.setDomIndex(local.getIndex());
- }
-
- private void compilePatterns(ClassGenerator classGen,
- MethodGenerator methodGen)
- {
- int current;
- int field;
- LocalVariableGen local;
- MatchGenerator matchGen;
- NodeCounterGenerator nodeCounterGen;
-
- _className = getXSLTC().getHelperClassName();
- nodeCounterGen = new NodeCounterGenerator(_className,
- ClassNames[_level],
- toString(),
- ACC_PUBLIC | ACC_SUPER,
- null,
- classGen.getStylesheet());
- InstructionList il = null;
- ConstantPoolGen cpg = nodeCounterGen.getConstantPool();
-
- // Add a new instance variable for each var in closure
- final int closureLen = (_closureVars == null) ? 0 :
- _closureVars.size();
-
- for (int i = 0; i < closureLen; i++) {
- VariableBase var =
- ((VariableRefBase) _closureVars.get(i)).getVariable();
-
- nodeCounterGen.addField(new Field(ACC_PUBLIC,
- cpg.addUtf8(var.getEscapedName()),
- cpg.addUtf8(var.getType().toSignature()),
- null, cpg.getConstantPool()));
- }
-
- // Add a single constructor to the class
- compileConstructor(nodeCounterGen);
-
- /*
- * Compile method matchesFrom()
- */
- if (_from != null) {
- il = new InstructionList();
- matchGen =
- new MatchGenerator(ACC_PUBLIC | ACC_FINAL,
- com.sun.org.apache.bcel.internal.generic.Type.BOOLEAN,
- new com.sun.org.apache.bcel.internal.generic.Type[] {
- com.sun.org.apache.bcel.internal.generic.Type.INT,
- },
- new String[] {
- "node",
- },
- "matchesFrom", _className, il, cpg);
-
- compileLocals(nodeCounterGen,matchGen,il);
-
- // Translate Pattern
- il.append(matchGen.loadContextNode());
- _from.translate(nodeCounterGen, matchGen);
- _from.synthesize(nodeCounterGen, matchGen);
- il.append(IRETURN);
-
- matchGen.stripAttributes(true);
- matchGen.setMaxLocals();
- matchGen.setMaxStack();
- matchGen.removeNOPs();
- nodeCounterGen.addMethod(matchGen.getMethod());
- }
-
- /*
- * Compile method matchesCount()
- */
- if (_count != null) {
- il = new InstructionList();
- matchGen = new MatchGenerator(ACC_PUBLIC | ACC_FINAL,
- com.sun.org.apache.bcel.internal.generic.Type.BOOLEAN,
- new com.sun.org.apache.bcel.internal.generic.Type[] {
- com.sun.org.apache.bcel.internal.generic.Type.INT,
- },
- new String[] {
- "node",
- },
- "matchesCount", _className, il, cpg);
-
- compileLocals(nodeCounterGen,matchGen,il);
-
- // Translate Pattern
- il.append(matchGen.loadContextNode());
- _count.translate(nodeCounterGen, matchGen);
- _count.synthesize(nodeCounterGen, matchGen);
-
- il.append(IRETURN);
-
- matchGen.stripAttributes(true);
- matchGen.setMaxLocals();
- matchGen.setMaxStack();
- matchGen.removeNOPs();
- nodeCounterGen.addMethod(matchGen.getMethod());
- }
-
- getXSLTC().dumpClass(nodeCounterGen.getJavaClass());
-
- // Push an instance of the newly created class
- cpg = classGen.getConstantPool();
- il = methodGen.getInstructionList();
-
- final int index = cpg.addMethodref(_className, "<init>",
- "(" + TRANSLET_INTF_SIG
- + DOM_INTF_SIG
- + NODE_ITERATOR_SIG
- + ")V");
- il.append(new NEW(cpg.addClass(_className)));
- il.append(DUP);
- il.append(classGen.loadTranslet());
- il.append(methodGen.loadDOM());
- il.append(methodGen.loadIterator());
- il.append(new INVOKESPECIAL(index));
-
- // Initialize closure variables
- for (int i = 0; i < closureLen; i++) {
- final VariableRefBase varRef = (VariableRefBase) _closureVars.get(i);
- final VariableBase var = varRef.getVariable();
- final Type varType = var.getType();
-
- // Store variable in new closure
- il.append(DUP);
- il.append(var.loadInstruction());
- il.append(new PUTFIELD(
- cpg.addFieldref(_className, var.getEscapedName(),
- varType.toSignature())));
- }
- }
-
- public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
- int index;
- final ConstantPoolGen cpg = classGen.getConstantPool();
- final InstructionList il = methodGen.getInstructionList();
-
- // Push "this" for the call to characters()
- il.append(classGen.loadTranslet());
-
- if (hasValue()) {
- compileDefault(classGen, methodGen);
- _value.translate(classGen, methodGen);
-
- // Round the number to the nearest integer
- index = cpg.addMethodref(MATH_CLASS, "round", "(D)J");
- il.append(new INVOKESTATIC(index));
- il.append(new L2I());
-
- // Call setValue on the node counter
- index = cpg.addMethodref(NODE_COUNTER,
- "setValue",
- "(I)" + NODE_COUNTER_SIG);
- il.append(new INVOKEVIRTUAL(index));
- }
- else if (isDefault()) {
- compileDefault(classGen, methodGen);
- }
- else {
- compilePatterns(classGen, methodGen);
- }
-
- // Call setStartNode()
- if (!hasValue()) {
- il.append(methodGen.loadContextNode());
- index = cpg.addMethodref(NODE_COUNTER,
- SET_START_NODE,
- "(I)" + NODE_COUNTER_SIG);
- il.append(new INVOKEVIRTUAL(index));
- }
-
- // Call getCounter() with or without args
- if (_formatNeeded) {
- if (_format != null) {
- _format.translate(classGen, methodGen);
- }
- else {
- il.append(new PUSH(cpg, "1"));
- }
-
- if (_lang != null) {
- _lang.translate(classGen, methodGen);
- }
- else {
- il.append(new PUSH(cpg, "en")); // TODO ??
- }
-
- if (_letterValue != null) {
- _letterValue.translate(classGen, methodGen);
- }
- else {
- il.append(new PUSH(cpg, Constants.EMPTYSTRING));
- }
-
- if (_groupingSeparator != null) {
- _groupingSeparator.translate(classGen, methodGen);
- }
- else {
- il.append(new PUSH(cpg, Constants.EMPTYSTRING));
- }
-
- if (_groupingSize != null) {
- _groupingSize.translate(classGen, methodGen);
- }
- else {
- il.append(new PUSH(cpg, "0"));
- }
-
- index = cpg.addMethodref(NODE_COUNTER, "getCounter",
- "(" + STRING_SIG + STRING_SIG
- + STRING_SIG + STRING_SIG
- + STRING_SIG + ")" + STRING_SIG);
- il.append(new INVOKEVIRTUAL(index));
- }
- else {
- index = cpg.addMethodref(NODE_COUNTER, "setDefaultFormatting",
- "()" + NODE_COUNTER_SIG);
- il.append(new INVOKEVIRTUAL(index));
-
- index = cpg.addMethodref(NODE_COUNTER, "getCounter",
- "()" + STRING_SIG);
- il.append(new INVOKEVIRTUAL(index));
- }
-
- // Output the resulting string to the handler
- il.append(methodGen.loadHandler());
- index = cpg.addMethodref(TRANSLET_CLASS,
- CHARACTERSW,
- CHARACTERSW_SIG);
- il.append(new INVOKEVIRTUAL(index));
- }
- }