diff options
Diffstat (limited to 'src/share/classes/com/sun/org/apache/xpath/internal/compiler/Compiler.java')
-rw-r--r-- | src/share/classes/com/sun/org/apache/xpath/internal/compiler/Compiler.java | 1270 |
1 files changed, 1270 insertions, 0 deletions
diff --git a/src/share/classes/com/sun/org/apache/xpath/internal/compiler/Compiler.java b/src/share/classes/com/sun/org/apache/xpath/internal/compiler/Compiler.java new file mode 100644 index 0000000..fd2fbae --- /dev/null +++ b/src/share/classes/com/sun/org/apache/xpath/internal/compiler/Compiler.java @@ -0,0 +1,1270 @@ +/* + * 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: Compiler.java,v 1.2.4.1 2005/09/14 19:47:10 jeffsuttor Exp $ + */ +package com.sun.org.apache.xpath.internal.compiler; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.SourceLocator; +import javax.xml.transform.TransformerException; + +import com.sun.org.apache.xalan.internal.res.XSLMessages; +import com.sun.org.apache.xml.internal.dtm.Axis; +import com.sun.org.apache.xml.internal.dtm.DTMFilter; +import com.sun.org.apache.xml.internal.dtm.DTMIterator; +import com.sun.org.apache.xml.internal.utils.PrefixResolver; +import com.sun.org.apache.xml.internal.utils.QName; +import com.sun.org.apache.xml.internal.utils.SAXSourceLocator; +import com.sun.org.apache.xpath.internal.Expression; +import com.sun.org.apache.xpath.internal.axes.UnionPathIterator; +import com.sun.org.apache.xpath.internal.axes.WalkerFactory; +import com.sun.org.apache.xpath.internal.functions.FuncExtFunction; +import com.sun.org.apache.xpath.internal.functions.FuncExtFunctionAvailable; +import com.sun.org.apache.xpath.internal.functions.Function; +import com.sun.org.apache.xpath.internal.functions.WrongNumberArgsException; +import com.sun.org.apache.xpath.internal.objects.XNumber; +import com.sun.org.apache.xpath.internal.objects.XString; +import com.sun.org.apache.xpath.internal.operations.And; +import com.sun.org.apache.xpath.internal.operations.Div; +import com.sun.org.apache.xpath.internal.operations.Equals; +import com.sun.org.apache.xpath.internal.operations.Gt; +import com.sun.org.apache.xpath.internal.operations.Gte; +import com.sun.org.apache.xpath.internal.operations.Lt; +import com.sun.org.apache.xpath.internal.operations.Lte; +import com.sun.org.apache.xpath.internal.operations.Minus; +import com.sun.org.apache.xpath.internal.operations.Mod; +import com.sun.org.apache.xpath.internal.operations.Mult; +import com.sun.org.apache.xpath.internal.operations.Neg; +import com.sun.org.apache.xpath.internal.operations.NotEquals; +import com.sun.org.apache.xpath.internal.operations.Operation; +import com.sun.org.apache.xpath.internal.operations.Or; +import com.sun.org.apache.xpath.internal.operations.Plus; +import com.sun.org.apache.xpath.internal.operations.UnaryOperation; +import com.sun.org.apache.xpath.internal.operations.Variable; +import com.sun.org.apache.xpath.internal.patterns.FunctionPattern; +import com.sun.org.apache.xpath.internal.patterns.NodeTest; +import com.sun.org.apache.xpath.internal.patterns.StepPattern; +import com.sun.org.apache.xpath.internal.patterns.UnionPattern; +import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; + +/** + * An instance of this class compiles an XPath string expression into + * a Expression object. This class compiles the string into a sequence + * of operation codes (op map) and then builds from that into an Expression + * tree. + * @xsl.usage advanced + */ +public class Compiler extends OpMap +{ + + /** + * Construct a Compiler object with a specific ErrorListener and + * SourceLocator where the expression is located. + * + * @param errorHandler Error listener where messages will be sent, or null + * if messages should be sent to System err. + * @param locator The location object where the expression lives, which + * may be null, but which, if not null, must be valid over + * the long haul, in other words, it will not be cloned. + * @param fTable The FunctionTable object where the xpath build-in + * functions are stored. + */ + public Compiler(ErrorListener errorHandler, SourceLocator locator, + FunctionTable fTable) + { + m_errorHandler = errorHandler; + m_locator = locator; + m_functionTable = fTable; + } + + /** + * Construct a Compiler instance that has a null error listener and a + * null source locator. + */ + public Compiler() + { + m_errorHandler = null; + m_locator = null; + } + + /** + * Execute the XPath object from a given opcode position. + * @param opPos The current position in the xpath.m_opMap array. + * @return The result of the XPath. + * + * @throws TransformerException if there is a syntax or other error. + * @xsl.usage advanced + */ + public Expression compile(int opPos) throws TransformerException + { + + int op = getOp(opPos); + + Expression expr = null; + // System.out.println(getPatternString()+"op: "+op); + switch (op) + { + case OpCodes.OP_XPATH : + expr = compile(opPos + 2); break; + case OpCodes.OP_OR : + expr = or(opPos); break; + case OpCodes.OP_AND : + expr = and(opPos); break; + case OpCodes.OP_NOTEQUALS : + expr = notequals(opPos); break; + case OpCodes.OP_EQUALS : + expr = equals(opPos); break; + case OpCodes.OP_LTE : + expr = lte(opPos); break; + case OpCodes.OP_LT : + expr = lt(opPos); break; + case OpCodes.OP_GTE : + expr = gte(opPos); break; + case OpCodes.OP_GT : + expr = gt(opPos); break; + case OpCodes.OP_PLUS : + expr = plus(opPos); break; + case OpCodes.OP_MINUS : + expr = minus(opPos); break; + case OpCodes.OP_MULT : + expr = mult(opPos); break; + case OpCodes.OP_DIV : + expr = div(opPos); break; + case OpCodes.OP_MOD : + expr = mod(opPos); break; +// case OpCodes.OP_QUO : +// expr = quo(opPos); break; + case OpCodes.OP_NEG : + expr = neg(opPos); break; + case OpCodes.OP_STRING : + expr = string(opPos); break; + case OpCodes.OP_BOOL : + expr = bool(opPos); break; + case OpCodes.OP_NUMBER : + expr = number(opPos); break; + case OpCodes.OP_UNION : + expr = union(opPos); break; + case OpCodes.OP_LITERAL : + expr = literal(opPos); break; + case OpCodes.OP_VARIABLE : + expr = variable(opPos); break; + case OpCodes.OP_GROUP : + expr = group(opPos); break; + case OpCodes.OP_NUMBERLIT : + expr = numberlit(opPos); break; + case OpCodes.OP_ARGUMENT : + expr = arg(opPos); break; + case OpCodes.OP_EXTFUNCTION : + expr = compileExtension(opPos); break; + case OpCodes.OP_FUNCTION : + expr = compileFunction(opPos); break; + case OpCodes.OP_LOCATIONPATH : + expr = locationPath(opPos); break; + case OpCodes.OP_PREDICATE : + expr = null; break; // should never hit this here. + case OpCodes.OP_MATCHPATTERN : + expr = matchPattern(opPos + 2); break; + case OpCodes.OP_LOCATIONPATHPATTERN : + expr = locationPathPattern(opPos); break; + case OpCodes.OP_QUO: + error(XPATHErrorResources.ER_UNKNOWN_OPCODE, + new Object[]{ "quo" }); //"ERROR! Unknown op code: "+m_opMap[opPos]); + break; + default : + error(XPATHErrorResources.ER_UNKNOWN_OPCODE, + new Object[]{ Integer.toString(getOp(opPos)) }); //"ERROR! Unknown op code: "+m_opMap[opPos]); + } +// if(null != expr) +// expr.setSourceLocator(m_locator); + + return expr; + } + + /** + * Bottle-neck compilation of an operation with left and right operands. + * + * @param operation non-null reference to parent operation. + * @param opPos The op map position of the parent operation. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Operation} instance. + * + * @throws TransformerException if there is a syntax or other error. + */ + private Expression compileOperation(Operation operation, int opPos) + throws TransformerException + { + + int leftPos = getFirstChildPos(opPos); + int rightPos = getNextOpPos(leftPos); + + operation.setLeftRight(compile(leftPos), compile(rightPos)); + + return operation; + } + + /** + * Bottle-neck compilation of a unary operation. + * + * @param unary The parent unary operation. + * @param opPos The position in the op map of the parent operation. + * + * @return The unary argument. + * + * @throws TransformerException if syntax or other error occurs. + */ + private Expression compileUnary(UnaryOperation unary, int opPos) + throws TransformerException + { + + int rightPos = getFirstChildPos(opPos); + + unary.setRight(compile(rightPos)); + + return unary; + } + + /** + * Compile an 'or' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Or} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression or(int opPos) throws TransformerException + { + return compileOperation(new Or(), opPos); + } + + /** + * Compile an 'and' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.And} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression and(int opPos) throws TransformerException + { + return compileOperation(new And(), opPos); + } + + /** + * Compile a '!=' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.NotEquals} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression notequals(int opPos) throws TransformerException + { + return compileOperation(new NotEquals(), opPos); + } + + /** + * Compile a '=' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Equals} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression equals(int opPos) throws TransformerException + { + return compileOperation(new Equals(), opPos); + } + + /** + * Compile a '<=' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Lte} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression lte(int opPos) throws TransformerException + { + return compileOperation(new Lte(), opPos); + } + + /** + * Compile a '<' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Lt} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression lt(int opPos) throws TransformerException + { + return compileOperation(new Lt(), opPos); + } + + /** + * Compile a '>=' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Gte} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression gte(int opPos) throws TransformerException + { + return compileOperation(new Gte(), opPos); + } + + /** + * Compile a '>' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Gt} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression gt(int opPos) throws TransformerException + { + return compileOperation(new Gt(), opPos); + } + + /** + * Compile a '+' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Plus} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression plus(int opPos) throws TransformerException + { + return compileOperation(new Plus(), opPos); + } + + /** + * Compile a '-' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Minus} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression minus(int opPos) throws TransformerException + { + return compileOperation(new Minus(), opPos); + } + + /** + * Compile a '*' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Mult} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression mult(int opPos) throws TransformerException + { + return compileOperation(new Mult(), opPos); + } + + /** + * Compile a 'div' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Div} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression div(int opPos) throws TransformerException + { + return compileOperation(new Div(), opPos); + } + + /** + * Compile a 'mod' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Mod} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression mod(int opPos) throws TransformerException + { + return compileOperation(new Mod(), opPos); + } + + /* + * Compile a 'quo' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Quo} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ +// protected Expression quo(int opPos) throws TransformerException +// { +// return compileOperation(new Quo(), opPos); +// } + + /** + * Compile a unary '-' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Neg} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression neg(int opPos) throws TransformerException + { + return compileUnary(new Neg(), opPos); + } + + /** + * Compile a 'string(...)' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.String} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression string(int opPos) throws TransformerException + { + return compileUnary(new com.sun.org.apache.xpath.internal.operations.String(), opPos); + } + + /** + * Compile a 'boolean(...)' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Bool} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression bool(int opPos) throws TransformerException + { + return compileUnary(new com.sun.org.apache.xpath.internal.operations.Bool(), opPos); + } + + /** + * Compile a 'number(...)' operation. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Number} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression number(int opPos) throws TransformerException + { + return compileUnary(new com.sun.org.apache.xpath.internal.operations.Number(), opPos); + } + + /** + * Compile a literal string value. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.objects.XString} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression literal(int opPos) + { + + opPos = getFirstChildPos(opPos); + + return (XString) getTokenQueue().elementAt(getOp(opPos)); + } + + /** + * Compile a literal number value. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.objects.XNumber} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression numberlit(int opPos) + { + + opPos = getFirstChildPos(opPos); + + return (XNumber) getTokenQueue().elementAt(getOp(opPos)); + } + + /** + * Compile a variable reference. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Variable} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression variable(int opPos) throws TransformerException + { + + Variable var = new Variable(); + + opPos = getFirstChildPos(opPos); + + int nsPos = getOp(opPos); + java.lang.String namespace + = (OpCodes.EMPTY == nsPos) ? null + : (java.lang.String) getTokenQueue().elementAt(nsPos); + java.lang.String localname + = (java.lang.String) getTokenQueue().elementAt(getOp(opPos+1)); + QName qname = new QName(namespace, localname); + + var.setQName(qname); + + return var; + } + + /** + * Compile an expression group. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to the contained expression. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression group(int opPos) throws TransformerException + { + + // no-op + return compile(opPos + 2); + } + + /** + * Compile a function argument. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to the argument expression. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression arg(int opPos) throws TransformerException + { + + // no-op + return compile(opPos + 2); + } + + /** + * Compile a location path union. The UnionPathIterator itself may create + * {@link com.sun.org.apache.xpath.internal.axes.LocPathIterator} children. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.axes.LocPathIterator} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression union(int opPos) throws TransformerException + { + locPathDepth++; + try + { + return UnionPathIterator.createUnionIterator(this, opPos); + } + finally + { + locPathDepth--; + } + } + + private int locPathDepth = -1; + + /** + * Get the level of the location path or union being constructed. + * @return 0 if it is a top-level path. + */ + public int getLocationPathDepth() + { + return locPathDepth; + } + + /** + * Get the function table + */ + FunctionTable getFunctionTable() + { + return m_functionTable; + } + + /** + * Compile a location path. The LocPathIterator itself may create + * {@link com.sun.org.apache.xpath.internal.axes.AxesWalker} children. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.axes.LocPathIterator} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + public Expression locationPath(int opPos) throws TransformerException + { + locPathDepth++; + try + { + DTMIterator iter = WalkerFactory.newDTMIterator(this, opPos, (locPathDepth == 0)); + return (Expression)iter; // cast OK, I guess. + } + finally + { + locPathDepth--; + } + } + + /** + * Compile a location step predicate expression. + * + * @param opPos The current position in the m_opMap array. + * + * @return the contained predicate expression. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + public Expression predicate(int opPos) throws TransformerException + { + return compile(opPos + 2); + } + + /** + * Compile an entire match pattern expression. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.patterns.UnionPattern} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected Expression matchPattern(int opPos) throws TransformerException + { + locPathDepth++; + try + { + // First, count... + int nextOpPos = opPos; + int i; + + for (i = 0; getOp(nextOpPos) == OpCodes.OP_LOCATIONPATHPATTERN; i++) + { + nextOpPos = getNextOpPos(nextOpPos); + } + + if (i == 1) + return compile(opPos); + + UnionPattern up = new UnionPattern(); + StepPattern[] patterns = new StepPattern[i]; + + for (i = 0; getOp(opPos) == OpCodes.OP_LOCATIONPATHPATTERN; i++) + { + nextOpPos = getNextOpPos(opPos); + patterns[i] = (StepPattern) compile(opPos); + opPos = nextOpPos; + } + + up.setPatterns(patterns); + + return up; + } + finally + { + locPathDepth--; + } + } + + /** + * Compile a location match pattern unit expression. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.patterns.StepPattern} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + public Expression locationPathPattern(int opPos) + throws TransformerException + { + + opPos = getFirstChildPos(opPos); + + return stepPattern(opPos, 0, null); + } + + /** + * Get a {@link org.w3c.dom.traversal.NodeFilter} bit set that tells what + * to show for a given node test. + * + * @param opPos the op map position for the location step. + * + * @return {@link org.w3c.dom.traversal.NodeFilter} bit set that tells what + * to show for a given node test. + */ + public int getWhatToShow(int opPos) + { + + int axesType = getOp(opPos); + int testType = getOp(opPos + 3); + + // System.out.println("testType: "+testType); + switch (testType) + { + case OpCodes.NODETYPE_COMMENT : + return DTMFilter.SHOW_COMMENT; + case OpCodes.NODETYPE_TEXT : +// return DTMFilter.SHOW_TEXT | DTMFilter.SHOW_COMMENT; + return DTMFilter.SHOW_TEXT | DTMFilter.SHOW_CDATA_SECTION ; + case OpCodes.NODETYPE_PI : + return DTMFilter.SHOW_PROCESSING_INSTRUCTION; + case OpCodes.NODETYPE_NODE : +// return DTMFilter.SHOW_ALL; + switch (axesType) + { + case OpCodes.FROM_NAMESPACE: + return DTMFilter.SHOW_NAMESPACE; + case OpCodes.FROM_ATTRIBUTES : + case OpCodes.MATCH_ATTRIBUTE : + return DTMFilter.SHOW_ATTRIBUTE; + case OpCodes.FROM_SELF: + case OpCodes.FROM_ANCESTORS_OR_SELF: + case OpCodes.FROM_DESCENDANTS_OR_SELF: + return DTMFilter.SHOW_ALL; + default: + if (getOp(0) == OpCodes.OP_MATCHPATTERN) + return ~DTMFilter.SHOW_ATTRIBUTE + & ~DTMFilter.SHOW_DOCUMENT + & ~DTMFilter.SHOW_DOCUMENT_FRAGMENT; + else + return ~DTMFilter.SHOW_ATTRIBUTE; + } + case OpCodes.NODETYPE_ROOT : + return DTMFilter.SHOW_DOCUMENT | DTMFilter.SHOW_DOCUMENT_FRAGMENT; + case OpCodes.NODETYPE_FUNCTEST : + return NodeTest.SHOW_BYFUNCTION; + case OpCodes.NODENAME : + switch (axesType) + { + case OpCodes.FROM_NAMESPACE : + return DTMFilter.SHOW_NAMESPACE; + case OpCodes.FROM_ATTRIBUTES : + case OpCodes.MATCH_ATTRIBUTE : + return DTMFilter.SHOW_ATTRIBUTE; + + // break; + case OpCodes.MATCH_ANY_ANCESTOR : + case OpCodes.MATCH_IMMEDIATE_ANCESTOR : + return DTMFilter.SHOW_ELEMENT; + + // break; + default : + return DTMFilter.SHOW_ELEMENT; + } + default : + // System.err.println("We should never reach here."); + return DTMFilter.SHOW_ALL; + } + } + +private static final boolean DEBUG = false; + + /** + * Compile a step pattern unit expression, used for both location paths + * and match patterns. + * + * @param opPos The current position in the m_opMap array. + * @param stepCount The number of steps to expect. + * @param ancestorPattern The owning StepPattern, which may be null. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.patterns.StepPattern} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + protected StepPattern stepPattern( + int opPos, int stepCount, StepPattern ancestorPattern) + throws TransformerException + { + + int startOpPos = opPos; + int stepType = getOp(opPos); + + if (OpCodes.ENDOP == stepType) + { + return null; + } + + boolean addMagicSelf = true; + + int endStep = getNextOpPos(opPos); + + // int nextStepType = getOpMap()[endStep]; + StepPattern pattern; + + // boolean isSimple = ((OpCodes.ENDOP == nextStepType) && (stepCount == 0)); + int argLen; + + switch (stepType) + { + case OpCodes.OP_FUNCTION : + if(DEBUG) + System.out.println("MATCH_FUNCTION: "+m_currentPattern); + addMagicSelf = false; + argLen = getOp(opPos + OpMap.MAPINDEX_LENGTH); + pattern = new FunctionPattern(compileFunction(opPos), Axis.PARENT, Axis.CHILD); + break; + case OpCodes.FROM_ROOT : + if(DEBUG) + System.out.println("FROM_ROOT, "+m_currentPattern); + addMagicSelf = false; + argLen = getArgLengthOfStep(opPos); + opPos = getFirstChildPosOfStep(opPos); + pattern = new StepPattern(DTMFilter.SHOW_DOCUMENT | + DTMFilter.SHOW_DOCUMENT_FRAGMENT, + Axis.PARENT, Axis.CHILD); + break; + case OpCodes.MATCH_ATTRIBUTE : + if(DEBUG) + System.out.println("MATCH_ATTRIBUTE: "+getStepLocalName(startOpPos)+", "+m_currentPattern); + argLen = getArgLengthOfStep(opPos); + opPos = getFirstChildPosOfStep(opPos); + pattern = new StepPattern(DTMFilter.SHOW_ATTRIBUTE, + getStepNS(startOpPos), + getStepLocalName(startOpPos), + Axis.PARENT, Axis.ATTRIBUTE); + break; + case OpCodes.MATCH_ANY_ANCESTOR : + if(DEBUG) + System.out.println("MATCH_ANY_ANCESTOR: "+getStepLocalName(startOpPos)+", "+m_currentPattern); + argLen = getArgLengthOfStep(opPos); + opPos = getFirstChildPosOfStep(opPos); + int what = getWhatToShow(startOpPos); + // bit-o-hackery, but this code is due for the morgue anyway... + if(0x00000500 == what) + addMagicSelf = false; + pattern = new StepPattern(getWhatToShow(startOpPos), + getStepNS(startOpPos), + getStepLocalName(startOpPos), + Axis.ANCESTOR, Axis.CHILD); + break; + case OpCodes.MATCH_IMMEDIATE_ANCESTOR : + if(DEBUG) + System.out.println("MATCH_IMMEDIATE_ANCESTOR: "+getStepLocalName(startOpPos)+", "+m_currentPattern); + argLen = getArgLengthOfStep(opPos); + opPos = getFirstChildPosOfStep(opPos); + pattern = new StepPattern(getWhatToShow(startOpPos), + getStepNS(startOpPos), + getStepLocalName(startOpPos), + Axis.PARENT, Axis.CHILD); + break; + default : + error(XPATHErrorResources.ER_UNKNOWN_MATCH_OPERATION, null); //"unknown match operation!"); + + return null; + } + + pattern.setPredicates(getCompiledPredicates(opPos + argLen)); + if(null == ancestorPattern) + { + // This is the magic and invisible "." at the head of every + // match pattern, and corresponds to the current node in the context + // list, from where predicates are counted. + // So, in order to calculate "foo[3]", it has to count from the + // current node in the context list, so, from that current node, + // the full pattern is really "self::node()/child::foo[3]". If you + // translate this to a select pattern from the node being tested, + // which is really how we're treating match patterns, it works out to + // self::foo/parent::node[child::foo[3]]", or close enough. + /* if(addMagicSelf && pattern.getPredicateCount() > 0) + { + StepPattern selfPattern = new StepPattern(DTMFilter.SHOW_ALL, + Axis.PARENT, Axis.CHILD); + // We need to keep the new nodetest from affecting the score... + XNumber score = pattern.getStaticScore(); + pattern.setRelativePathPattern(selfPattern); + pattern.setStaticScore(score); + selfPattern.setStaticScore(score); + }*/ + } + else + { + // System.out.println("Setting "+ancestorPattern+" as relative to "+pattern); + pattern.setRelativePathPattern(ancestorPattern); + } + + StepPattern relativePathPattern = stepPattern(endStep, stepCount + 1, + pattern); + + return (null != relativePathPattern) ? relativePathPattern : pattern; + } + + /** + * Compile a zero or more predicates for a given match pattern. + * + * @param opPos The position of the first predicate the m_opMap array. + * + * @return reference to array of {@link com.sun.org.apache.xpath.internal.Expression} instances. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + public Expression[] getCompiledPredicates(int opPos) + throws TransformerException + { + + int count = countPredicates(opPos); + + if (count > 0) + { + Expression[] predicates = new Expression[count]; + + compilePredicates(opPos, predicates); + + return predicates; + } + + return null; + } + + /** + * Count the number of predicates in the step. + * + * @param opPos The position of the first predicate the m_opMap array. + * + * @return The number of predicates for this step. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + public int countPredicates(int opPos) throws TransformerException + { + + int count = 0; + + while (OpCodes.OP_PREDICATE == getOp(opPos)) + { + count++; + + opPos = getNextOpPos(opPos); + } + + return count; + } + + /** + * Compiles predicates in the step. + * + * @param opPos The position of the first predicate the m_opMap array. + * @param predicates An empty pre-determined array of + * {@link com.sun.org.apache.xpath.internal.Expression}s, that will be filled in. + * + * @throws TransformerException + */ + private void compilePredicates(int opPos, Expression[] predicates) + throws TransformerException + { + + for (int i = 0; OpCodes.OP_PREDICATE == getOp(opPos); i++) + { + predicates[i] = predicate(opPos); + opPos = getNextOpPos(opPos); + } + } + + /** + * Compile a built-in XPath function. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.functions.Function} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + Expression compileFunction(int opPos) throws TransformerException + { + + int endFunc = opPos + getOp(opPos + 1) - 1; + + opPos = getFirstChildPos(opPos); + + int funcID = getOp(opPos); + + opPos++; + + if (-1 != funcID) + { + Function func = m_functionTable.getFunction(funcID); + + /** + * It is a trick for function-available. Since the function table is an + * instance field, insert this table at compilation time for later usage + */ + + if (func instanceof FuncExtFunctionAvailable) + ((FuncExtFunctionAvailable) func).setFunctionTable(m_functionTable); + + func.postCompileStep(this); + + try + { + int i = 0; + + for (int p = opPos; p < endFunc; p = getNextOpPos(p), i++) + { + + // System.out.println("argPos: "+ p); + // System.out.println("argCode: "+ m_opMap[p]); + func.setArg(compile(p), i); + } + + func.checkNumberArgs(i); + } + catch (WrongNumberArgsException wnae) + { + java.lang.String name = m_functionTable.getFunctionName(funcID); + + m_errorHandler.fatalError( new TransformerException( + XSLMessages.createXPATHMessage(XPATHErrorResources.ER_ONLY_ALLOWS, + new Object[]{name, wnae.getMessage()}), m_locator)); + //"name + " only allows " + wnae.getMessage() + " arguments", m_locator)); + } + + return func; + } + else + { + error(XPATHErrorResources.ER_FUNCTION_TOKEN_NOT_FOUND, null); //"function token not found."); + + return null; + } + } + + // The current id for extension functions. + private static long s_nextMethodId = 0; + + /** + * Get the next available method id + */ + synchronized private long getNextMethodId() + { + if (s_nextMethodId == Long.MAX_VALUE) + s_nextMethodId = 0; + + return s_nextMethodId++; + } + + /** + * Compile an extension function. + * + * @param opPos The current position in the m_opMap array. + * + * @return reference to {@link com.sun.org.apache.xpath.internal.functions.FuncExtFunction} instance. + * + * @throws TransformerException if a error occurs creating the Expression. + */ + private Expression compileExtension(int opPos) + throws TransformerException + { + + int endExtFunc = opPos + getOp(opPos + 1) - 1; + + opPos = getFirstChildPos(opPos); + + java.lang.String ns = (java.lang.String) getTokenQueue().elementAt(getOp(opPos)); + + opPos++; + + java.lang.String funcName = + (java.lang.String) getTokenQueue().elementAt(getOp(opPos)); + + opPos++; + + // We create a method key to uniquely identify this function so that we + // can cache the object needed to invoke it. This way, we only pay the + // reflection overhead on the first call. + + Function extension = new FuncExtFunction(ns, funcName, String.valueOf(getNextMethodId())); + + try + { + int i = 0; + + while (opPos < endExtFunc) + { + int nextOpPos = getNextOpPos(opPos); + + extension.setArg(this.compile(opPos), i); + + opPos = nextOpPos; + + i++; + } + } + catch (WrongNumberArgsException wnae) + { + ; // should never happen + } + + return extension; + } + + /** + * Warn the user of an problem. + * + * @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 warn(String msg, Object[] args) throws TransformerException + { + + java.lang.String fmsg = XSLMessages.createXPATHWarning(msg, args); + + if (null != m_errorHandler) + { + m_errorHandler.warning(new TransformerException(fmsg, m_locator)); + } + else + { + System.out.println(fmsg + +"; file "+m_locator.getSystemId() + +"; line "+m_locator.getLineNumber() + +"; column "+m_locator.getColumnNumber()); + } + } + + /** + * Tell the user of an assertion error, and probably throw an + * exception. + * + * @param b If false, a runtime exception will be thrown. + * @param msg The assertion message, which should be informative. + * + * @throws RuntimeException if the b argument is false. + */ + public void assertion(boolean b, java.lang.String msg) + { + + if (!b) + { + java.lang.String fMsg = XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION, + new Object[]{ msg }); + + throw new RuntimeException(fMsg); + } + } + + /** + * 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 TransformerException + { + + java.lang.String fmsg = XSLMessages.createXPATHMessage(msg, args); + + + if (null != m_errorHandler) + { + m_errorHandler.fatalError(new TransformerException(fmsg, m_locator)); + } + else + { + + // System.out.println(te.getMessage() + // +"; file "+te.getSystemId() + // +"; line "+te.getLineNumber() + // +"; column "+te.getColumnNumber()); + throw new TransformerException(fmsg, (SAXSourceLocator)m_locator); + } + } + + /** + * The current prefixResolver for the execution context. + */ + private PrefixResolver m_currentPrefixResolver = null; + + /** + * Get the current namespace context for the xpath. + * + * @return The current prefix resolver, *may* be null, though hopefully not. + */ + public PrefixResolver getNamespaceContext() + { + return m_currentPrefixResolver; + } + + /** + * Set the current namespace context for the xpath. + * + * @param pr The resolver for prefixes in the XPath expression. + */ + public void setNamespaceContext(PrefixResolver pr) + { + m_currentPrefixResolver = pr; + } + + /** The error listener where errors will be sent. If this is null, errors + * and warnings will be sent to System.err. May be null. */ + ErrorListener m_errorHandler; + + /** The source locator for the expression being compiled. May be null. */ + SourceLocator m_locator; + + /** + * The FunctionTable for all xpath build-in functions + */ + private FunctionTable m_functionTable; +} |