| /* |
| * 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: OpMap.java,v 1.1.2.1 2005/08/01 01:30:31 jeffsuttor Exp $ |
| */ |
| package com.sun.org.apache.xpath.internal.compiler; |
| |
| import com.sun.org.apache.xalan.internal.res.XSLMessages; |
| import com.sun.org.apache.xml.internal.utils.ObjectVector; |
| import com.sun.org.apache.xpath.internal.patterns.NodeTest; |
| import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; |
| |
| /** |
| * This class represents the data structure basics of the XPath |
| * object. |
| */ |
| public class OpMap |
| { |
| |
| /** |
| * The current pattern string, for diagnostics purposes |
| */ |
| protected String m_currentPattern; |
| |
| /** |
| * 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. |
| * |
| * @return The expression string. |
| */ |
| public String getPatternString() |
| { |
| return m_currentPattern; |
| } |
| |
| /** |
| * 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. |
| */ |
| ObjectVector m_tokenQueue = new ObjectVector(MAXTOKENQUEUESIZE, BLOCKTOKENQUEUESIZE); |
| |
| /** |
| * 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. |
| * |
| * @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. |
| * |
| * @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. |
| */ |
| 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. |
| * |
| * @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. |
| */ |
| public static final int MAPINDEX_LENGTH = 1; |
| |
| /** |
| * 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. |
| * |
| * @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. |
| * |
| * @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. |
| * |
| * @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. |
| * |
| * @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. |
| * |
| * @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); |
| * |
| * @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(com.sun.org.apache.xpath.internal.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. |
| * |
| * @param msg An error msgkey that corresponds to one of the constants found |
| * in {@link com.sun.org.apache.xpath.internal.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 = com.sun.org.apache.xalan.internal.res.XSLMessages.createXPATHMessage(msg, args); |
| |
| |
| throw new javax.xml.transform.TransformerException(fmsg); |
| } |
| |
| |
| /** |
| * 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. |
| * |
| * @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. |
| * |
| * @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. |
| * |
| * @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. |
| * |
| * @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. |
| * |
| * @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. |
| * @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; |
| } |
| |
| } |