Package com.sun.org.apache.xalan.internal.xsltc.compiler

Source Code of com.sun.org.apache.xalan.internal.xsltc.compiler.Whitespace$WhitespaceRule

/*
* 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: Whitespace.java,v 1.5 2005/09/28 13:48:18 pvedula Exp $
*/

package com.sun.org.apache.xalan.internal.xsltc.compiler;

import java.util.StringTokenizer;
import java.util.Vector;

import com.sun.org.apache.bcel.internal.generic.ALOAD;
import com.sun.org.apache.bcel.internal.generic.BranchHandle;
import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
import com.sun.org.apache.bcel.internal.generic.IF_ICMPEQ;
import com.sun.org.apache.bcel.internal.generic.ILOAD;
import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
import com.sun.org.apache.bcel.internal.generic.InstructionList;
import com.sun.org.apache.bcel.internal.generic.PUSH;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
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 Morten Jorgensen
*/
final class Whitespace extends TopLevelElement {
    // Three possible actions for the translet:
    public static final int USE_PREDICATE  = 0;
    public static final int STRIP_SPACE    = 1;
    public static final int PRESERVE_SPACE = 2;

    // The 3 different categories of strip/preserve rules (order important)
    public static final int RULE_NONE      = 0;
    public static final int RULE_ELEMENT   = 1; // priority 0
    public static final int RULE_NAMESPACE = 2; // priority -1/4
    public static final int RULE_ALL       = 3; // priority -1/2

    private String _elementList;
    private int    _action;
    private int    _importPrecedence;

    /**
     * Auxillary class for encapsulating a single strip/preserve rule
     */
    private final static class WhitespaceRule {
  private final int _action;
  private String _namespace; // Should be replaced by NS type (int)
  private String _element;   // Should be replaced by node type (int)
  private int    _type;
  private int    _priority;
 
  /**
   * Strip/preserve rule constructor
   */
  public WhitespaceRule(int action, String element, int precedence) {
       // Determine the action (strip or preserve) for this rule
      _action = action;

      // Get the namespace and element name for this rule
      final int colon = element.lastIndexOf(':');
      if (colon >= 0) {
    _namespace = element.substring(0,colon);
    _element = element.substring(colon+1,element.length());
      }
      else {
    _namespace = Constants.EMPTYSTRING;
    _element = element;
      }

      // Determine the initial priority for this rule
      _priority = precedence << 2;

      // Get the strip/preserve type; either "NS:EL", "NS:*" or "*"
      if (_element.equals("*")) {
    if (_namespace == Constants.EMPTYSTRING) {
        _type = RULE_ALL;       // Strip/preserve _all_ elements
        _priority += 2;         // Lowest priority
    }
    else {
        _type = RULE_NAMESPACE; // Strip/reserve elements within NS
        _priority += 1;         // Medium priority
    }
      }
      else {
    _type = RULE_ELEMENT;       // Strip/preserve single element
      }
  }

  /**
   * For sorting rules depending on priority
   */
  public int compareTo(WhitespaceRule other) {
      return _priority < other._priority
    ? -1
    : _priority > other._priority ? 1 : 0;
  }

  public int getAction() { return _action; }
  public int getStrength() { return _type; }
  public int getPriority() { return _priority; }
  public String getElement() { return _element; }
  public String getNamespace() { return _namespace; }
    }

    /**
     * Parse the attributes of the xsl:strip/preserve-space element.
     * The element should have not contents (ignored if any).
     */
    public void parseContents(Parser parser) {
        // Determine if this is an xsl:strip- or preserve-space element
        _action = _qname.getLocalPart().endsWith("strip-space")
            ? STRIP_SPACE : PRESERVE_SPACE;

        // Determine the import precedence
        _importPrecedence = parser.getCurrentImportPrecedence();

        // Get the list of elements to strip/preserve
        _elementList = getAttribute("elements");
        if (_elementList == null || _elementList.length() == 0) {
            reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "elements");
            return;
        }

        final SymbolTable stable = parser.getSymbolTable();
        StringTokenizer list = new StringTokenizer(_elementList);
        StringBuffer elements = new StringBuffer(Constants.EMPTYSTRING);

