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

Source Code of com.sun.org.apache.xalan.internal.xsltc.compiler.Step

/*
* Copyright 2001-2005 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: Step.java,v 1.6 2006/06/06 22:34:34 spericas Exp $
*/

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

import java.util.Vector;

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.CHECKCAST;
import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
import com.sun.org.apache.bcel.internal.generic.ICONST;
import com.sun.org.apache.bcel.internal.generic.ILOAD;
import com.sun.org.apache.bcel.internal.generic.ISTORE;
import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
import com.sun.org.apache.bcel.internal.generic.InstructionList;
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.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
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;
import com.sun.org.apache.xml.internal.dtm.Axis;
import com.sun.org.apache.xml.internal.dtm.DTM;

/**
* @author Jacek Ambroziak
* @author Santiago Pericas-Geertsen
* @author Morten Jorgensen
*/
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 a parent location path.
     */
    private boolean hasParentLocationPath() {
  return getParent() instanceof ParentLocationPath;
    }
   
    /**
     * 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() || hasParentLocationPath()) ?
    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 {
            int star = 0;
            String name = null;
            final XSLTC xsltc = getParser().getXSLTC();

            if (_nodeType >= DTM.NTYPES) {
    final Vector ni = xsltc.getNamesIndex();
   
                name = (String)ni.elementAt(_nodeType-DTM.NTYPES);
                star = name.lastIndexOf('*');
            }

      // If it is an attribute, but not '@*', '@pre:*' or '@node()',
            // and has no parent
      if (_axis == Axis.ATTRIBUTE && _nodeType != NodeTest.ATTRIBUTE
    && _nodeType != NodeTest.ANODE && !hasParentPattern()
                && star == 0)
      {
    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;
      }

      SyntaxTreeNode parent = getParent();
      // Special case for '.'
      if (isAbbreviatedDot()) {
    if (_type == Type.Node) {
        // Put context node on stack if using Type.Node
        il.append(methodGen.loadContextNode());
    }
    else {
        if (parent instanceof ParentLocationPath){
      // 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));
        } else {
      // 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));
        }
    }
    return;
      }

      // Special case for /foo/*/bar
      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:
    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);
                    _parent = step._parent = path;      // Force re-parenting
                   
        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));
    il.append(new ICONST(predicate.getPosType()));
    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");

                // Backwards branches are prohibited if an uninitialized object
                // is on the stack by section 4.9.4 of the JVM Specification,
                // 2nd Ed.  We don't know whether this code might contain
                // backwards branches, so we mustn't create the new object until
                // after we've created the suspect arguments to its constructor.
                // Instead we calculate the values of the arguments to the
                // constructor first, store them in temporary variables, create
                // the object and reload the arguments from the temporaries to
                // avoid the problem.
    translatePredicates(classGen, methodGen); // recursive call
                LocalVariableGen iteratorTemp
                        = methodGen.addLocalVariable("step_tmp1",
                                         Util.getJCRefType(NODE_ITERATOR_SIG),
                                         il.getEnd(), null);
                il.append(new ASTORE(iteratorTemp.getIndex()));

    predicate.translate(classGen, methodGen);
                LocalVariableGen predicateValueTemp
                        = methodGen.addLocalVariable("step_tmp2",
                                         Util.getJCRefType("I"),
                                         il.getEnd(), null);
                il.append(new ISTORE(predicateValueTemp.getIndex()));

    il.append(new NEW(cpg.addClass(NTH_ITERATOR_CLASS)));
    il.append(DUP);
                il.append(new ALOAD(iteratorTemp.getIndex()));
                il.append(new ILOAD(predicateValueTemp.getIndex()));
    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");

                // Backwards branches are prohibited if an uninitialized object
                // is on the stack by section 4.9.4 of the JVM Specification,
                // 2nd Ed.  We don't know whether this code might contain
                // backwards branches, so we mustn't create the new object until
                // after we've created the suspect arguments to its constructor.
                // Instead we calculate the values of the arguments to the
                // constructor first, store them in temporary variables, create
                // the object and reload the arguments from the temporaries to
                // avoid the problem.
    translatePredicates(classGen, methodGen); // recursive call
                LocalVariableGen iteratorTemp
                        = methodGen.addLocalVariable("step_tmp1",
                                         Util.getJCRefType(NODE_ITERATOR_SIG),
                                         il.getEnd(), null);
                il.append(new ASTORE(iteratorTemp.getIndex()));

    predicate.translateFilter(classGen, methodGen);
                LocalVariableGen filterTemp
                        = methodGen.addLocalVariable("step_tmp2",
                              Util.getJCRefType(CURRENT_NODE_LIST_FILTER_SIG),
                              il.getEnd(), null);
                il.append(new ASTORE(filterTemp.getIndex()));

    // create new CurrentNodeListIterator
    il.append(new NEW(cpg.addClass(CURRENT_NODE_LIST_ITERATOR)));
    il.append(DUP);

                il.append(new ALOAD(iteratorTemp.getIndex()));
                il.append(new ALOAD(filterTemp.getIndex()));
   
    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.getNames(_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 com.sun.org.apache.xalan.internal.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.