Package org.apache.xalan.xsltc.compiler

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

/*
* @(#)$Id: Step.java,v 1.42 2003/01/30 18:46:02 mkwan Exp $
*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
*    not be used to endorse or promote products derived from this
*    software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    nor may "Apache" appear in their name, without prior written
*    permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 2001, Sun
* Microsystems., http://www.sun.com.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* @author Jacek Ambroziak
* @author Santiago Pericas-Geertsen
* @author Morten Jorgensen
*
*/

package org.apache.xalan.xsltc.compiler;

import java.util.Vector;

import org.apache.bcel.generic.CHECKCAST;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.ICONST;
import org.apache.bcel.generic.INVOKEINTERFACE;
import org.apache.bcel.generic.INVOKESPECIAL;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.NEW;
import org.apache.bcel.generic.PUSH;
import org.apache.xalan.xsltc.DOM;
import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
import org.apache.xalan.xsltc.compiler.util.Type;
import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
import org.apache.xalan.xsltc.dom.Axis;

final class Step extends RelativeLocationPath {

    /**
     * This step's axis as defined in class Axis.
     */
    private int _axis;

    /**
     * A vector of predicates (filters) defined on this step - may be null
     */
    private Vector _predicates;

    /**
     * Some simple predicates can be handled by this class (and not by the
     * Predicate class) and will be removed from the above vector as they are
     * handled. We use this boolean to remember if we did have any predicates.
     */
    private boolean _hadPredicates = false;

    /**
     * Type of the node test.
     */
    private int _nodeType;

    public Step(int axis, int nodeType, Vector predicates) {
  _axis = axis;
  _nodeType = nodeType;
  _predicates = predicates;
    }

    /**
     * Set the parser for this element and all child predicates
     */
    public void setParser(Parser parser) {
  super.setParser(parser);
  if (_predicates != null) {
      final int n = _predicates.size();
      for (int i = 0; i < n; i++) {
    final Predicate exp = (Predicate)_predicates.elementAt(i);
    exp.setParser(parser);
    exp.setParent(this);
      }
  }
    }
   
    /**
     * Define the axis (defined in Axis class) for this step
     */
    public int getAxis() {
  return _axis;
    }
 
    /**
     * Get the axis (defined in Axis class) for this step
     */
    public void setAxis(int axis) {
  _axis = axis;
    }

    /**
     * Returns the node-type for this step
     */
    public int getNodeType() {
  return _nodeType;
    }

    /**
     * Returns the vector containing all predicates for this step.
     */
    public Vector getPredicates() {
  return _predicates;
    }

    /**
     * Returns the vector containing all predicates for this step.
     */
    public void addPredicates(Vector predicates) {
  if (_predicates == null) {
      _predicates = predicates;
  }
  else {
      _predicates.addAll(predicates);
  }
    }

    /**
     * Returns 'true' if this step has a parent pattern.
     * This method will return 'false' if this step occurs on its own under
     * an element like <xsl:for-each> or <xsl:apply-templates>.
     */
    private boolean hasParentPattern() {
  final SyntaxTreeNode parent = getParent();
  return (parent instanceof ParentPattern ||
    parent instanceof ParentLocationPath ||
    parent instanceof UnionPathExpr ||
    parent instanceof FilterParentPath);
    }
   
    /**
     * Returns 'true' if this step has any predicates
     */
    private boolean hasPredicates() {
  return _predicates != null && _predicates.size() > 0;
    }

    /**
     * Returns 'true' if this step is used within a predicate
     */
    private boolean isPredicate() {
  SyntaxTreeNode parent = this;
  while (parent != null) {
      parent = parent.getParent();
      if (parent instanceof Predicate) return true;
  }
  return false;
    }

    /**
     * True if this step is the abbreviated step '.'
     */
    public boolean isAbbreviatedDot() {
  return _nodeType == NodeTest.ANODE && _axis == Axis.SELF;
    }


    /**
     * True if this step is the abbreviated step '..'
     */
    public boolean isAbbreviatedDDot() {
  return _nodeType == NodeTest.ANODE && _axis == Axis.PARENT;
    }

    /**
     * Type check this step. The abbreviated steps '.' and '@attr' are
     * assigned type node if they have no predicates. All other steps
     * have type node-set.
     */
    public Type typeCheck(SymbolTable stable) throws TypeCheckError {

  // Save this value for later - important for testing for special
  // combinations of steps and patterns than can be optimised
  _hadPredicates = hasPredicates();

  // Special case for '.'
   //   in the case where '.' has a context such as book/.
  //   or .[false()] we can not optimize the nodeset to a single node.
  if (isAbbreviatedDot()) {
      _type =  (hasParentPattern() || hasPredicates() ) ?
    Type.NodeSet : Type.Node;
  }
  else {
      _type = Type.NodeSet;
  }

  // Type check all predicates (expressions applied to the step)
  if (_predicates != null) {
      final int n = _predicates.size();
      for (int i = 0; i < n; i++) {
    final Expression pred = (Expression)_predicates.elementAt(i);
    pred.typeCheck(stable);
      }
  }

  // Return either Type.Node or Type.NodeSet
  return _type;
    }