        while (list.hasMoreElements()) {
            String token = list.nextToken();
            String prefix;
            String namespace;
            int col = token.indexOf(':');

            if (col != -1) {
                namespace = lookupNamespace(token.substring(0,col));
                if (namespace != null) {
                    elements.append(namespace+":"+
                                    token.substring(col+1,token.length()));
                } else {
                    elements.append(token);
                }
            } else {
                elements.append(token);
            }

            if (list.hasMoreElements())
                elements.append(" ");
        }
        _elementList = elements.toString();
    }


    /**
     * De-tokenize the elements listed in the 'elements' attribute and
     * instanciate a set of strip/preserve rules.
     */
    public Vector getRules() {
  final Vector rules = new Vector();
  // Go through each element and instanciate strip/preserve-object
  final StringTokenizer list = new StringTokenizer(_elementList);
  while (list.hasMoreElements()) {
      rules.add(new WhitespaceRule(_action,
           list.nextToken(),
           _importPrecedence));
  }
  return rules;
    }
   
   
    /**
     * Scans through the rules vector and looks for a rule of higher
     * priority that contradicts the current rule.
     */
    private static WhitespaceRule findContradictingRule(Vector rules,
              WhitespaceRule rule) {
  for (int i = 0; i < rules.size(); i++) {
      // Get the next rule in the prioritized list
      WhitespaceRule currentRule = (WhitespaceRule)rules.elementAt(i);
      // We only consider rules with higher priority
      if (currentRule == rule) {
    return null;
      }
     
      /*
       * See if there is a contradicting rule with higher priority.
       * If the rules has the same action then this rule is redundant,
       * if they have different action then this rule will never win.
       */
      switch (currentRule.getStrength()) {
      case RULE_ALL:
    return currentRule;
   
      case RULE_ELEMENT:
    if (!rule.getElement().equals(currentRule.getElement())) {
        break;
    }
    // intentional fall-through
      case RULE_NAMESPACE:
    if (rule.getNamespace().equals(currentRule.getNamespace())) {
        return currentRule;
    }
    break;
      }
  }
  return null;
    }


    /**
     * Orders a set or rules by priority, removes redundant rules and rules
     * that are shadowed by stronger, contradicting rules.
     */
    private static int prioritizeRules(Vector rules) {
  WhitespaceRule currentRule;
  int defaultAction = PRESERVE_SPACE;

  // Sort all rules with regard to priority
  quicksort(rules, 0, rules.size()-1);

  // Check if there are any "xsl:strip-space" elements at all.
  // If there are no xsl:strip elements we can ignore all xsl:preserve
  // elements and signal that all whitespaces should be preserved
  boolean strip = false;
  for (int i = 0; i < rules.size(); i++) {
      currentRule = (WhitespaceRule)rules.elementAt(i);
      if (currentRule.getAction() == STRIP_SPACE) {
    strip = true;
      }
  }
  // Return with default action: PRESERVE_SPACE
  if (!strip) {
      rules.removeAllElements();
      return PRESERVE_SPACE;
  }

  // Remove all rules that are contradicted by rules with higher priority
  for (int idx = 0; idx < rules.size(); ) {
      currentRule = (WhitespaceRule)rules.elementAt(idx);
 
      // Remove this single rule if it has no purpose
      if (findContradictingRule(rules,currentRule) != null) {
    rules.remove(idx);
      }
      else {
    // Remove all following rules if this one overrides all
    if (currentRule.getStrength() == RULE_ALL) {
        defaultAction = currentRule.getAction();
        for (int i = idx; i < rules.size(); i++) {
      rules.removeElementAt(i);
        }
    }
    // Skip to next rule (there might not be any)...
    idx++;
      }
  }

  // The rules vector could be empty if first rule has strength RULE_ALL
  if (rules.size() == 0) {
      return defaultAction;
  }

  // Now work backwards and strip away all rules that have the same
  // action as the default rule (no reason the check them at the end).
  do {
      currentRule = (WhitespaceRule)rules.lastElement();
      if (currentRule.getAction() == defaultAction) {
    rules.removeElementAt(rules.size() - 1);
      }
      else {
    break;
      }
  } while (rules.size() > 0);
 
  // Signal that whitespace detection predicate must be used.
  return defaultAction;
    }

    public static void compileStripSpace(BranchHandle strip[],
           int sCount,
           InstructionList il) {
  final InstructionHandle target = il.append(ICONST_1);
  il.append(IRETURN);
  for (int i = 0; i < sCount; i++) {
      strip[i].setTarget(target);
  }
    }

    public static void compilePreserveSpace(BranchHandle preserve[],
              int pCount,
              InstructionList il) {
  final InstructionHandle target = il.append(ICONST_0);
  il.append(IRETURN);
  for (int i = 0; i < pCount; i++) {
      preserve[i].setTarget(target);
  }
    }

    /*
    private static void compileDebug(ClassGenerator classGen,
             InstructionList il) {
  final ConstantPoolGen cpg = classGen.getConstantPool();
  final int prt = cpg.addMethodref("java/lang/System/out",
           "println",
           "(Ljava/lang/String;)V");
  il.append(DUP);
  il.append(new INVOKESTATIC(prt));
    }
    */

    /**
     * Compiles the predicate method
     */
    private static void compilePredicate(Vector rules,
           int defaultAction,
           ClassGenerator classGen) {
  final ConstantPoolGen cpg = classGen.getConstantPool();
  final InstructionList il = new InstructionList();
  final XSLTC xsltc = classGen.getParser().getXSLTC();

  // private boolean Translet.stripSpace(int type) - cannot be static
  final MethodGenerator stripSpace =
      new MethodGenerator(ACC_PUBLIC | ACC_FINAL ,
      com.sun.org.apache.bcel.internal.generic.Type.BOOLEAN,
      new com.sun.org.apache.bcel.internal.generic.Type[] {
          Util.getJCRefType(DOM_INTF_SIG),
          com.sun.org.apache.bcel.internal.generic.Type.INT,
          com.sun.org.apache.bcel.internal.generic.Type.INT
      },
      new String[] { "dom","node","type" },
      "stripSpace",classGen.getClassName(),il,cpg);

  classGen.addInterface("com/sun/org/apache/xalan/internal/xsltc/StripFilter");

  final int paramDom = stripSpace.getLocalIndex("dom");
  final int paramCurrent = stripSpace.getLocalIndex("node");
  final int paramType = stripSpace.getLocalIndex("type");

  BranchHandle strip[] = new BranchHandle[rules.size()];
  BranchHandle preserve[] = new BranchHandle[rules.size()];
  int sCount = 0;
  int pCount = 0;

  // Traverse all strip/preserve rules
  for (int i = 0; i<rules.size(); i++) {
      // Get the next rule in the prioritised list
      WhitespaceRule rule = (WhitespaceRule)rules.elementAt(i);

      // Returns the namespace for a node in the DOM
      final int gns = cpg.addInterfaceMethodref(DOM_INTF,
                  "getNamespaceName",
                  "(I)Ljava/lang/String;");

      final int strcmp = cpg.addMethodref("java/lang/String",
            "compareTo",
            "(Ljava/lang/String;)I");

      // Handle elements="ns:*" type rule
      if (rule.getStrength() == RULE_NAMESPACE) {
    il.append(new ALOAD(paramDom));
    il.append(new ILOAD(paramCurrent));
    il.append(new INVOKEINTERFACE(gns,2));
    il.append(new PUSH(cpg, rule.getNamespace()));
    il.append(new INVOKEVIRTUAL(strcmp));
    il.append(ICONST_0);

    if (rule.getAction() == STRIP_SPACE) {
        strip[sCount++] = il.append(new IF_ICMPEQ(null));
    }
    else {
        preserve[pCount++] = il.append(new IF_ICMPEQ(null));
    }
      }
      // Handle elements="ns:el" type rule
      else if (rule.getStrength() == RULE_ELEMENT) {
    // Create the QName for the element
    final Parser parser = classGen.getParser();
    QName qname;
    if (rule.getNamespace() != Constants.EMPTYSTRING )
        qname = parser.getQName(rule.getNamespace(), null,
              rule.getElement());
    else
        qname = parser.getQName(rule.getElement());

    // Register the element.
    final int elementType = xsltc.registerElement(qname);
    il.append(new ILOAD(paramType));
    il.append(new PUSH(cpg, elementType));

    // Compare current node type with wanted element type
    if (rule.getAction() == STRIP_SPACE)
        strip[sCount++] = il.append(new IF_ICMPEQ(null));
    else
        preserve[pCount++] = il.append(new IF_ICMPEQ(null));
      }
  }

  if (defaultAction == STRIP_SPACE) {
      compileStripSpace(strip, sCount, il);
      compilePreserveSpace(preserve, pCount, il);
  }
  else {
      compilePreserveSpace(preserve, pCount, il);
      compileStripSpace(strip, sCount, il);
  }

  stripSpace.stripAttributes(true);
  stripSpace.setMaxLocals();
  stripSpace.setMaxStack();
  stripSpace.removeNOPs();

  classGen.addMethod(stripSpace.getMethod());
    }

    /**
     * Compiles the predicate method
     */
    private static void compileDefault(int defaultAction,
               ClassGenerator classGen) {
  final ConstantPoolGen cpg = classGen.getConstantPool();
  final InstructionList il = new InstructionList();
  final XSLTC xsltc = classGen.getParser().getXSLTC();

  // private boolean Translet.stripSpace(int type) - cannot be static
  final MethodGenerator stripSpace =
      new MethodGenerator(ACC_PUBLIC | ACC_FINAL ,
      com.sun.org.apache.bcel.internal.generic.Type.BOOLEAN,
      new com.sun.org.apache.bcel.internal.generic.Type[] {
          Util.getJCRefType(DOM_INTF_SIG),
          com.sun.org.apache.bcel.internal.generic.Type.INT,
          com.sun.org.apache.bcel.internal.generic.Type.INT
      },
      new String[] { "dom","node","type" },
      "stripSpace",classGen.getClassName(),il,cpg);

  classGen.addInterface("com/sun/org/apache/xalan/internal/xsltc/StripFilter");

  if (defaultAction == STRIP_SPACE)
      il.append(ICONST_1);
  else
      il.append(ICONST_0);
  il.append(IRETURN);

  stripSpace.stripAttributes(true);
  stripSpace.setMaxLocals();
  stripSpace.setMaxStack();
  stripSpace.removeNOPs();

  classGen.addMethod(stripSpace.getMethod());
    }


    /**
     * Takes a vector of WhitespaceRule objects and generates a predicate
     * method. This method returns the translets default action for handling
     * whitespace text-nodes:
     *    - USE_PREDICATE  (run the method generated by this method)
     *    - STRIP_SPACE    (always strip whitespace text-nodes)
     *    - PRESERVE_SPACE (always preserve whitespace text-nodes)
     */
    public static int translateRules(Vector rules,
             ClassGenerator classGen) {
  // Get the core rules in prioritized order
  final int defaultAction = prioritizeRules(rules);
  // The rules vector may be empty after prioritising
  if (rules.size() == 0) {
      compileDefault(defaultAction,classGen);
      return defaultAction;
  }
  // Now - create a predicate method and sequence through rules...
  compilePredicate(rules, defaultAction, classGen);
  // Return with the translets required action (
  return USE_PREDICATE;
    }

    /**
     * Sorts a range of rules with regard to PRIORITY only
     */
    private static void quicksort(Vector rules, int p, int r) {
  while (p < r) {
      final int q = partition(rules, p, r);
      quicksort(rules, p, q);
      p = q + 1;
  }
    }
   
    /**
     * Used with quicksort method above
     */
    private static int partition(Vector rules, int p, int r) {
  final WhitespaceRule x = (WhitespaceRule)rules.elementAt((p+r) >>> 1);
  int i = p - 1, j = r + 1;
  while (true) {
      while (x.compareTo((WhitespaceRule)rules.elementAt(--j)) < 0) {
      }
      while (x.compareTo((WhitespaceRule)rules.elementAt(++i)) > 0) {
      }
      if (i < j) {
    final WhitespaceRule tmp = (WhitespaceRule)rules.elementAt(i);
    rules.setElementAt(rules.elementAt(j), i);
    rules.setElementAt(tmp, j);
      }
      else {
    return j;
      }
  }
    }
   
    /**
     * Type-check contents/attributes - nothing to do...
     */
    public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  return Type.Void; // We don't return anything.
    }

    /**
     * This method should not produce any code
     */
    public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
    }
}
TOP

Related Classes of com.sun.org.apache.xalan.internal.xsltc.compiler.Whitespace$WhitespaceRule

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.