mmidy       2002/06/27 08:01:19

  Modified:    java/src/org/apache/xpath/compiler XPathParser.java
               java/src/org/apache/xpath/res XPATHErrorResources.java
                        XPATHErrorResources.properties
  Log:
  Bugzilla 5016: Patch from Henry Zongaro... Fix XPATHParser.java to prevent matching 
empty RelativeLocationPath and Step expressions, prevent a LocationPath from preceding 
a Predicate in a FilterExpr, check for valid NameTest in NodeTest()
  
  Revision  Changes    Path
  1.21      +274 -96   xml-xalan/java/src/org/apache/xpath/compiler/XPathParser.java
  
  Index: XPathParser.java
  ===================================================================
  RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/compiler/XPathParser.java,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- XPathParser.java  6 May 2002 18:45:28 -0000       1.20
  +++ XPathParser.java  27 Jun 2002 15:01:19 -0000      1.21
  @@ -110,6 +110,13 @@
     int m_queueMark = 0;
   
     /**
  +   * Results from checking FilterExpr syntax
  +   */
  +  protected final static int FILTER_MATCH_FAILED     = 0;
  +  protected final static int FILTER_MATCH_PRIMARY    = 1;
  +  protected final static int FILTER_MATCH_PREDICATES = 2;
  +
  +  /**
      * The parser constructor.
      */
     public XPathParser(ErrorListener errorListener, javax.xml.transform.SourceLocator 
sourceLocator)
  @@ -1256,23 +1263,47 @@
     {
   
       int opPos = m_ops.m_opMap[OpMap.MAPINDEX_LENGTH];
  -    boolean foundLocationPath;
   
  -    FilterExpr();
  +    int filterExprMatch = FilterExpr();
   
  -    if (tokenIs('/'))
  +    if (filterExprMatch != FILTER_MATCH_FAILED)
       {
  -      nextToken();
  +      // If FilterExpr had Predicates, a OP_LOCATIONPATH opcode would already
  +      // have been inserted.
  +      boolean locationPathStarted = (filterExprMatch==FILTER_MATCH_PREDICATES);
  +
  +      if (tokenIs('/'))
  +      {
  +        nextToken();
  +
  +        if (!locationPathStarted)
  +        {
  +          // int locationPathOpPos = opPos;
  +          insertOp(opPos, 2, OpCodes.OP_LOCATIONPATH);
  +
  +          locationPathStarted = true;
  +        }
  +
  +        if (!RelativeLocationPath())
  +        {
  +          // "Relative location path expected following '/' or '//'"
  +          error(XPATHErrorResources.ER_EXPECTED_REL_LOC_PATH, null);
  +        }
   
  -      // int locationPathOpPos = opPos;
  -      insertOp(opPos, 2, OpCodes.OP_LOCATIONPATH);
  -      RelativeLocationPath();
  +      }
   
         // Terminate for safety.
  -      m_ops.m_opMap[m_ops.m_opMap[OpMap.MAPINDEX_LENGTH]] = OpCodes.ENDOP;
  -      m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] += 1;
  -      m_ops.m_opMap[opPos + OpMap.MAPINDEX_LENGTH] =
  -        m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - opPos;
  +      if (locationPathStarted)
  +      {
  +        m_ops.m_opMap[m_ops.m_opMap[OpMap.MAPINDEX_LENGTH]] = OpCodes.ENDOP;
  +        m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] += 1;
  +        m_ops.m_opMap[opPos + OpMap.MAPINDEX_LENGTH] =
  +          m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - opPos;
  +      }
  +    }
  +    else
  +    {
  +      LocationPath();
       }
     }
   
  @@ -1285,40 +1316,48 @@
      * @throws XSLProcessorException thrown if the active ProblemListener and 
