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