1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xpath.internal.functions;
23
24import com.sun.org.apache.xalan.internal.res.XSLMessages;
25import com.sun.org.apache.xpath.internal.Expression;
26import com.sun.org.apache.xpath.internal.ExpressionOwner;
27import com.sun.org.apache.xpath.internal.XPathVisitor;
28import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
29
30/**
31 * Base class for functions that accept an undetermined number of multiple
32 * arguments.
33 * @xsl.usage advanced
34 */
35public class FunctionMultiArgs extends Function3Args
36{
37    static final long serialVersionUID = 7117257746138417181L;
38
39  /** Argument expressions that are at index 3 or greater.
40   *  @serial */
41  Expression[] m_args;
42
43  /**
44   * Return an expression array containing arguments at index 3 or greater.
45   *
46   * @return An array that contains the arguments at index 3 or greater.
47   */
48  public Expression[] getArgs()
49  {
50    return m_args;
51  }
52
53  /**
54   * Set an argument expression for a function.  This method is called by the
55   * XPath compiler.
56   *
57   * @param arg non-null expression that represents the argument.
58   * @param argNum The argument number index.
59   *
60   * @throws WrongNumberArgsException If a derived class determines that the
61   * number of arguments is incorrect.
62   */
63  public void setArg(Expression arg, int argNum)
64          throws WrongNumberArgsException
65  {
66
67    if (argNum < 3)
68      super.setArg(arg, argNum);
69    else
70    {
71      if (null == m_args)
72      {
73        m_args = new Expression[1];
74        m_args[0] = arg;
75      }
76      else
77      {
78
79        // Slow but space conservative.
80        Expression[] args = new Expression[m_args.length + 1];
81
82        System.arraycopy(m_args, 0, args, 0, m_args.length);
83
84        args[m_args.length] = arg;
85        m_args = args;
86      }
87      arg.exprSetParent(this);
88    }
89  }
90
91  /**
92   * This function is used to fixup variables from QNames to stack frame
93   * indexes at stylesheet build time.
94   * @param vars List of QNames that correspond to variables.  This list
95   * should be searched backwards for the first qualified name that
96   * corresponds to the variable reference qname.  The position of the
97   * QName in the vector from the start of the vector will be its position
98   * in the stack frame (but variables above the globalsTop value will need
99   * to be offset to the current stack frame).
100   */
101  public void fixupVariables(java.util.Vector vars, int globalsSize)
102  {
103    super.fixupVariables(vars, globalsSize);
104    if(null != m_args)
105    {
106      for (int i = 0; i < m_args.length; i++)
107      {
108        m_args[i].fixupVariables(vars, globalsSize);
109      }
110    }
111  }
112
113  /**
114   * Check that the number of arguments passed to this function is correct.
115   *
116   *
117   * @param argNum The number of arguments that is being passed to the function.
118   *
119   * @throws WrongNumberArgsException
120   */
121  public void checkNumberArgs(int argNum) throws WrongNumberArgsException{}
122
123  /**
124   * Constructs and throws a WrongNumberArgException with the appropriate
125   * message for this function object.  This class supports an arbitrary
126   * number of arguments, so this method must never be called.
127   *
128   * @throws WrongNumberArgsException
129   */
130  protected void reportWrongNumberArgs() throws WrongNumberArgsException {
131    String fMsg = XSLMessages.createXPATHMessage(
132        XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION,
133        new Object[]{ "Programmer's assertion:  the method FunctionMultiArgs.reportWrongNumberArgs() should never be called." });
134
135    throw new RuntimeException(fMsg);
136  }
137
138  /**
139   * Tell if this expression or it's subexpressions can traverse outside
140   * the current subtree.
141   *
142   * @return true if traversal outside the context node's subtree can occur.
143   */
144  public boolean canTraverseOutsideSubtree()
145  {
146
147    if (super.canTraverseOutsideSubtree())
148      return true;
149    else
150    {
151      int n = m_args.length;
152
153      for (int i = 0; i < n; i++)
154      {
155        if (m_args[i].canTraverseOutsideSubtree())
156          return true;
157      }
158
159      return false;
160    }
161  }
162
163  class ArgMultiOwner implements ExpressionOwner
164  {
165        int m_argIndex;
166
167        ArgMultiOwner(int index)
168        {
169                m_argIndex = index;
170        }
171
172    /**
173     * @see ExpressionOwner#getExpression()
174     */
175    public Expression getExpression()
176    {
177      return m_args[m_argIndex];
178    }
179
180
181    /**
182     * @see ExpressionOwner#setExpression(Expression)
183     */
184    public void setExpression(Expression exp)
185    {
186        exp.exprSetParent(FunctionMultiArgs.this);
187        m_args[m_argIndex] = exp;
188    }
189  }
190
191
192    /**
193     * @see com.sun.org.apache.xpath.internal.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
194     */
195    public void callArgVisitors(XPathVisitor visitor)
196    {
197      super.callArgVisitors(visitor);
198      if (null != m_args)
199      {
200        int n = m_args.length;
201        for (int i = 0; i < n; i++)
202        {
203          m_args[i].callVisitors(new ArgMultiOwner(i), visitor);
204        }
205      }
206    }
207
208    /**
209     * @see Expression#deepEquals(Expression)
210     */
211    public boolean deepEquals(Expression expr)
212    {
213      if (!super.deepEquals(expr))
214            return false;
215
216      FunctionMultiArgs fma = (FunctionMultiArgs) expr;
217      if (null != m_args)
218      {
219        int n = m_args.length;
220        if ((null == fma) || (fma.m_args.length != n))
221              return false;
222
223        for (int i = 0; i < n; i++)
224        {
225          if (!m_args[i].deepEquals(fma.m_args[i]))
226                return false;
227        }
228
229      }
230      else if (null != fma.m_args)
231      {
232          return false;
233      }
234
235      return true;
236    }
237}
238