XPathContext decide
      * the error condition is severe enough to halt processing.
      *
  +   * @return  FILTER_MATCH_PREDICATES, if this method successfully matched a
  +   *          FilterExpr with one or more Predicates;
  +   *          FILTER_MATCH_PRIMARY, if this method successfully matched a
  +   *          FilterExpr that was just a PrimaryExpr; or
  +   *          FILTER_MATCH_FAILED, if this method did not match a FilterExpr
  +   *
      * @throws javax.xml.transform.TransformerException
      */
  -  protected void FilterExpr() throws javax.xml.transform.TransformerException
  +  protected int FilterExpr() throws javax.xml.transform.TransformerException
     {
   
       int opPos = m_ops.m_opMap[OpMap.MAPINDEX_LENGTH];
   
  -    // boolean isFunc = lookahead('(', 1);
  -    PrimaryExpr();
  +    int filterMatch;
   
  -    if (tokenIs('['))
  +    if (PrimaryExpr())
       {
  +      if (tokenIs('['))
  +      {
   
  -      // int locationPathOpPos = opPos;
  -      insertOp(opPos, 2, OpCodes.OP_LOCATIONPATH);
  +        // int locationPathOpPos = opPos;
  +        insertOp(opPos, 2, OpCodes.OP_LOCATIONPATH);
   
  -      while (tokenIs('['))
  -      {
  -        Predicate();
  -      }
  +        while (tokenIs('['))
  +        {
  +          Predicate();
  +        }
   
  -      if (tokenIs('/'))
  +        filterMatch = FILTER_MATCH_PREDICATES;
  +      }
  +      else
         {
  -        nextToken();
  -        RelativeLocationPath();
  +        filterMatch = FILTER_MATCH_PRIMARY;
         }
  -
  -      // Terminate for safety.
  -      m_ops.m_opMap[m_ops.m_opMap[OpMap.MAPINDEX_LENGTH]] = OpCodes.ENDOP;
  -      m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] += 1;
  -      m_ops.m_opMap[opPos + OpMap.MAPINDEX_LENGTH] =
  -        m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - opPos;
  +    }
  +    else
  +    {
  +      filterMatch = FILTER_MATCH_FAILED;
       }
   
  +    return filterMatch;
  +
       /*
        * if(tokenIs('['))
        * {
  @@ -1336,12 +1375,15 @@
      * | Number
      * | FunctionCall
      *
  +   * @return true if this method successfully matched a PrimaryExpr
      *
      * @throws javax.xml.transform.TransformerException
  +   *
      */
  -  protected void PrimaryExpr() throws javax.xml.transform.TransformerException
  +  protected boolean PrimaryExpr() throws javax.xml.transform.TransformerException
     {
   
  +    boolean matchFound;
       int opPos = m_ops.m_opMap[OpMap.MAPINDEX_LENGTH];
   
       if ((m_tokenChar == '\'') || (m_tokenChar == '"'))
  @@ -1351,6 +1393,8 @@
   
         m_ops.m_opMap[opPos + OpMap.MAPINDEX_LENGTH] =
           m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - opPos;
  +
  +      matchFound = true;
       }
       else if (m_tokenChar == '$')
       {
  @@ -1360,6 +1404,8 @@
         
         m_ops.m_opMap[opPos + OpMap.MAPINDEX_LENGTH] =
           m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - opPos;
  +
  +      matchFound = true;
       }
       else if (m_tokenChar == '(')
       {
  @@ -1370,6 +1416,8 @@
   
         m_ops.m_opMap[opPos + OpMap.MAPINDEX_LENGTH] =
           m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - opPos;
  +
  +      matchFound = true;
       }
       else if ((null != m_token) && ((('.' == m_tokenChar) && (m_token.length() > 1) 
&& Character.isDigit(
               m_token.charAt(1))) || Character.isDigit(m_tokenChar)))
  @@ -1379,15 +1427,19 @@
   
         m_ops.m_opMap[opPos + OpMap.MAPINDEX_LENGTH] =
           m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - opPos;
  +
  +      matchFound = true;
       }
       else if (lookahead('(', 1) || (lookahead(':', 1) && lookahead('(', 3)))
       {
  -      FunctionCall();
  +      matchFound = FunctionCall();
       }
       else
       {
  -      LocationPath();
  +      matchFound = false;
       }
  +
  +    return matchFound;
     }
   
     /**
  @@ -1413,10 +1465,11 @@
      *
      * FunctionCall    ::=    FunctionName '(' ( Argument ( ',' Argument)*)? ')'
      *
  +   * @return true if, and only if, a FunctionCall was matched
      *
      * @throws javax.xml.transform.TransformerException
      */
  -  protected void FunctionCall() throws javax.xml.transform.TransformerException
  +  protected boolean FunctionCall() throws javax.xml.transform.TransformerException
     {
   
       int opPos = m_ops.m_opMap[OpMap.MAPINDEX_LENGTH];
  @@ -1450,9 +1503,8 @@
         case OpCodes.NODETYPE_COMMENT :
         case OpCodes.NODETYPE_TEXT :
         case OpCodes.NODETYPE_NODE :
  -        LocationPath();
  -
  -        return;
  +        // Node type tests look like function calls, but they're not
  +        return false;
         default :
           appendOp(3, OpCodes.OP_FUNCTION);
   
  @@ -1492,6 +1544,8 @@
       m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] += 1;
       m_ops.m_opMap[opPos + OpMap.MAPINDEX_LENGTH] =
         m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - opPos;
  +
  +    return true;
     }
   
     // ============= GRAMMAR FUNCTIONS =================
  @@ -1512,7 +1566,9 @@
       // int locationPathOpPos = opPos;
       appendOp(2, OpCodes.OP_LOCATIONPATH);
   
  -    if (tokenIs('/'))
  +    boolean seenSlash = tokenIs('/');
  +
  +    if (seenSlash)
       {
         appendOp(4, OpCodes.FROM_ROOT);
   
  @@ -1526,7 +1582,13 @@
   
       if (m_token != null)
       {
  -      RelativeLocationPath();
  +      if (!RelativeLocationPath() && !seenSlash)
  +      {
  +        // Neither a '/' nor a RelativeLocationPath - i.e., matched nothing
  +        // "Location path expected, but found "+m_token+" was encountered."
  +        error(XPATHErrorResources.ER_EXPECTED_LOC_PATH, 
  +              new Object [] {m_token});
  +      }
       }
   
       // Terminate for safety.
  @@ -1542,19 +1604,31 @@
      * | RelativeLocationPath '/' Step
      * | AbbreviatedRelativeLocationPath
      *
  +   * @returns true if, and only if, a RelativeLocationPath was matched
      *
      * @throws javax.xml.transform.TransformerException
      */
  -  protected void RelativeLocationPath() throws 
javax.xml.transform.TransformerException
  +  protected boolean RelativeLocationPath()
  +               throws javax.xml.transform.TransformerException
     {
  -
  -    Step();
  +    if (!Step())
  +    {
  +      return false;
  +    }
   
       while (tokenIs('/'))
       {
         nextToken();
  -      Step();
  +
  +      if (!Step())
  +      {
  +        // RelativeLocationPath can't end with a trailing '/'
  +        // "Location step expected following '/' or '//'"
  +        error(XPATHErrorResources.ER_EXPECTED_LOC_STEP, null);
  +      }
       }
  +
  +    return true;
     }
   
     /**
  @@ -1562,13 +1636,47 @@
      * Step    ::=    Basis Predicate
      * | AbbreviatedStep
      *
  +   * @returns false if step was empty (or only a '/'); true, otherwise
  +   *
      * @throws javax.xml.transform.TransformerException
      */
  -  protected void Step() throws javax.xml.transform.TransformerException
  +  protected boolean Step() throws javax.xml.transform.TransformerException
     {
  -
       int opPos = m_ops.m_opMap[OpMap.MAPINDEX_LENGTH];
   
  +    boolean doubleSlash = tokenIs('/');
  +
  +    // At most a single '/' before each Step is consumed by caller; if the
  +    // first thing is a '/', that means we had '//' and the Step must not
  +    // be empty.
  +    if (doubleSlash)
  +    {
  +      nextToken();
  +
  +      appendOp(2, OpCodes.FROM_DESCENDANTS_OR_SELF);
  +
  +      // Have to fix up for patterns such as '//@foo' or '//attribute::foo',
  +      // which translate to 'descendant-or-self::node()/attribute::foo'.
  +      // notice I leave the '/' on the queue, so the next will be processed
  +      // by a regular step pattern.
  +
  +      // Make room for telling how long the step is without the predicate
  +      m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] += 1;
  +      m_ops.m_opMap[m_ops.m_opMap[OpMap.MAPINDEX_LENGTH]] =
  +        OpCodes.NODETYPE_NODE;
  +      m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] += 1;
  +
  +      // Tell how long the step is without the predicate
  +      m_ops.m_opMap[opPos + OpMap.MAPINDEX_LENGTH + 1] =
  +          m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - opPos;
  +
  +      // Tell how long the step is with the predicate
  +      m_ops.m_opMap[opPos + OpMap.MAPINDEX_LENGTH] =
  +          m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - opPos;
  +
  +      opPos = m_ops.m_opMap[OpMap.MAPINDEX_LENGTH];
  +    }
  +
       if (tokenIs("."))
       {
         nextToken();
  @@ -1599,8 +1707,8 @@
       // There is probably a better way to test for this 
       // transition... but it gets real hairy if you try 
       // to do it in basis().
  -    else if (tokenIs('*') || tokenIs('@') || tokenIs('/')
  -             || tokenIs('_') || (m_token!= null && 
Character.isLetter(m_token.charAt(0))))
  +    else if (tokenIs('*') || tokenIs('@') || tokenIs('_')
  +             || (m_token!= null && Character.isLetter(m_token.charAt(0))))
       {
         Basis();
   
  @@ -1613,6 +1721,19 @@
         m_ops.m_opMap[opPos + OpMap.MAPINDEX_LENGTH] =
           m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - opPos;
       }
  +    else
  +    {
  +      // No Step matched - that's an error if previous thing was a '//'
  +      if (doubleSlash)
  +      {
  +        // "Location step expected following '/' or '//'"
  +        error(XPATHErrorResources.ER_EXPECTED_LOC_STEP, null);
  +      }
  +
  +      return false;
  +    }
  +
  +    return true;
     }
   
     /**
  @@ -1643,37 +1764,6 @@
         appendOp(2, axesType);
         nextToken();
       }
  -    else if (tokenIs('/'))
  -    {
  -      axesType = OpCodes.FROM_DESCENDANTS_OR_SELF;
  -
  -      appendOp(2, axesType);
  -
  -      // Have to fix up for patterns such as '//@foo' or '//attribute::foo',
  -      // which translate to 'descendant-or-self::node()/attribute::foo'.
  -      // notice I leave the '/' on the queue, so the next will be processed
  -      // by a regular step pattern.
  -      // if(lookahead('@', 1) || lookahead("::", 2))
  -      {
  -
  -        // Make room for telling how long the step is without the predicate
  -        m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] += 1;
  -        m_ops.m_opMap[m_ops.m_opMap[OpMap.MAPINDEX_LENGTH]] =
  -          OpCodes.NODETYPE_NODE;
  -        m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] += 1;
  -
  -        // Tell how long the step is without the predicate
  -        m_ops.m_opMap[opPos + OpMap.MAPINDEX_LENGTH + 1] =
  -          m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - opPos;
  -
  -        return;  // make a quick exit...
  -      }
  -
  -      // else
  -      // {
  -      //  nextToken();
  -      // }
  -    }
       else
       {
         axesType = OpCodes.FROM_CHILDREN;
  @@ -1780,6 +1870,14 @@
           {
             m_ops.m_opMap[m_ops.m_opMap[OpMap.MAPINDEX_LENGTH]] = m_queueMark
                     - 1;
  +
  +          // Minimalist check for an NCName - just check first character
  +          // to distinguish from other possible tokens
  +          if (!Character.isLetter(m_tokenChar) && !tokenIs('_'))
  +          {
  +            // "Node test that matches either NCName:* or QName was expected."
  +            error(XPATHErrorResources.ER_EXPECTED_NODE_TEST, null);
  +          }
           }
   
           nextToken();
  @@ -1810,6 +1908,14 @@
           }
   
           m_ops.m_opMap[m_ops.m_opMap[OpMap.MAPINDEX_LENGTH]] = m_queueMark - 1;
  +
  +        // Minimalist check for an NCName - just check first character
  +        // to distinguish from other possible tokens
  +        if (!Character.isLetter(m_tokenChar) && !tokenIs('_'))
  +        {
  +          // "Node test that matches either NCName:* or QName was expected."
  +          error(XPATHErrorResources.ER_EXPECTED_NODE_TEST, null);
  +        }
         }
   
         m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] += 1;
  @@ -2025,6 +2131,12 @@
   
       int opPos = m_ops.m_opMap[OpMap.MAPINDEX_LENGTH];
   
  +    final int RELATIVE_PATH_NOT_PERMITTED = 0;
  +    final int RELATIVE_PATH_PERMITTED     = 1;
  +    final int RELATIVE_PATH_REQUIRED      = 2;
  +
  +    int relativePathStatus = RELATIVE_PATH_NOT_PERMITTED;
  +
       appendOp(2, OpCodes.OP_LOCATIONPATHPATTERN);
   
       if (lookahead('(', 1)
  @@ -2033,17 +2145,27 @@
       {
         IdKeyPattern();
   
  -      if (tokenIs('/') && lookahead('/', 1))
  +      if (tokenIs('/'))
         {
  -        appendOp(4, OpCodes.MATCH_ANY_ANCESTOR);
  +        nextToken();
  +
  +        if (tokenIs('/'))
  +        {
  +          appendOp(4, OpCodes.MATCH_ANY_ANCESTOR);
  +
  +          nextToken();
  +        }
  +        else
  +        {
  +          appendOp(4, OpCodes.MATCH_IMMEDIATE_ANCESTOR);
  +        }
   
           // Tell how long the step is without the predicate
           m_ops.m_opMap[m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - 2] = 4;
           m_ops.m_opMap[m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - 1] =
             OpCodes.NODETYPE_FUNCTEST;
   
  -        nextToken();
  -        nextToken();
  +        relativePathStatus = RELATIVE_PATH_REQUIRED;
         }
       }
       else if (tokenIs('/'))
  @@ -2057,12 +2179,17 @@
           // of a '//' pattern, and so will cause 'a' to be matched when it has
           // any ancestor that is 'x'.
           nextToken();
  +
  +        relativePathStatus = RELATIVE_PATH_REQUIRED;
         }
         else
         {
           appendOp(4, OpCodes.FROM_ROOT);
  +
  +        relativePathStatus = RELATIVE_PATH_PERMITTED;
         }
   
  +
         // Tell how long the step is without the predicate
         m_ops.m_opMap[m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - 2] = 4;
         m_ops.m_opMap[m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - 1] =
  @@ -2070,10 +2197,22 @@
   
         nextToken();
       }
  +    else
  +    {
  +      relativePathStatus = RELATIVE_PATH_REQUIRED;
  +    }
   
  -    if (!tokenIs('|') && (null != m_token))
  +    if (relativePathStatus != RELATIVE_PATH_NOT_PERMITTED)
       {
  -      RelativePathPattern();
  +      if (!tokenIs('|') && (null != m_token))
  +      {
  +        RelativePathPattern();
  +      }
  +      else if (relativePathStatus == RELATIVE_PATH_REQUIRED)
  +      {
  +        // "A relative path pattern was expected."
  +        error(XPATHErrorResources.ER_EXPECTED_REL_PATH_PATTERN, null);
  +      }
       }
   
       // Terminate for safety.
  @@ -2103,18 +2242,24 @@
      * | RelativePathPattern '/' StepPattern
      * | RelativePathPattern '//' StepPattern
      *
  -   *
      * @throws javax.xml.transform.TransformerException
      */
  -  protected void RelativePathPattern() throws 
