1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 /* 19 * $Id: FunctionMultiArgs.java 468655 2006-10-28 07:12:06Z minchau $ 20 */ 21 package org.apache.xpath.functions; 22 23 import org.apache.xalan.res.XSLMessages; 24 import org.apache.xpath.Expression; 25 import org.apache.xpath.ExpressionOwner; 26 import org.apache.xpath.XPathVisitor; 27 import org.apache.xpath.res.XPATHErrorResources; 28 29 /** 30 * Base class for functions that accept an undetermined number of multiple 31 * arguments. 32 * @xsl.usage advanced 33 */ 34 public class FunctionMultiArgs extends Function3Args 35 { 36 static final long serialVersionUID = 7117257746138417181L; 37 38 /** Argument expressions that are at index 3 or greater. 39 * @serial */ 40 Expression[] m_args; 41 42 /** 43 * Return an expression array containing arguments at index 3 or greater. 44 * 45 * @return An array that contains the arguments at index 3 or greater. 46 */ 47 public Expression[] getArgs() 48 { 49 return m_args; 50 } 51 52 /** 53 * Set an argument expression for a function. This method is called by the 54 * XPath compiler. 55 * 56 * @param arg non-null expression that represents the argument. 57 * @param argNum The argument number index. 58 * 59 * @throws WrongNumberArgsException If a derived class determines that the 60 * number of arguments is incorrect. 61 */ 62 public void setArg(Expression arg, int argNum) 63 throws WrongNumberArgsException 64 { 65 66 if (argNum < 3) 67 super.setArg(arg, argNum); 68 else 69 { 70 if (null == m_args) 71 { 72 m_args = new Expression[1]; 73 m_args[0] = arg; 74 } 75 else 76 { 77 78 // Slow but space conservative. 79 Expression[] args = new Expression[m_args.length + 1]; 80 81 System.arraycopy(m_args, 0, args, 0, m_args.length); 82 83 args[m_args.length] = arg; 84 m_args = args; 85 } 86 arg.exprSetParent(this); 87 } 88 } 89 90 /** 91 * This function is used to fixup variables from QNames to stack frame 92 * indexes at stylesheet build time. 93 * @param vars List of QNames that correspond to variables. This list 94 * should be searched backwards for the first qualified name that 95 * corresponds to the variable reference qname. The position of the 96 * QName in the vector from the start of the vector will be its position 97 * in the stack frame (but variables above the globalsTop value will need 98 * to be offset to the current stack frame). 99 */ 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 } 237