/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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: OpMap.java 468655 2006-10-28 07:12:06Z minchau $
 */
package org.apache.xpath.compiler;

import org.apache.xalan.res.XSLMessages;
import org.apache.xml.utils.ObjectVector;
import org.apache.xpath.patterns.NodeTest;
import org.apache.xpath.res.XPATHErrorResources;

This class represents the data structure basics of the XPath object.
/** * This class represents the data structure basics of the XPath * object. */
public class OpMap {
The current pattern string, for diagnostics purposes
/** * The current pattern string, for diagnostics purposes */
protected String m_currentPattern;
Return the expression as a string for diagnostics.
Returns:The expression string.
/** * Return the expression as a string for diagnostics. * * @return The expression string. */
public String toString() { return m_currentPattern; }
Return the expression as a string for diagnostics.
Returns:The expression string.
/** * Return the expression as a string for diagnostics. * * @return The expression string. */
public String getPatternString() { return m_currentPattern; }
The starting size of the token queue.
/** * The starting size of the token queue. */
static final int MAXTOKENQUEUESIZE = 500; /* * Amount to grow token queue when it becomes full */ static final int BLOCKTOKENQUEUESIZE = 500;
TokenStack is the queue of used tokens. The current token is the token at the end of the m_tokenQueue. The idea is that the queue can be marked and a sequence of tokens can be reused.
/** * TokenStack is the queue of used tokens. The current token is the token at the * end of the m_tokenQueue. The idea is that the queue can be marked and a sequence * of tokens can be reused. */
ObjectVector m_tokenQueue = new ObjectVector(MAXTOKENQUEUESIZE, BLOCKTOKENQUEUESIZE);
Get the XPath as a list of tokens.
Returns:ObjectVector of tokens.
/** * Get the XPath as a list of tokens. * * @return ObjectVector of tokens. */
public ObjectVector getTokenQueue() { return m_tokenQueue; }
Get the XPath as a list of tokens.
Params:
  • pos – index into token queue.
Returns:The token, normally a string.
/** * Get the XPath as a list of tokens. * * @param pos index into token queue. * * @return The token, normally a string. */
public Object getToken(int pos) { return m_tokenQueue.elementAt(pos); } /** * The current size of the token queue. */ // public int m_tokenQueueSize = 0;
Get size of the token queue.
Returns:The size of the token queue.
/** * Get size of the token queue. * * @return The size of the token queue. */
public int getTokenQueueSize() { return m_tokenQueue.size(); }
An operations map is used instead of a proper parse tree. It contains operations codes and indexes into the m_tokenQueue. I use an array instead of a full parse tree in order to cut down on the number of objects created.
/** * An operations map is used instead of a proper parse tree. It contains * operations codes and indexes into the m_tokenQueue. * I use an array instead of a full parse tree in order to cut down * on the number of objects created. */
OpMapVector m_opMap = null;
Get the opcode list that describes the XPath operations. It contains operations codes and indexes into the m_tokenQueue. I use an array instead of a full parse tree in order to cut down on the number of objects created.
Returns:An IntVector that is the opcode list that describes the XPath operations.
/** * Get the opcode list that describes the XPath operations. It contains * operations codes and indexes into the m_tokenQueue. * I use an array instead of a full parse tree in order to cut down * on the number of objects created. * * @return An IntVector that is the opcode list that describes the XPath operations. */
public OpMapVector getOpMap() { return m_opMap; } // Position indexes
The length is always the opcode position + 1. Length is always expressed as the opcode+length bytes, so it is always 2 or greater.
/** * The length is always the opcode position + 1. * Length is always expressed as the opcode+length bytes, * so it is always 2 or greater. */
public static final int MAPINDEX_LENGTH = 1;
Replace the large arrays with a small array.
/** * Replace the large arrays * with a small array. */
void shrink() { int n = m_opMap.elementAt(MAPINDEX_LENGTH); m_opMap.setToSize(n + 4); m_opMap.setElementAt(0,n); m_opMap.setElementAt(0,n+1); m_opMap.setElementAt(0,n+2); n = m_tokenQueue.size(); m_tokenQueue.setToSize(n + 4); m_tokenQueue.setElementAt(null,n); m_tokenQueue.setElementAt(null,n + 1); m_tokenQueue.setElementAt(null,n + 2); }
Given an operation position, return the current op.
Params:
  • opPos – index into op map.
Returns:the op that corresponds to the opPos argument.
/** * Given an operation position, return the current op. * * @param opPos index into op map. * @return the op that corresponds to the opPos argument. */
public int getOp(int opPos) { return m_opMap.elementAt(opPos); }
Set the op at index to the given int.
Params:
  • opPos – index into op map.
  • value – Value to set
/** * Set the op at index to the given int. * * @param opPos index into op map. * @param value Value to set */
public void setOp(int opPos, int value) { m_opMap.setElementAt(value,opPos); }
Given an operation position, return the end position, i.e. the beginning of the next operation.
Params:
  • opPos – An op position of an operation for which there is a size entry following.
Returns:position of next operation in m_opMap.
/** * Given an operation position, return the end position, i.e. the * beginning of the next operation. * * @param opPos An op position of an operation for which there is a size * entry following. * @return position of next operation in m_opMap. */
public int getNextOpPos(int opPos) { return opPos + m_opMap.elementAt(opPos + 1); }
Given a location step position, return the end position, i.e. the beginning of the next step.
Params:
  • opPos – the position of a location step.
Returns:the position of the next location step.
/** * Given a location step position, return the end position, i.e. the * beginning of the next step. * * @param opPos the position of a location step. * @return the position of the next location step. */
public int getNextStepPos(int opPos) { int stepType = getOp(opPos); if ((stepType >= OpCodes.AXES_START_TYPES) && (stepType <= OpCodes.AXES_END_TYPES)) { return getNextOpPos(opPos); } else if ((stepType >= OpCodes.FIRST_NODESET_OP) && (stepType <= OpCodes.LAST_NODESET_OP)) { int newOpPos = getNextOpPos(opPos); while (OpCodes.OP_PREDICATE == getOp(newOpPos)) { newOpPos = getNextOpPos(newOpPos); } stepType = getOp(newOpPos); if (!((stepType >= OpCodes.AXES_START_TYPES) && (stepType <= OpCodes.AXES_END_TYPES))) { return OpCodes.ENDOP; } return newOpPos; } else { throw new RuntimeException( XSLMessages.createXPATHMessage(XPATHErrorResources.ER_UNKNOWN_STEP, new Object[]{String.valueOf(stepType)})); //"Programmer's assertion in getNextStepPos: unknown stepType: " + stepType); } }
Given an operation position, return the end position, i.e. the beginning of the next operation.
Params:
  • opMap – The operations map.
  • opPos – index to operation, for which there is a size entry following.
Returns:position of next operation in m_opMap.
/** * Given an operation position, return the end position, i.e. the * beginning of the next operation. * * @param opMap The operations map. * @param opPos index to operation, for which there is a size entry following. * @return position of next operation in m_opMap. */
public static int getNextOpPos(int[] opMap, int opPos) { return opPos + opMap[opPos + 1]; }
Given an FROM_stepType position, return the position of the first predicate, if there is one, or else this will point to the end of the FROM_stepType. Example: int posOfPredicate = xpath.getNextOpPos(stepPos); boolean hasPredicates = OpCodes.OP_PREDICATE == xpath.getOp(posOfPredicate);
Params:
  • opPos – position of FROM_stepType op.
Returns:position of predicate in FROM_stepType structure.
/** * Given an FROM_stepType position, return the position of the * first predicate, if there is one, or else this will point * to the end of the FROM_stepType. * Example: * int posOfPredicate = xpath.getNextOpPos(stepPos); * boolean hasPredicates = * OpCodes.OP_PREDICATE == xpath.getOp(posOfPredicate); * * @param opPos position of FROM_stepType op. * @return position of predicate in FROM_stepType structure. */
public int getFirstPredicateOpPos(int opPos) throws javax.xml.transform.TransformerException { int stepType = m_opMap.elementAt(opPos); if ((stepType >= OpCodes.AXES_START_TYPES) && (stepType <= OpCodes.AXES_END_TYPES)) { return opPos + m_opMap.elementAt(opPos + 2); } else if ((stepType >= OpCodes.FIRST_NODESET_OP) && (stepType <= OpCodes.LAST_NODESET_OP)) { return opPos + m_opMap.elementAt(opPos + 1); } else if(-2 == stepType) { return -2; } else { error(org.apache.xpath.res.XPATHErrorResources.ER_UNKNOWN_OPCODE, new Object[]{ String.valueOf(stepType) }); //"ERROR! Unknown op code: "+m_opMap[opPos]); return -1; } }
Tell the user of an error, and probably throw an exception.
Params:
  • msg – An error msgkey that corresponds to one of the constants found in XPATHErrorResources, which is a key for a format string.
  • args – An array of arguments represented in the format string, which may be null.
Throws:
  • TransformerException – if the current ErrorListoner determines to throw an exception.
/** * Tell the user of an error, and probably throw an * exception. * * @param msg An error msgkey that corresponds to one of the constants found * in {@link org.apache.xpath.res.XPATHErrorResources}, which is * a key for a format string. * @param args An array of arguments represented in the format string, which * may be null. * * @throws TransformerException if the current ErrorListoner determines to * throw an exception. */
public void error(String msg, Object[] args) throws javax.xml.transform.TransformerException { java.lang.String fmsg = org.apache.xalan.res.XSLMessages.createXPATHMessage(msg, args); throw new javax.xml.transform.TransformerException(fmsg); }
Go to the first child of a given operation.
Params:
  • opPos – position of operation.
Returns:The position of the first child of the operation.
/** * Go to the first child of a given operation. * * @param opPos position of operation. * * @return The position of the first child of the operation. */
public static int getFirstChildPos(int opPos) { return opPos + 2; }
Get the length of an operation.
Params:
  • opPos – The position of the operation in the op map.
Returns:The size of the operation.
/** * Get the length of an operation. * * @param opPos The position of the operation in the op map. * * @return The size of the operation. */
public int getArgLength(int opPos) { return m_opMap.elementAt(opPos + MAPINDEX_LENGTH); }
Given a location step, get the length of that step.
Params:
  • opPos – Position of location step in op map.
Returns:The length of the step.
/** * Given a location step, get the length of that step. * * @param opPos Position of location step in op map. * * @return The length of the step. */
public int getArgLengthOfStep(int opPos) { return m_opMap.elementAt(opPos + MAPINDEX_LENGTH + 1) - 3; }
Get the first child position of a given location step.
Params:
  • opPos – Position of location step in the location map.
Returns:The first child position of the step.
/** * Get the first child position of a given location step. * * @param opPos Position of location step in the location map. * * @return The first child position of the step. */
public static int getFirstChildPosOfStep(int opPos) { return opPos + 3; }
Get the test type of the step, i.e. NODETYPE_XXX value.
Params:
  • opPosOfStep – The position of the FROM_XXX step.
Returns:NODETYPE_XXX value.
/** * Get the test type of the step, i.e. NODETYPE_XXX value. * * @param opPosOfStep The position of the FROM_XXX step. * * @return NODETYPE_XXX value. */
public int getStepTestType(int opPosOfStep) { return m_opMap.elementAt(opPosOfStep + 3); // skip past op, len, len without predicates }
Get the namespace of the step.
Params:
  • opPosOfStep – The position of the FROM_XXX step.
Returns:The step's namespace, NodeTest.WILD, or null for null namespace.
/** * Get the namespace of the step. * * @param opPosOfStep The position of the FROM_XXX step. * * @return The step's namespace, NodeTest.WILD, or null for null namespace. */
public String getStepNS(int opPosOfStep) { int argLenOfStep = getArgLengthOfStep(opPosOfStep); // System.out.println("getStepNS.argLenOfStep: "+argLenOfStep); if (argLenOfStep == 3) { int index = m_opMap.elementAt(opPosOfStep + 4); if (index >= 0) return (String) m_tokenQueue.elementAt(index); else if (OpCodes.ELEMWILDCARD == index) return NodeTest.WILD; else return null; } else return null; }
Get the local name of the step.
Params:
  • opPosOfStep – The position of the FROM_XXX step.
Returns:OpCodes.EMPTY, OpCodes.ELEMWILDCARD, or the local name.
/** * Get the local name of the step. * @param opPosOfStep The position of the FROM_XXX step. * * @return OpCodes.EMPTY, OpCodes.ELEMWILDCARD, or the local name. */
public String getStepLocalName(int opPosOfStep) { int argLenOfStep = getArgLengthOfStep(opPosOfStep); // System.out.println("getStepLocalName.argLenOfStep: "+argLenOfStep); int index; switch (argLenOfStep) { case 0 : index = OpCodes.EMPTY; break; case 1 : index = OpCodes.ELEMWILDCARD; break; case 2 : index = m_opMap.elementAt(opPosOfStep + 4); break; case 3 : index = m_opMap.elementAt(opPosOfStep + 5); break; default : index = OpCodes.EMPTY; break; // Should assert error } // int index = (argLenOfStep == 3) ? m_opMap[opPosOfStep+5] // : ((argLenOfStep == 1) ? -3 : -2); if (index >= 0) return (String) m_tokenQueue.elementAt(index).toString(); else if (OpCodes.ELEMWILDCARD == index) return NodeTest.WILD; else return null; } }