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 }