javax.xml.transform.TransformerException
  +  protected void RelativePathPattern()
  +              throws javax.xml.transform.TransformerException
     {
   
  -    StepPattern();
  +    // Caller will have consumed any '/' or '//' preceding the
  +    // RelativePathPattern, so let StepPattern know it can't begin with a '/'
  +    boolean trailingSlashConsumed = StepPattern(false);
   
       while (tokenIs('/'))
       {
         nextToken();
  -      StepPattern();
  +
  +      // StepPattern() may consume first slash of pair in "a//b" while
  +      // processing StepPattern "a".  On next iteration, let StepPattern know
  +      // that happened, so it doesn't match ill-formed patterns like "a///b".
  +      trailingSlashConsumed = StepPattern(!trailingSlashConsumed);
       }
     }
   
  @@ -2122,22 +2267,32 @@
      *
      * StepPattern  ::=  AbbreviatedNodeTestStep
      *
  +   * @param isLeadingSlashPermitted a boolean indicating whether a slash can
  +   *        appear at the start of this step
  +   *
  +   * @return boolean indicating whether a slash following the step was consumed
      *
      * @throws javax.xml.transform.TransformerException
      */
  -  protected void StepPattern() throws javax.xml.transform.TransformerException
  +  protected boolean StepPattern(boolean isLeadingSlashPermitted)
  +            throws javax.xml.transform.TransformerException
     {
  -    AbbreviatedNodeTestStep();
  +    return AbbreviatedNodeTestStep(isLeadingSlashPermitted);
     }
   
     /**
      *
      * AbbreviatedNodeTestStep    ::=    '@'? NodeTest Predicate
      *
  +   * @param isLeadingSlashPermitted a boolean indicating whether a slash can
  +   *        appear at the start of this step
  +   *
  +   * @return boolean indicating whether a slash following the step was consumed
      *
      * @throws javax.xml.transform.TransformerException
      */
  -  protected void AbbreviatedNodeTestStep() throws 