    /**
     * Translate a step by pushing the appropriate iterator onto the stack.
     * The abbreviated steps '.' and '@attr' do not create new iterators
     * if they are not part of a LocationPath and have no filters.
     * In these cases a node index instead of an iterator is pushed
     * onto the stack.
     */
    public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  final ConstantPoolGen cpg = classGen.getConstantPool();
  final InstructionList il = methodGen.getInstructionList();

  if (hasPredicates()) {
      translatePredicates(classGen, methodGen);
  }
  else {
      // If it is an attribute but not '@*', '@attr' or '@node()' and
      // has no parent
      if (_axis == Axis.ATTRIBUTE && _nodeType != NodeTest.ATTRIBUTE &&
    _nodeType != NodeTest.ANODE && !hasParentPattern())
      {
    int iter = cpg.addInterfaceMethodref(DOM_INTF,
                 "getTypedAxisIterator",
                 "(II)"+NODE_ITERATOR_SIG);
    il.append(methodGen.loadDOM());
    il.append(new PUSH(cpg, Axis.ATTRIBUTE));
    il.append(new PUSH(cpg, _nodeType));
    il.append(new INVOKEINTERFACE(iter, 3));
    return;
      }

      // Special case for '.'
      if (isAbbreviatedDot()) {
    if (_type == Type.Node) {
        // Put context node on stack if using Type.Node
        il.append(methodGen.loadContextNode());
    }
    else {
        // Wrap the context node in a singleton iterator if not.
        int init = cpg.addMethodref(SINGLETON_ITERATOR,
            "<init>", "("+NODE_SIG+")V");
        il.append(new NEW(cpg.addClass(SINGLETON_ITERATOR)));
        il.append(DUP);
        il.append(methodGen.loadContextNode());
        il.append(new INVOKESPECIAL(init));
    }
    return;
      }

      // Special case for /foo/*/bar
      SyntaxTreeNode parent = getParent();
      if ((parent instanceof ParentLocationPath) &&
    (parent.getParent() instanceof ParentLocationPath)) {
    if ((_nodeType == NodeTest.ELEMENT) && (!_hadPredicates)) {
        _nodeType = NodeTest.ANODE;
    }
      }

      // "ELEMENT" or "*" or "@*" or ".." or "@attr" with a parent.
      switch (_nodeType) {
      case NodeTest.ATTRIBUTE:
    _axis = Axis.ATTRIBUTE;
      case NodeTest.ANODE:
    // DOM.getAxisIterator(int axis);
    int git = cpg.addInterfaceMethodref(DOM_INTF,
                "getAxisIterator",
                "(I)"+NODE_ITERATOR_SIG);
    il.append(methodGen.loadDOM());
    il.append(new PUSH(cpg, _axis));
    il.append(new INVOKEINTERFACE(git, 2));
    break;
      default:
    final XSLTC xsltc = getParser().getXSLTC();
    final Vector ni = xsltc.getNamesIndex();
    String name = null;
    int star = 0;
   
    if (_nodeType >= DOM.NTYPES) {
        name = (String)ni.elementAt(_nodeType-DOM.NTYPES);
        star = name.lastIndexOf('*');
    }
   
    if (star > 1) {
        final String namespace;
        if (_axis == Axis.ATTRIBUTE)
      namespace = name.substring(0,star-2);
        else
      namespace = name.substring(0,star-1);

        final int nsType = xsltc.registerNamespace(namespace);
        final int ns = cpg.addInterfaceMethodref(DOM_INTF,
                "getNamespaceAxisIterator",
                "(II)"+NODE_ITERATOR_SIG);
        il.append(methodGen.loadDOM());
        il.append(new PUSH(cpg, _axis));
        il.append(new PUSH(cpg, nsType));
        il.append(new INVOKEINTERFACE(ns, 3));
        break;
    }
      case NodeTest.ELEMENT:
    // DOM.getTypedAxisIterator(int axis, int type);
    final int ty = cpg.addInterfaceMethodref(DOM_INTF,
            "getTypedAxisIterator",
            "(II)"+NODE_ITERATOR_SIG);
    // Get the typed iterator we're after
    il.append(methodGen.loadDOM());
    il.append(new PUSH(cpg, _axis));
    il.append(new PUSH(cpg, _nodeType));
    il.append(new INVOKEINTERFACE(ty, 3));

    break;
      }
  }
    }


    /**
     * Translate a sequence of predicates. Each predicate is translated
     * by constructing an instance of <code>CurrentNodeListIterator</code>
     * which is initialized from another iterator (recursive call),
     * a filter and a closure (call to translate on the predicate) and "this".
     */
    public void translatePredicates(ClassGenerator classGen,
            MethodGenerator methodGen) {
  final ConstantPoolGen cpg = classGen.getConstantPool();
  final InstructionList il = methodGen.getInstructionList();

  int idx = 0;

  if (_predicates.size() == 0) {
      translate(classGen, methodGen);
  }
  else {
      final Predicate predicate = (Predicate)_predicates.lastElement();
      _predicates.remove(predicate);

      // Special case for predicates that can use the NodeValueIterator
      // instead of an auxiliary class. Certain path/predicates pairs
      // are translated into a base path, on top of which we place a
      // node value iterator that tests for the desired value:
      //   foo[@attr = 'str']  ->  foo/@attr + test(value='str')
      //   foo[bar = 'str']    ->  foo/bar + test(value='str')
      //   foo/bar[. = 'str']  ->  foo/bar + test(value='str')
      if (predicate.isNodeValueTest()) {
    Step step = predicate.getStep();

    il.append(methodGen.loadDOM());
    // If the predicate's Step is simply '.' we translate this Step
    // and place the node test on top of the resulting iterator
    if (step.isAbbreviatedDot()) {
        translate(classGen, methodGen);
        il.append(new ICONST(DOM.RETURN_CURRENT));
    }
    // Otherwise we create a parent location path with this Step and
    // the predicates Step, and place the node test on top of that
    else {
        ParentLocationPath path = new ParentLocationPath(this,step);
        try {
      path.typeCheck(getParser().getSymbolTable());
        }
        catch (TypeCheckError e) { }
        path.translate(classGen, methodGen);
        il.append(new ICONST(DOM.RETURN_PARENT));
    }
    predicate.translate(classGen, methodGen);
    idx = cpg.addInterfaceMethodref(DOM_INTF,
            GET_NODE_VALUE_ITERATOR,
            GET_NODE_VALUE_ITERATOR_SIG);
    il.append(new INVOKEINTERFACE(idx, 5));
      }
      // Handle '//*[n]' expression
      else if (predicate.isNthDescendant()) {
    il.append(methodGen.loadDOM());
    il.append(new ICONST(NodeTest.ELEMENT));
    predicate.translate(classGen, methodGen);
    il.append(new ICONST(0));
    idx = cpg.addInterfaceMethodref(DOM_INTF,
            "getNthDescendant",
            "(IIZ)"+NODE_ITERATOR_SIG);
    il.append(new INVOKEINTERFACE(idx, 4));
      }
      // Handle 'elem[n]' expression
      else if (predicate.isNthPositionFilter()) {
    idx = cpg.addMethodref(NTH_ITERATOR_CLASS,
               "<init>",
               "("+NODE_ITERATOR_SIG+"I)V");
    il.append(new NEW(cpg.addClass(NTH_ITERATOR_CLASS)));
    il.append(DUP);
    translatePredicates(classGen, methodGen); // recursive call
    predicate.translate(classGen, methodGen);
    il.append(new INVOKESPECIAL(idx));
      }
      else {
    idx = cpg.addMethodref(CURRENT_NODE_LIST_ITERATOR,
               "<init>",
               "("
               + NODE_ITERATOR_SIG
               + CURRENT_NODE_LIST_FILTER_SIG
               + NODE_SIG
               + TRANSLET_SIG
               + ")V");
    // create new CurrentNodeListIterator
    il.append(new NEW(cpg.addClass(CURRENT_NODE_LIST_ITERATOR)));
    il.append(DUP);
    translatePredicates(classGen, methodGen); // recursive call
    predicate.translateFilter(classGen, methodGen);
   
    il.append(methodGen.loadCurrentNode());
    il.append(classGen.loadTranslet());
    if (classGen.isExternal()) {
        final String className = classGen.getClassName();
        il.append(new CHECKCAST(cpg.addClass(className)));
    }
    il.append(new INVOKESPECIAL(idx));
      }
  }
    }

    /**
     * Returns a string representation of this step.
     */
    public String toString() {
  final StringBuffer buffer = new StringBuffer("step(\"");
  buffer.append(Axis.names[_axis]).append("\", ").append(_nodeType);
  if (_predicates != null) {
      final int n = _predicates.size();
      for (int i = 0; i < n; i++) {
    final Predicate pred = (Predicate)_predicates.elementAt(i);
    buffer.append(", ").append(pred.toString());
      }
  }
  return buffer.append(')').toString();
    }
}
TOP

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

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.