content: /*
   *  This file is part of AndroidIDE.
   *
   *  AndroidIDE is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  AndroidIDE is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *   along with AndroidIDE.  If not, see <https://www.gnu.org/licenses/>.
   */
  
  /*
   * reserved comment block
   * DO NOT REMOVE OR ALTER!
   */
  /*
   * Copyright 1999-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: StepPattern.java,v 1.2.4.2 2005/09/15 00:21:16 jeffsuttor Exp $
   */
  package jaxp.sun.org.apache.xpath.internal.patterns;
  
  import jaxp.sun.org.apache.xml.internal.dtm.Axis;
  import jaxp.sun.org.apache.xml.internal.dtm.DTM;
  import jaxp.sun.org.apache.xml.internal.dtm.DTMAxisTraverser;
  import jaxp.sun.org.apache.xml.internal.dtm.DTMFilter;
  import jaxp.sun.org.apache.xpath.internal.Expression;
  import jaxp.sun.org.apache.xpath.internal.ExpressionOwner;
  import jaxp.sun.org.apache.xpath.internal.XPathContext;
  import jaxp.sun.org.apache.xpath.internal.XPathVisitable;
  import jaxp.sun.org.apache.xpath.internal.XPathVisitor;
  import jaxp.sun.org.apache.xpath.internal.axes.SubContextList;
  import jaxp.sun.org.apache.xpath.internal.compiler.PsuedoNames;
  import jaxp.sun.org.apache.xpath.internal.objects.XObject;
  import jaxp.xml.transform.TransformerException;
  
  /**
   * This class represents a single pattern match step.
   * @xsl.usage advanced
   */
  public class StepPattern extends NodeTest implements SubContextList, ExpressionOwner
  {
      static final long serialVersionUID = 9071668960168152644L;
  
    /** The axis for this test. */
    protected int m_axis;
  
    /**
     * Construct a StepPattern that tests for namespaces and node names.
     *
     *
     * @param whatToShow Bit set defined mainly by {@link org.w3c.dom.traversal.NodeFilter}.
     * @param namespace The namespace to be tested.
     * @param name The local name to be tested.
     * @param axis The Axis for this test, one of of Axes.ANCESTORORSELF, etc.
     * @param axisForPredicate No longer used.
     */
    public StepPattern(int whatToShow, String namespace, String name, int axis,
                       int axisForPredicate)
    {
  
      super(whatToShow, namespace, name);
  
      m_axis = axis;
    }
  
    /**
     * Construct a StepPattern that doesn't test for node names.
     *
     *
     * @param whatToShow Bit set defined mainly by {@link org.w3c.dom.traversal.NodeFilter}.
     * @param axis The Axis for this test, one of of Axes.ANCESTORORSELF, etc.
     * @param axisForPredicate No longer used.
     */
    public StepPattern(int whatToShow, int axis, int axisForPredicate)
    {
  
      super(whatToShow);
  
      m_axis = axis;
    }
  
    /**
     * The target local name or psuedo name, for hash table lookup optimization.
     *  @serial
     */
    String m_targetString;  // only calculate on head
  
    /**
     * Calculate the local name or psuedo name of the node that this pattern will test,
     * for hash table lookup optimization.
     *
     * @see PsuedoNames
     */
    public void calcTargetString()
    {
  
      int whatToShow = getWhatToShow();
  
      switch (whatToShow)
      {
      case DTMFilter.SHOW_COMMENT :
        m_targetString = PsuedoNames.PSEUDONAME_COMMENT;
        break;
      case DTMFilter.SHOW_TEXT :
      case DTMFilter.SHOW_CDATA_SECTION :
      case (DTMFilter.SHOW_TEXT | DTMFilter.SHOW_CDATA_SECTION) :
        m_targetString = PsuedoNames.PSEUDONAME_TEXT;
        break;
      case DTMFilter.SHOW_ALL :
        m_targetString = PsuedoNames.PSEUDONAME_ANY;
        break;
      case DTMFilter.SHOW_DOCUMENT :
      case DTMFilter.SHOW_DOCUMENT | DTMFilter.SHOW_DOCUMENT_FRAGMENT :
        m_targetString = PsuedoNames.PSEUDONAME_ROOT;
        break;
      case DTMFilter.SHOW_ELEMENT :
        if (this.WILD == m_name)
          m_targetString = PsuedoNames.PSEUDONAME_ANY;
        else
          m_targetString = m_name;
        break;
      default :
        m_targetString = PsuedoNames.PSEUDONAME_ANY;
        break;
      }
    }
  
    /**
     * Get the local name or psuedo name of the node that this pattern will test,
     * for hash table lookup optimization.
     *
     *
     * @return local name or psuedo name of the node.
     * @see PsuedoNames
     */
    public String getTargetString()
    {
      return m_targetString;
    }
  
    /**
     * Reference to nodetest and predicate for
     * parent or ancestor.
     * @serial
     */
    StepPattern m_relativePathPattern;
  
    /**
     * This function is used to fixup variables from QNames to stack frame
     * indexes at stylesheet build time.
     * @param vars List of QNames that correspond to variables.  This list
     * should be searched backwards for the first qualified name that
     * corresponds to the variable reference qname.  The position of the
     * QName in the vector from the start of the vector will be its position
     * in the stack frame (but variables above the globalsTop value will need
     * to be offset to the current stack frame).
     * @param globalsSize The number of variables in the global variable area.
     */
    public void fixupVariables(java.util.Vector vars, int globalsSize)
    {
  
      super.fixupVariables(vars, globalsSize);
  
      if (null != m_predicates)
      {
        for (int i = 0; i < m_predicates.length; i++)
        {
          m_predicates[i].fixupVariables(vars, globalsSize);
        }
      }
  
      if (null != m_relativePathPattern)
      {
        m_relativePathPattern.fixupVariables(vars, globalsSize);
      }
    }
  
    /**
     * Set the reference to nodetest and predicate for
     * parent or ancestor.
     *
     *
     * @param expr The relative pattern expression.
     */
    public void setRelativePathPattern(StepPattern expr)
    {
  
      m_relativePathPattern = expr;
      expr.exprSetParent(this);
  
      calcScore();
    }
  
    /**
     * Get the reference to nodetest and predicate for
     * parent or ancestor.
     *
     *
     * @return The relative pattern expression.
     */
    public StepPattern getRelativePathPattern()
    {
      return m_relativePathPattern;
    }
  
    //  /**
    //   * Set the list of predicate expressions for this pattern step.
    //   * @param predicates List of expression objects.
    //   */
    //  public void setPredicates(Expression[] predicates)
    //  {
    //    m_predicates = predicates;
    //  }
  
    /**
     * Set the list of predicate expressions for this pattern step.
     * @return List of expression objects.
     */
    public Expression[] getPredicates()
    {
      return m_predicates;
    }
  
    /**
     * The list of predicate expressions for this pattern step.
     *  @serial
     */
    Expression[] m_predicates;
  
    /**
     * Tell if this expression or it's subexpressions can traverse outside
     * the current subtree.
     *
     * NOTE: Ancestors tests with predicates are problematic, and will require
     * special treatment.
     *
     * @return true if traversal outside the context node's subtree can occur.
     */
    public boolean canTraverseOutsideSubtree()
    {
  
      int n = getPredicateCount();
  
      for (int i = 0; i < n; i++)
      {
        if (getPredicate(i).canTraverseOutsideSubtree())
          return true;
      }
  
      return false;
    }
  
    /**
     * Get a predicate expression.
     *
     *
     * @param i The index of the predicate.
     *
     * @return A predicate expression.
     */
    public Expression getPredicate(int i)
    {
      return m_predicates[i];
    }
  
    /**
     * Get the number of predicates for this match pattern step.
     *
     *
     * @return the number of predicates for this match pattern step.
     */
    public final int getPredicateCount()
    {
      return (null == m_predicates) ? 0 : m_predicates.length;
    }
  
    /**
     * Set the predicates for this match pattern step.
     *
     *
     * @param predicates An array of expressions that define predicates
     *                   for this step.
     */
    public void setPredicates(Expression[] predicates)
    {
  
      m_predicates = predicates;
      if(null != predicates)
      {
          for(int i = 0; i < predicates.length; i++)
          {
                  predicates[i].exprSetParent(this);
          }
      }
  
      calcScore();
    }
  
    /**
     * Static calc of match score.
     */
    public void calcScore()
    {
  
      if ((getPredicateCount() > 0) || (null != m_relativePathPattern))
      {
        m_score = SCORE_OTHER;
      }
      else
        super.calcScore();
  
      if (null == m_targetString)
        calcTargetString();
    }
  
    /**
     * Execute this pattern step, including predicates.
     *
     *
     * @param xctxt XPath runtime context.
     * @param currentNode The current node context.
     *
     * @return {@link NodeTest#SCORE_NODETEST},
     *         {@link NodeTest#SCORE_NONE},
     *         {@link NodeTest#SCORE_NSWILD},
     *         {@link NodeTest#SCORE_QNAME}, or
     *         {@link NodeTest#SCORE_OTHER}.
     *
     * @throws TransformerException
     */
    public XObject execute(XPathContext xctxt, int currentNode)
            throws TransformerException
    {
  
      DTM dtm = xctxt.getDTM(currentNode);
  
      if (dtm != null)
      {
        int expType = dtm.getExpandedTypeID(currentNode);
  
        return execute(xctxt, currentNode, dtm, expType);
      }
  
      return SCORE_NONE;
    }
  
    /**
     * Execute this pattern step, including predicates.
     *
     *
     * @param xctxt XPath runtime context.
     *
     * @return {@link NodeTest#SCORE_NODETEST},
     *         {@link NodeTest#SCORE_NONE},
     *         {@link NodeTest#SCORE_NSWILD},
     *         {@link NodeTest#SCORE_QNAME}, or
     *         {@link NodeTest#SCORE_OTHER}.
     *
     * @throws TransformerException
     */
    public XObject execute(XPathContext xctxt)
            throws TransformerException
    {
      return execute(xctxt, xctxt.getCurrentNode());
    }
  
    /**
     * Execute an expression in the XPath runtime context, and return the
     * result of the expression.
     *
     *
     * @param xctxt The XPath runtime context.
     * @param currentNode The currentNode.
     * @param dtm The DTM of the current node.
     * @param expType The expanded type ID of the current node.
     *
     * @return The result of the expression in the form of a <code>XObject</code>.
     *
     * @throws TransformerException if a runtime exception
     *         occurs.
     */
    public XObject execute(
            XPathContext xctxt, int currentNode, DTM dtm, int expType)
              throws TransformerException
    {
  
      if (m_whatToShow == SHOW_BYFUNCTION)
      {
        if (null != m_relativePathPattern)
        {
          return m_relativePathPattern.execute(xctxt);
        }
        else
          return SCORE_NONE;
      }
  
      XObject score;
  
      score = super.execute(xctxt, currentNode, dtm, expType);
  
      if (score == SCORE_NONE)
        return SCORE_NONE;
  
      if (getPredicateCount() != 0)
      {
        if (!executePredicates(xctxt, dtm, currentNode))
          return SCORE_NONE;
      }
  
      if (null != m_relativePathPattern)
        return m_relativePathPattern.executeRelativePathPattern(xctxt, dtm,
                currentNode);
  
      return score;
    }
  
    /**
     * New Method to check whether the current node satisfies a position predicate
     *
     * @param xctxt The XPath runtime context.
     * @param predPos Which predicate we're evaluating of foo[1][2][3].
     * @param dtm The DTM of the current node.
     * @param context The currentNode.
     * @param pos The position being requested, i.e. the value returned by
     *            m_predicates[predPos].execute(xctxt).
     *
     * @return true of the position of the context matches pos, false otherwise.
     */
    private final boolean checkProximityPosition(XPathContext xctxt,
            int predPos, DTM dtm, int context, int pos)
    {
  
      try
      {
        DTMAxisTraverser traverser =
          dtm.getAxisTraverser(Axis.PRECEDINGSIBLING);
  
        for (int child = traverser.first(context); DTM.NULL != child;
                child = traverser.next(context, child))
        {
          try
          {
            xctxt.pushCurrentNode(child);
  
            if (SCORE_NONE != super.execute(xctxt, child))
            {
              boolean pass = true;
  
              try
              {
                xctxt.pushSubContextList(this);
  
                for (int i = 0; i < predPos; i++)
                {
                  xctxt.pushPredicatePos(i);
                  try
                  {
                    XObject pred = m_predicates[i].execute(xctxt);
  
                    try
                    {
                      if (XObject.CLASS_NUMBER == pred.getType())
                      {
                        throw new Error("Why: Should never have been called");
                      }
                      else if (!pred.boolWithSideEffects())
                      {
                        pass = false;
  
                        break;
                      }
                    }
                    finally
                    {
                      pred.detach();
                    }
                  }
                  finally
                  {
                    xctxt.popPredicatePos();
                  }
                }
              }
              finally
              {
                xctxt.popSubContextList();
              }
  
              if (pass)
                pos--;
  
              if (pos < 1)
                return false;
            }
          }
          finally
          {
            xctxt.popCurrentNode();
          }
        }
      }
      catch (TransformerException se)
      {
  
        // TODO: should keep throw sax exception...
        throw new java.lang.RuntimeException(se.getMessage());
      }
  
      return (pos == 1);
    }
  
    /**
     * Get the proximity position index of the current node based on this
     * node test.
     *
     *
     * @param xctxt XPath runtime context.
     * @param predPos Which predicate we're evaluating of foo[1][2][3].
     * @param findLast If true, don't terminate when the context node is found.
     *
     * @return the proximity position index of the current node based on the
     *         node test.
     */
    private final int getProximityPosition(XPathContext xctxt, int predPos,
                      boolean findLast)
    {
  
      int pos = 0;
      int context = xctxt.getCurrentNode();
      DTM dtm = xctxt.getDTM(context);
      int parent = dtm.getParent(context);
  
      try
      {
        DTMAxisTraverser traverser = dtm.getAxisTraverser(Axis.CHILD);
  
        for (int child = traverser.first(parent); DTM.NULL != child;
                child = traverser.next(parent, child))
        {
          try
          {
            xctxt.pushCurrentNode(child);
  
            if (SCORE_NONE != super.execute(xctxt, child))
            {
              boolean pass = true;
  
              try
              {
                xctxt.pushSubContextList(this);
  
                for (int i = 0; i < predPos; i++)
                {
                  xctxt.pushPredicatePos(i);
                  try
                  {
                    XObject pred = m_predicates[i].execute(xctxt);
  
                    try
                    {
                      if (XObject.CLASS_NUMBER == pred.getType())
                      {
                        if ((pos + 1) != (int) pred.numWithSideEffects())
                        {
                          pass = false;
  
                          break;
                        }
                      }
                      else if (!pred.boolWithSideEffects())
                      {
                        pass = false;
  
                        break;
                      }
                    }
                    finally
                    {
                      pred.detach();
                    }
                  }
                  finally
                  {
                    xctxt.popPredicatePos();
                  }
                }
              }
              finally
              {
                xctxt.popSubContextList();
              }
  
              if (pass)
                pos++;
  
              if (!findLast && child == context)
              {
                return pos;
              }
            }
          }
          finally
          {
            xctxt.popCurrentNode();
          }
        }
      }
      catch (TransformerException se)
      {
  
        // TODO: should keep throw sax exception...
        throw new java.lang.RuntimeException(se.getMessage());
      }
  
      return pos;
    }
  
    /**
     * Get the proximity position index of the current node based on this
     * node test.
     *
     *
     * @param xctxt XPath runtime context.
     *
     * @return the proximity position index of the current node based on the
     *         node test.
     */
    public int getProximityPosition(XPathContext xctxt)
    {
      return getProximityPosition(xctxt, xctxt.getPredicatePos(), false);
    }
  
    /**
     * Get the count of the nodes that match the test, which is the proximity
     * position of the last node that can pass this test in the sub context
     * selection.  In XSLT 1-based indexing, this count is the index of the last
     * node.
     *
     *
     * @param xctxt XPath runtime context.
     *
     * @return the count of the nodes that match the test.
     */
    public int getLastPos(XPathContext xctxt)
    {
      return getProximityPosition(xctxt, xctxt.getPredicatePos(), true);
    }
  
    /**
     * Execute the match pattern step relative to another step.
     *
     *
     * @param xctxt The XPath runtime context.
     * @param dtm The DTM of the current node.
     * @param currentNode The current node context.
     *
     * @return {@link NodeTest#SCORE_NODETEST},
     *         {@link NodeTest#SCORE_NONE},
     *         {@link NodeTest#SCORE_NSWILD},
     *         {@link NodeTest#SCORE_QNAME}, or
     *         {@link NodeTest#SCORE_OTHER}.
     *
     * @throws TransformerException
     */
    protected final XObject executeRelativePathPattern(
            XPathContext xctxt, DTM dtm, int currentNode)
              throws TransformerException
    {
  
      XObject score = SCORE_NONE;
      int context = currentNode;
      DTMAxisTraverser traverser;
  
      traverser = dtm.getAxisTraverser(m_axis);
  
      for (int relative = traverser.first(context); DTM.NULL != relative;
              relative = traverser.next(context, relative))
      {
        try
        {
          xctxt.pushCurrentNode(relative);
  
          score = execute(xctxt);
  
          if (score != SCORE_NONE)
            break;
        }
        finally
        {
          xctxt.popCurrentNode();
        }
      }
  
      return score;
    }
  
    /**
     * Execute the predicates on this step to determine if the current node
     * should be filtered or accepted.
     *
     * @param xctxt The XPath runtime context.
     * @param dtm The DTM of the current node.
     * @param currentNode The current node context.
     *
     * @return true if the node should be accepted, false otherwise.
     *
     * @throws TransformerException
     */
    protected final boolean executePredicates(
            XPathContext xctxt, DTM dtm, int currentNode)
              throws TransformerException
    {
  
      boolean result = true;
      boolean positionAlreadySeen = false;
      int n = getPredicateCount();
  
      try
      {
        xctxt.pushSubContextList(this);
  
        for (int i = 0; i < n; i++)
        {
          xctxt.pushPredicatePos(i);
  
          try
          {
            XObject pred = m_predicates[i].execute(xctxt);
  
            try
            {
              if (XObject.CLASS_NUMBER == pred.getType())
              {
                int pos = (int) pred.num();
  
                if (positionAlreadySeen)
                {
                  result = (pos == 1);
  
                  break;
                }
                else
                {
                  positionAlreadySeen = true;
  
                  if (!checkProximityPosition(xctxt, i, dtm, currentNode, pos))
                  {
                    result = false;
  
                    break;
                  }
                }
  
              }
              else if (!pred.boolWithSideEffects())
              {
                result = false;
  
                break;
              }
            }
            finally
            {
              pred.detach();
            }
          }
          finally
          {
            xctxt.popPredicatePos();
          }
        }
      }
      finally
      {
        xctxt.popSubContextList();
      }
  
      return result;
    }
  
    /**
     * Get the string represenentation of this step for diagnostic purposes.
     *
     *
     * @return A string representation of this step, built by reverse-engineering
     * the contained info.
     */
    public String toString()
    {
  
      StringBuffer buf = new StringBuffer();
  
      for (StepPattern pat = this; pat != null; pat = pat.m_relativePathPattern)
      {
        if (pat != this)
          buf.append("/");
  
        buf.append(Axis.getNames(pat.m_axis));
        buf.append("::");
  
        if (0x000005000 == pat.m_whatToShow)
        {
          buf.append("doc()");
        }
        else if (DTMFilter.SHOW_BYFUNCTION == pat.m_whatToShow)
        {
          buf.append("function()");
        }
        else if (DTMFilter.SHOW_ALL == pat.m_whatToShow)
        {
          buf.append("node()");
        }
        else if (DTMFilter.SHOW_TEXT == pat.m_whatToShow)
        {
          buf.append("text()");
        }
        else if (DTMFilter.SHOW_PROCESSING_INSTRUCTION == pat.m_whatToShow)
        {
          buf.append("processing-instruction(");
  
          if (null != pat.m_name)
          {
            buf.append(pat.m_name);
          }
  
          buf.append(")");
        }
        else if (DTMFilter.SHOW_COMMENT == pat.m_whatToShow)
        {
          buf.append("comment()");
        }
        else if (null != pat.m_name)
        {
          if (DTMFilter.SHOW_ATTRIBUTE == pat.m_whatToShow)
          {
            buf.append("@");
          }
  
          if (null != pat.m_namespace)
          {
            buf.append("{");
            buf.append(pat.m_namespace);
            buf.append("}");
          }
  
          buf.append(pat.m_name);
        }
        else if (DTMFilter.SHOW_ATTRIBUTE == pat.m_whatToShow)
        {
          buf.append("@");
        }
        else if ((DTMFilter.SHOW_DOCUMENT | DTMFilter.SHOW_DOCUMENT_FRAGMENT)
                 == pat.m_whatToShow)
        {
          buf.append("doc-root()");
        }
        else
        {
          buf.append('?').append(Integer.toHexString(pat.m_whatToShow));
        }
  
        if (null != pat.m_predicates)
        {
          for (int i = 0; i < pat.m_predicates.length; i++)
          {
            buf.append("[");
            buf.append(pat.m_predicates[i]);
            buf.append("]");
          }
        }
      }
  
      return buf.toString();
    }
  
    /** Set to true to send diagnostics about pattern matches to the consol. */
    private static final boolean DEBUG_MATCHES = false;
  
    /**
     * Get the match score of the given node.
     *
     * @param xctxt The XPath runtime context.
     * @param context The node to be tested.
     *
     * @return {@link NodeTest#SCORE_NODETEST},
     *         {@link NodeTest#SCORE_NONE},
     *         {@link NodeTest#SCORE_NSWILD},
     *         {@link NodeTest#SCORE_QNAME}, or
     *         {@link NodeTest#SCORE_OTHER}.
     *
     * @throws TransformerException
     */
    public double getMatchScore(XPathContext xctxt, int context)
            throws TransformerException
    {
  
      xctxt.pushCurrentNode(context);
      xctxt.pushCurrentExpressionNode(context);
  
      try
      {
        XObject score = execute(xctxt);
  
        return score.num();
      }
      finally
      {
        xctxt.popCurrentNode();
        xctxt.popCurrentExpressionNode();
      }
  
      // return XPath.MATCH_SCORE_NONE;
    }
  
    /**
     * Set the axis that this step should follow.
     *
     *
     * @param axis The Axis for this test, one of of Axes.ANCESTORORSELF, etc.
     */
    public void setAxis(int axis)
    {
      m_axis = axis;
    }
  
    /**
     * Get the axis that this step follows.
     *
     *
     * @return The Axis for this test, one of of Axes.ANCESTORORSELF, etc.
     */
    public int getAxis()
    {
      return m_axis;
    }
  
    class PredOwner implements ExpressionOwner
    {
          int m_index;
  
          PredOwner(int index)
          {
                  m_index = index;
          }
  
      /**
       * @see ExpressionOwner#getExpression()
       */
      public Expression getExpression()
      {
        return m_predicates[m_index];
      }
  
  
      /**
       * @see ExpressionOwner#setExpression(Expression)
       */
      public void setExpression(Expression exp)
      {
          exp.exprSetParent(StepPattern.this);
          m_predicates[m_index] = exp;
      }
    }
  
    /**
     * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
     */
    public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
    {
                  if(visitor.visitMatchPattern(owner, this))
                  {
                          callSubtreeVisitors(visitor);
                  }
    }
  
    /**
     * Call the visitors on the subtree.  Factored out from callVisitors
     * so it may be called by derived classes.
     */
    protected void callSubtreeVisitors(XPathVisitor visitor)
    {
      if (null != m_predicates)
      {
        int n = m_predicates.length;
        for (int i = 0; i < n; i++)
        {
          ExpressionOwner predOwner = new PredOwner(i);
          if (visitor.visitPredicate(predOwner, m_predicates[i]))
          {
            m_predicates[i].callVisitors(predOwner, visitor);
          }
        }
      }
      if (null != m_relativePathPattern)
      {
        m_relativePathPattern.callVisitors(this, visitor);
      }
    }
  
  
    /**
     * @see ExpressionOwner#getExpression()
     */
    public Expression getExpression()
    {
      return m_relativePathPattern;
    }
  
    /**
     * @see ExpressionOwner#setExpression(Expression)
     */
    public void setExpression(Expression exp)
    {
      exp.exprSetParent(this);
          m_relativePathPattern = (StepPattern)exp;
    }
  
    /**
     * @see Expression#deepEquals(Expression)
     */
    public boolean deepEquals(Expression expr)
    {
          if(!super.deepEquals(expr))
                  return false;
  
          StepPattern sp = (StepPattern)expr;
  
      if (null != m_predicates)
      {
          int n = m_predicates.length;
          if ((null == sp.m_predicates) || (sp.m_predicates.length != n))
                return false;
          for (int i = 0; i < n; i++)
          {
            if (!m_predicates[i].deepEquals(sp.m_predicates[i]))
                  return false;
          }
      }
      else if (null != sp.m_predicates)
          return false;
  
          if(null != m_relativePathPattern)
          {
                  if(!m_relativePathPattern.deepEquals(sp.m_relativePathPattern))
                          return false;
          }
          else if(sp.m_relativePathPattern != null)
                  return false;
  
          return true;
    }
  
  
  }
  