javax.xml.transform.TransformerException
  +  protected boolean AbbreviatedNodeTestStep(boolean isLeadingSlashPermitted)
  +            throws javax.xml.transform.TransformerException
     {
   
       int opPos = m_ops.m_opMap[OpMap.MAPINDEX_LENGTH];
  @@ -2163,6 +2318,7 @@
         }
         else if (tokenIs("child"))
         {
  +        matchTypePos = m_ops.m_opMap[OpMap.MAPINDEX_LENGTH];
           axesType = OpCodes.MATCH_IMMEDIATE_ANCESTOR;
   
           appendOp(2, axesType);
  @@ -2180,6 +2336,11 @@
       }
       else if (tokenIs('/'))
       {
  +      if (!isLeadingSlashPermitted)
  +      {
  +        // "A step was expected in the pattern, but '/' was encountered."
  +        error(XPATHErrorResources.ER_EXPECTED_STEP_PATTERN, null);
  +      }
         axesType = OpCodes.MATCH_ANY_ANCESTOR;
   
         appendOp(2, axesType);
  @@ -2187,11 +2348,6 @@
       }
       else
       {
  -      if (tokenIs('/'))
  -      {
  -        nextToken();
  -      }
  -
         matchTypePos = m_ops.m_opMap[OpMap.MAPINDEX_LENGTH];
         axesType = OpCodes.MATCH_IMMEDIATE_ANCESTOR;
   
  @@ -2212,15 +2368,37 @@
         Predicate();
       }
   
  +    boolean trailingSlashConsumed;
  +
  +    // For "a//b", where "a" is current step, we need to mark operation of
  +    // current step as "MATCH_ANY_ANCESTOR".  Then we'll consume the first
  +    // slash and subsequent step will be treated as a MATCH_IMMEDIATE_ANCESTOR
  +    // (unless it too is followed by '//'.)
  +    //
  +    // %REVIEW%  Following is what happens today, but I'm not sure that's
  +    // %REVIEW%  correct behaviour.  Perhaps no valid case could be constructed
  +    // %REVIEW%  where it would matter?
  +    //
  +    // If current step is on the attribute axis (e.g., "@x//b"), we won't
  +    // change the current step, and let following step be marked as
  +    // MATCH_ANY_ANCESTOR on next call instead.
       if ((matchTypePos > -1) && tokenIs('/') && lookahead('/', 1))
       {
         m_ops.m_opMap[matchTypePos] = OpCodes.MATCH_ANY_ANCESTOR;
   
         nextToken();
  +
  +      trailingSlashConsumed = true;
  +    }
  +    else
  +    {
  +      trailingSlashConsumed = false;
       }
   
       // Tell how long the entire step is.
       m_ops.m_opMap[opPos + OpMap.MAPINDEX_LENGTH] =
         m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - opPos;
  +
  +    return trailingSlashConsumed;
     }
   }
  
  
  
  1.15      +24 -0     xml-xalan/java/src/org/apache/xpath/res/XPATHErrorResources.java
  
  Index: XPATHErrorResources.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xpath/res/XPATHErrorResources.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- XPATHErrorResources.java  26 Jun 2002 15:17:38 -0000      1.14
  +++ XPATHErrorResources.java  27 Jun 2002 15:01:19 -0000      1.15
  @@ -491,6 +491,30 @@
     
     // Programmer's assertion in getNextStepPos: unknown stepType: {0}
     public static final int ER_UNKNOWN_STEP = 94;
  +  
  +  /** Problem with RelativeLocationPath */
  +  public static final int ER_EXPECTED_REL_LOC_PATH = 95;
  +
  +
  +   /** Problem with LocationPath */
  +  public static final int ER_EXPECTED_LOC_PATH = 96;
  +
  +
  +   /** Problem with Step */
  +  public static final int ER_EXPECTED_LOC_STEP = 97;
  +
  +
  +   /** Problem with NodeTest */
  +  public static final int ER_EXPECTED_NODE_TEST = 98;
  +
  +
  +   /** Expected step pattern */
  +  public static final int ER_EXPECTED_STEP_PATTERN = 99;
  +
  +  
  +   /** Expected relative path pattern */
  +  public static final int ER_EXPECTED_REL_PATH_PATTERN = 100;
  + 
   
   
   
  
  
  
  1.5       +12 -0     
