Home | History | Annotate | Download | only in compiler
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one
      3  * or more contributor license agreements. See the NOTICE file
      4  * distributed with this work for additional information
      5  * regarding copyright ownership. The ASF licenses this file
      6  * to you under the Apache License, Version 2.0 (the  "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  */
     18 /*
     19  * $Id: OpMap.java 468655 2006-10-28 07:12:06Z minchau $
     20  */
     21 package org.apache.xpath.compiler;
     22 
     23 import org.apache.xalan.res.XSLMessages;
     24 import org.apache.xml.utils.ObjectVector;
     25 import org.apache.xpath.patterns.NodeTest;
     26 import org.apache.xpath.res.XPATHErrorResources;
     27 
     28 /**
     29  * This class represents the data structure basics of the XPath
     30  * object.
     31  */
     32 public class OpMap
     33 {
     34 
     35   /**
     36    * The current pattern string, for diagnostics purposes
     37    */
     38   protected String m_currentPattern;
     39 
     40   /**
     41    * Return the expression as a string for diagnostics.
     42    *
     43    * @return The expression string.
     44    */
     45   public String toString()
     46   {
     47     return m_currentPattern;
     48   }
     49 
     50   /**
     51    * Return the expression as a string for diagnostics.
     52    *
     53    * @return The expression string.
     54    */
     55   public String getPatternString()
     56   {
     57     return m_currentPattern;
     58   }
     59 
     60   /**
     61    * The starting size of the token queue.
     62    */
     63   static final int MAXTOKENQUEUESIZE = 500;
     64 
     65   /*
     66    * Amount to grow token queue when it becomes full
     67    */
     68   static final int BLOCKTOKENQUEUESIZE = 500;
     69 
     70   /**
     71    *  TokenStack is the queue of used tokens. The current token is the token at the
     72    * end of the m_tokenQueue. The idea is that the queue can be marked and a sequence
     73    * of tokens can be reused.
     74    */
     75   ObjectVector m_tokenQueue = new ObjectVector(MAXTOKENQUEUESIZE, BLOCKTOKENQUEUESIZE);
     76 
     77   /**
     78    * Get the XPath as a list of tokens.
     79    *
     80    * @return ObjectVector of tokens.
     81    */
     82   public ObjectVector getTokenQueue()
     83   {
     84     return m_tokenQueue;
     85   }
     86 
     87   /**
     88    * Get the XPath as a list of tokens.
     89    *
     90    * @param pos index into token queue.
     91    *
     92    * @return The token, normally a string.
     93    */
     94   public Object getToken(int pos)
     95   {
     96     return m_tokenQueue.elementAt(pos);
     97   }
     98 
     99   /**
    100    * The current size of the token queue.
    101    */
    102 //  public int m_tokenQueueSize = 0;
    103 
    104   /**
    105     * Get size of the token queue.
    106    *
    107    * @return The size of the token queue.
    108    */
    109   public int getTokenQueueSize()
    110   {
    111     return m_tokenQueue.size();
    112 
    113   }
    114 
    115   /**
    116    * An operations map is used instead of a proper parse tree.  It contains
    117    * operations codes and indexes into the m_tokenQueue.
    118    * I use an array instead of a full parse tree in order to cut down
    119    * on the number of objects created.
    120    */
    121   OpMapVector m_opMap = null;
    122 
    123   /**
    124     * Get the opcode list that describes the XPath operations.  It contains
    125    * operations codes and indexes into the m_tokenQueue.
    126    * I use an array instead of a full parse tree in order to cut down
    127    * on the number of objects created.
    128    *
    129    * @return An IntVector that is the opcode list that describes the XPath operations.
    130    */
    131   public OpMapVector getOpMap()
    132   {
    133     return m_opMap;
    134   }
    135 
    136   // Position indexes
    137 
    138   /**
    139    * The length is always the opcode position + 1.
    140    * Length is always expressed as the opcode+length bytes,
    141    * so it is always 2 or greater.
    142    */
    143   public static final int MAPINDEX_LENGTH = 1;
    144 
    145   /**
    146    * Replace the large arrays
    147    * with a small array.
    148    */
    149   void shrink()
    150   {
    151 
    152     int n = m_opMap.elementAt(MAPINDEX_LENGTH);
    153     m_opMap.setToSize(n + 4);
    154 
    155     m_opMap.setElementAt(0,n);
    156     m_opMap.setElementAt(0,n+1);
    157     m_opMap.setElementAt(0,n+2);
    158 
    159 
    160     n = m_tokenQueue.size();
    161     m_tokenQueue.setToSize(n + 4);
    162 
    163     m_tokenQueue.setElementAt(null,n);
    164     m_tokenQueue.setElementAt(null,n + 1);
    165     m_tokenQueue.setElementAt(null,n + 2);
    166   }
    167 
    168   /**
    169   * Given an operation position, return the current op.
    170    *
    171    * @param opPos index into op map.
    172    * @return the op that corresponds to the opPos argument.
    173    */
    174   public int getOp(int opPos)
    175   {
    176     return m_opMap.elementAt(opPos);
    177   }
    178 
    179   /**
    180   * Set the op at index to the given int.
    181    *
    182    * @param opPos index into op map.
    183    * @param value Value to set
    184    */
    185   public void setOp(int opPos, int value)
    186   {
    187      m_opMap.setElementAt(value,opPos);
    188   }
    189 
    190   /**
    191    * Given an operation position, return the end position, i.e. the
    192    * beginning of the next operation.
    193    *
    194    * @param opPos An op position of an operation for which there is a size
    195    *              entry following.
    196    * @return position of next operation in m_opMap.
    197    */
    198   public int getNextOpPos(int opPos)
    199   {
    200     return opPos + m_opMap.elementAt(opPos + 1);
    201   }
    202 
    203   /**
    204    * Given a location step position, return the end position, i.e. the
    205    * beginning of the next step.
    206    *
    207    * @param opPos the position of a location step.
    208    * @return the position of the next location step.
    209    */
    210   public int getNextStepPos(int opPos)
    211   {
    212 
    213     int stepType = getOp(opPos);
    214 
    215     if ((stepType >= OpCodes.AXES_START_TYPES)
    216             && (stepType <= OpCodes.AXES_END_TYPES))
    217     {
    218       return getNextOpPos(opPos);
    219     }
    220     else if ((stepType >= OpCodes.FIRST_NODESET_OP)
    221              && (stepType <= OpCodes.LAST_NODESET_OP))
    222     {
    223       int newOpPos = getNextOpPos(opPos);
    224 
    225       while (OpCodes.OP_PREDICATE == getOp(newOpPos))
    226       {
    227         newOpPos = getNextOpPos(newOpPos);
    228       }
    229 
    230       stepType = getOp(newOpPos);
    231 
    232       if (!((stepType >= OpCodes.AXES_START_TYPES)
    233             && (stepType <= OpCodes.AXES_END_TYPES)))
    234       {
    235         return OpCodes.ENDOP;
    236       }
    237 
    238       return newOpPos;
    239     }
    240     else
    241     {
    242       throw new RuntimeException(
    243         XSLMessages.createXPATHMessage(XPATHErrorResources.ER_UNKNOWN_STEP, new Object[]{String.valueOf(stepType)}));
    244       //"Programmer's assertion in getNextStepPos: unknown stepType: " + stepType);
    245     }
    246   }
    247 
    248   /**
    249    * Given an operation position, return the end position, i.e. the
    250    * beginning of the next operation.
    251    *
    252    * @param opMap The operations map.
    253    * @param opPos index to operation, for which there is a size entry following.
    254    * @return position of next operation in m_opMap.
    255    */
    256   public static int getNextOpPos(int[] opMap, int opPos)
    257   {
    258     return opPos + opMap[opPos + 1];
    259   }
    260 
    261   /**
    262    * Given an FROM_stepType position, return the position of the
    263    * first predicate, if there is one, or else this will point
    264    * to the end of the FROM_stepType.
    265    * Example:
    266    *  int posOfPredicate = xpath.getNextOpPos(stepPos);
    267    *  boolean hasPredicates =
    268    *            OpCodes.OP_PREDICATE == xpath.getOp(posOfPredicate);
    269    *
    270    * @param opPos position of FROM_stepType op.
    271    * @return position of predicate in FROM_stepType structure.
    272    */
    273   public int getFirstPredicateOpPos(int opPos)
    274      throws javax.xml.transform.TransformerException
    275   {
    276 
    277     int stepType = m_opMap.elementAt(opPos);
    278 
    279     if ((stepType >= OpCodes.AXES_START_TYPES)
    280             && (stepType <= OpCodes.AXES_END_TYPES))
    281     {
    282       return opPos + m_opMap.elementAt(opPos + 2);
    283     }
    284     else if ((stepType >= OpCodes.FIRST_NODESET_OP)
    285              && (stepType <= OpCodes.LAST_NODESET_OP))
    286     {
    287       return opPos + m_opMap.elementAt(opPos + 1);
    288     }
    289     else if(-2 == stepType)
    290     {
    291       return -2;
    292     }
    293     else
    294     {
    295       error(org.apache.xpath.res.XPATHErrorResources.ER_UNKNOWN_OPCODE,
    296             new Object[]{ String.valueOf(stepType) });  //"ERROR! Unknown op code: "+m_opMap[opPos]);
    297       return -1;
    298     }
    299   }
    300 
    301   /**
    302    * Tell the user of an error, and probably throw an
    303    * exception.
    304    *
    305    * @param msg An error msgkey that corresponds to one of the constants found
    306    *            in {@link org.apache.xpath.res.XPATHErrorResources}, which is
    307    *            a key for a format string.
    308    * @param args An array of arguments represented in the format string, which
    309    *             may be null.
    310    *
    311    * @throws TransformerException if the current ErrorListoner determines to
    312    *                              throw an exception.
    313    */
    314   public void error(String msg, Object[] args) throws javax.xml.transform.TransformerException
    315   {
    316 
    317     java.lang.String fmsg = org.apache.xalan.res.XSLMessages.createXPATHMessage(msg, args);
    318 
    319 
    320     throw new javax.xml.transform.TransformerException(fmsg);
    321   }
    322 
    323 
    324   /**
    325    * Go to the first child of a given operation.
    326    *
    327    * @param opPos position of operation.
    328    *
    329    * @return The position of the first child of the operation.
    330    */
    331   public static int getFirstChildPos(int opPos)
    332   {
    333     return opPos + 2;
    334   }
    335 
    336   /**
    337    * Get the length of an operation.
    338    *
    339    * @param opPos The position of the operation in the op map.
    340    *
    341    * @return The size of the operation.
    342    */
    343   public int getArgLength(int opPos)
    344   {
    345     return m_opMap.elementAt(opPos + MAPINDEX_LENGTH);
    346   }
    347 
    348   /**
    349    * Given a location step, get the length of that step.
    350    *
    351    * @param opPos Position of location step in op map.
    352    *
    353    * @return The length of the step.
    354    */
    355   public int getArgLengthOfStep(int opPos)
    356   {
    357     return m_opMap.elementAt(opPos + MAPINDEX_LENGTH + 1) - 3;
    358   }
    359 
    360   /**
    361    * Get the first child position of a given location step.
    362    *
    363    * @param opPos Position of location step in the location map.
    364    *
    365    * @return The first child position of the step.
    366    */
    367   public static int getFirstChildPosOfStep(int opPos)
    368   {
    369     return opPos + 3;
    370   }
    371 
    372   /**
    373    * Get the test type of the step, i.e. NODETYPE_XXX value.
    374    *
    375    * @param opPosOfStep The position of the FROM_XXX step.
    376    *
    377    * @return NODETYPE_XXX value.
    378    */
    379   public int getStepTestType(int opPosOfStep)
    380   {
    381     return m_opMap.elementAt(opPosOfStep + 3);  // skip past op, len, len without predicates
    382   }
    383 
    384   /**
    385    * Get the namespace of the step.
    386    *
    387    * @param opPosOfStep The position of the FROM_XXX step.
    388    *
    389    * @return The step's namespace, NodeTest.WILD, or null for null namespace.
    390    */
    391   public String getStepNS(int opPosOfStep)
    392   {
    393 
    394     int argLenOfStep = getArgLengthOfStep(opPosOfStep);
    395 
    396     // System.out.println("getStepNS.argLenOfStep: "+argLenOfStep);
    397     if (argLenOfStep == 3)
    398     {
    399       int index = m_opMap.elementAt(opPosOfStep + 4);
    400 
    401       if (index >= 0)
    402         return (String) m_tokenQueue.elementAt(index);
    403       else if (OpCodes.ELEMWILDCARD == index)
    404         return NodeTest.WILD;
    405       else
    406         return null;
    407     }
    408     else
    409       return null;
    410   }
    411 
    412   /**
    413    * Get the local name of the step.
    414    * @param opPosOfStep The position of the FROM_XXX step.
    415    *
    416    * @return OpCodes.EMPTY, OpCodes.ELEMWILDCARD, or the local name.
    417    */
    418   public String getStepLocalName(int opPosOfStep)
    419   {
    420 
    421     int argLenOfStep = getArgLengthOfStep(opPosOfStep);
    422 
    423     // System.out.println("getStepLocalName.argLenOfStep: "+argLenOfStep);
    424     int index;
    425 
    426     switch (argLenOfStep)
    427     {
    428     case 0 :
    429       index = OpCodes.EMPTY;
    430       break;
    431     case 1 :
    432       index = OpCodes.ELEMWILDCARD;
    433       break;
    434     case 2 :
    435       index = m_opMap.elementAt(opPosOfStep + 4);
    436       break;
    437     case 3 :
    438       index = m_opMap.elementAt(opPosOfStep + 5);
    439       break;
    440     default :
    441       index = OpCodes.EMPTY;
    442       break;  // Should assert error
    443     }
    444 
    445     // int index = (argLenOfStep == 3) ? m_opMap[opPosOfStep+5]
    446     //                                  : ((argLenOfStep == 1) ? -3 : -2);
    447     if (index >= 0)
    448       return (String) m_tokenQueue.elementAt(index).toString();
    449     else if (OpCodes.ELEMWILDCARD == index)
    450       return NodeTest.WILD;
    451     else
    452       return null;
    453   }
    454 
    455 }
    456