Package org.apache.xalan.xsltc.compiler

Source Code of org.apache.xalan.xsltc.compiler.Number

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 468650 2006-10-28 07:03:30Z minchau $
*/

package org.apache.xalan.xsltc.compiler;

import java.util.ArrayList;

import org.apache.bcel.classfile.Field;
import org.apache.bcel.generic.ALOAD;
import org.apache.bcel.generic.ASTORE;
import org.apache.bcel.generic.BranchHandle;
import org.apache.bcel.generic.CHECKCAST;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETFIELD;
import org.apache.bcel.generic.GOTO;
import org.apache.bcel.generic.IFNONNULL;
import org.apache.bcel.generic.INVOKESPECIAL;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.D2I;
import org.apache.bcel.generic.LocalVariableGen;
import org.apache.bcel.generic.NEW;
import org.apache.bcel.generic.PUSH;
import org.apache.bcel.generic.PUTFIELD;
import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
import org.apache.xalan.xsltc.compiler.util.MatchGenerator;
import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
import org.apache.xalan.xsltc.compiler.util.NodeCounterGenerator;
import org.apache.xalan.xsltc.compiler.util.RealType;
import org.apache.xalan.xsltc.compiler.util.Type;
import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
import org.apache.xalan.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 = {
  "org.apache.xalan.xsltc.dom.SingleNodeCounter",    // LEVEL_SINGLE
  "org.apache.xalan.xsltc.dom.MultipleNodeCounter", // LEVEL_MULTIPLE
  "org.apache.xalan.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,
           org.apache.bcel.generic.Type.VOID,
           new org.apache.bcel.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);
 
  classGen.addMethod(cons);
    }

    /**
     * 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));
  local.setStart(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",
        "Lorg/apache/xalan/xsltc/Translet;");
  il.append(ALOAD_0); // 'this' pointer on stack
  il.append(new GETFIELD(field));
  il.append(new CHECKCAST(cpg.addClass(TRANSLET_CLASS)));
  local.setStart(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!!!
  local.setStart(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,
           org.apache.bcel.generic.Type.BOOLEAN,
           new org.apache.bcel.generic.Type[] {
               org.apache.bcel.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);
       
      nodeCounterGen.addMethod(matchGen);
  }

  /*
   * Compile method matchesCount()
   */
  if (_count != null) {
      il = new InstructionList();
      matchGen = new MatchGenerator(ACC_PUBLIC | ACC_FINAL,
            org.apache.bcel.generic.Type.BOOLEAN,
            new org.apache.bcel.generic.Type[] {
                org.apache.bcel.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);
       
      nodeCounterGen.addMethod(matchGen);
  }
 
  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);

      // Using java.lang.Math.floor(number + 0.5) to return a double value
            il.append(new PUSH(cpg, 0.5));
            il.append(DADD);
      index = cpg.addMethodref(MATH_CLASS, "floor", "(D)D");
      il.append(new INVOKESTATIC(index));

      // Call setValue on the node counter
      index = cpg.addMethodref(NODE_COUNTER,
             "setValue",
             "(D)" + 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));
    }
}
TOP

Related Classes of org.apache.xalan.xsltc.compiler.Number

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.