xml-xalan/java/src/org/apache/xpath/res/XPATHErrorResources.properties
  
  Index: XPATHErrorResources.properties
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xpath/res/XPATHErrorResources.properties,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- XPATHErrorResources.properties    26 Jun 2002 15:17:38 -0000      1.4
  +++ XPATHErrorResources.properties    27 Jun 2002 15:01:19 -0000      1.5
  @@ -194,6 +194,18 @@
   ER0093={0} only allows {1} arguments
   # ER_UNKNOWN_STEP
   ER0094=Programmer's assertion in getNextStepPos: unknown stepType: {0}
  +# ER_EXPECTED_REL_LOC_PATH
  +ER0095=A relative location path was expected following the '/' or '//' token.
  +# ER_EXPECTED_LOC_PATH
  +ER0096=A location path was expected, but the following token was encountered\u003a  
{0}
  +# ER_EXPECTED_LOC_STEP
  +ER0097=A location step was expected following the '/' or '//' token.
  +# ER_EXPECTED_NODE_TEST
  +ER0098=A node test that matches either NCName:* or QName was expected.
  +# ER_EXPECTED_STEP_PATTERN
  +ER0099=A step pattern was expected, but '/' was encountered.
  +# ER_EXPECTED_REL_PATH_PATTERN
  +ER00100=A relative path pattern was expected.
   
   
   
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to