001: /*
002: * Copyright 1999-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: /*
017: * $Id: FunctionMultiArgs.java,v 1.16 2005/01/23 01:08:21 mcnamara Exp $
018: */
019: package org.apache.xpath.functions;
020:
021: import org.apache.xalan.res.XSLMessages;
022: import org.apache.xpath.Expression;
023: import org.apache.xpath.ExpressionOwner;
024: import org.apache.xpath.XPathVisitor;
025: import org.apache.xpath.res.XPATHErrorResources;
026:
027: /**
028: * Base class for functions that accept an undetermined number of multiple
029: * arguments.
030: * @xsl.usage advanced
031: */
032: public class FunctionMultiArgs extends Function3Args {
033: static final long serialVersionUID = 7117257746138417181L;
034:
035: /** Argument expressions that are at index 3 or greater.
036: * @serial */
037: Expression[] m_args;
038:
039: /**
040: * Return an expression array containing arguments at index 3 or greater.
041: *
042: * @return An array that contains the arguments at index 3 or greater.
043: */
044: public Expression[] getArgs() {
045: return m_args;
046: }
047:
048: /**
049: * Set an argument expression for a function. This method is called by the
050: * XPath compiler.
051: *
052: * @param arg non-null expression that represents the argument.
053: * @param argNum The argument number index.
054: *
055: * @throws WrongNumberArgsException If a derived class determines that the
056: * number of arguments is incorrect.
057: */
058: public void setArg(Expression arg, int argNum)
059: throws WrongNumberArgsException {
060:
061: if (argNum < 3)
062: super .setArg(arg, argNum);
063: else {
064: if (null == m_args) {
065: m_args = new Expression[1];
066: m_args[0] = arg;
067: } else {
068:
069: // Slow but space conservative.
070: Expression[] args = new Expression[m_args.length + 1];
071:
072: System.arraycopy(m_args, 0, args, 0, m_args.length);
073:
074: args[m_args.length] = arg;
075: m_args = args;
076: }
077: arg.exprSetParent(this );
078: }
079: }
080:
081: /**
082: * This function is used to fixup variables from QNames to stack frame
083: * indexes at stylesheet build time.
084: * @param vars List of QNames that correspond to variables. This list
085: * should be searched backwards for the first qualified name that
086: * corresponds to the variable reference qname. The position of the
087: * QName in the vector from the start of the vector will be its position
088: * in the stack frame (but variables above the globalsTop value will need
089: * to be offset to the current stack frame).
090: */
091: public void fixupVariables(java.util.Vector vars, int globalsSize) {
092: super .fixupVariables(vars, globalsSize);
093: if (null != m_args) {
094: for (int i = 0; i < m_args.length; i++) {
095: m_args[i].fixupVariables(vars, globalsSize);
096: }
097: }
098: }
099:
100: /**
101: * Check that the number of arguments passed to this function is correct.
102: *
103: *
104: * @param argNum The number of arguments that is being passed to the function.
105: *
106: * @throws WrongNumberArgsException
107: */
108: public void checkNumberArgs(int argNum)
109: throws WrongNumberArgsException {
110: }
111:
112: /**
113: * Constructs and throws a WrongNumberArgException with the appropriate
114: * message for this function object. This class supports an arbitrary
115: * number of arguments, so this method must never be called.
116: *
117: * @throws WrongNumberArgsException
118: */
119: protected void reportWrongNumberArgs()
120: throws WrongNumberArgsException {
121: String fMsg = XSLMessages
122: .createXPATHMessage(
123: XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION,
124: new Object[] { "Programmer's assertion: the method FunctionMultiArgs.reportWrongNumberArgs() should never be called." });
125:
126: throw new RuntimeException(fMsg);
127: }
128:
129: /**
130: * Tell if this expression or it's subexpressions can traverse outside
131: * the current subtree.
132: *
133: * @return true if traversal outside the context node's subtree can occur.
134: */
135: public boolean canTraverseOutsideSubtree() {
136:
137: if (super .canTraverseOutsideSubtree())
138: return true;
139: else {
140: int n = m_args.length;
141:
142: for (int i = 0; i < n; i++) {
143: if (m_args[i].canTraverseOutsideSubtree())
144: return true;
145: }
146:
147: return false;
148: }
149: }
150:
151: class ArgMultiOwner implements ExpressionOwner {
152: int m_argIndex;
153:
154: ArgMultiOwner(int index) {
155: m_argIndex = index;
156: }
157:
158: /**
159: * @see ExpressionOwner#getExpression()
160: */
161: public Expression getExpression() {
162: return m_args[m_argIndex];
163: }
164:
165: /**
166: * @see ExpressionOwner#setExpression(Expression)
167: */
168: public void setExpression(Expression exp) {
169: exp.exprSetParent(FunctionMultiArgs.this );
170: m_args[m_argIndex] = exp;
171: }
172: }
173:
174: /**
175: * @see org.apache.xpath.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
176: */
177: public void callArgVisitors(XPathVisitor visitor) {
178: super .callArgVisitors(visitor);
179: if (null != m_args) {
180: int n = m_args.length;
181: for (int i = 0; i < n; i++) {
182: m_args[i].callVisitors(new ArgMultiOwner(i), visitor);
183: }
184: }
185: }
186:
187: /**
188: * @see Expression#deepEquals(Expression)
189: */
190: public boolean deepEquals(Expression expr) {
191: if (!super .deepEquals(expr))
192: return false;
193:
194: FunctionMultiArgs fma = (FunctionMultiArgs) expr;
195: if (null != m_args) {
196: int n = m_args.length;
197: if ((null == fma) || (fma.m_args.length != n))
198: return false;
199:
200: for (int i = 0; i < n; i++) {
201: if (!m_args[i].deepEquals(fma.m_args[i]))
202: return false;
203: }
204:
205: } else if (null != fma.m_args) {
206: return false;
207: }
208:
209: return true;
210: }
211: }
|