Home | History | Annotate | Download | only in functions
      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