FunctionMultiArgs.java revision 9f8118474e9513f7a5b7d2a05e4a0fb15d1a6569
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 */
21package org.apache.xpath.functions;
22
23import org.apache.xalan.res.XSLMessages;
24import org.apache.xpath.Expression;
25import org.apache.xpath.ExpressionOwner;
26import org.apache.xpath.XPathVisitor;
27import 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 */
34public 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