blob: 31c6b812c1c6c090c9ada566e2d86f0afd07d9ad [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Lotus
* Development Corporation., http://www.lotus.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xpath;
import org.apache.xpath.XPathContext;
import org.apache.xpath.objects.XObject;
import javax.xml.transform.TransformerException;
/**
* <meta name="usage" content="internal"/>
* Defines a class to keep track of a stack for
* template arguments and variables.
*
* <p>This has been changed from the previous incarnations of this
* class to be fairly low level.</p>
*/
public final class VariableStack implements Cloneable
{
/**
* Constructor for a variable stack.
*/
public VariableStack()
{
reset();
}
/**
* Returns a clone of this variable stack.
*
* @return a clone of this variable stack.
*
* @throws CloneNotSupportedException
*/
public synchronized Object clone() throws CloneNotSupportedException
{
VariableStack vs = (VariableStack) super.clone();
// I *think* I can get away with a shallow clone here?
vs._sf = (XObject[]) _sf.clone();
vs._links = (int[]) _links.clone();
return vs;
}
/**
* The stack frame where all variables and params will be kept.
* @serial
*/
XObject[] _sf = new XObject[XPathContext.RECURSIONLIMIT * 2];
/**
* The top of the stack frame (<code>_sf</code>).
* @serial
*/
int _top;
/**
* The bottom index of the current frame (relative to <code>_sf</code>).
* @serial
*/
private int _cfb;
/**
* The stack of frame positions. I call 'em links because of distant
* <a href="http://math.millikin.edu/mprogers/Courses/currentCourses/CS481-ComputerArchitecture/cs481.Motorola68000.html">
* Motorola 68000 assembler</a> memories. :-)
* @serial
*/
int[] _links = new int[XPathContext.RECURSIONLIMIT];
/**
* The top of the links stack.
*/
int _linksTop;
/**
* Get the element at the given index, regardless of stackframe.
*
* @param i index from zero.
*
* @return The item at the given index.
*/
public final XObject elementAt(final int i)
{
return _sf[i];
}
/**
* Get size of the stack.
*
* @return the total size of the execution stack.
*/
public final int size()
{
return _top;
}
/**
* Reset the stack to a start position.
*
* @return the total size of the execution stack.
*/
public final void reset()
{
_top = 0;
_linksTop = 0;
// Adding one here to the stack of frame positions will allow us always
// to look one under without having to check if we're at zero.
// (As long as the caller doesn't screw up link/unlink.)
_links[_linksTop++] = 0;
}
/**
* Set the current stack frame.
*
* @param sf The new stack frame position.
*/
public final void setStackFrame(int sf)
{
_cfb = sf;
}
/**
* Get the position from where the search should start,
* which is either the searchStart property, or the top
* of the stack if that value is -1.
*
* @return The current stack frame position.
*/
public final int getStackFrame()
{
return _cfb;
}
/**
* Allocates memory (called a stackframe) on the stack; used to store
* local variables and parameter arguments.
*
* <p>I use the link/unlink concept because of distant
* <a href="http://math.millikin.edu/mprogers/Courses/currentCourses/CS481-ComputerArchitecture/cs481.Motorola68000.html">
* Motorola 68000 assembler</a> memories.</p>
*
* @param size The size of the stack frame allocation. This ammount should
* normally be the maximum number of variables that you can have allocated
* at one time in the new stack frame.
*
* @return The bottom of the stack frame, from where local variable addressing
* should start from.
*/
public final int link(final int size)
{
_cfb = _top;
_top += size;
if (_top >= _sf.length)
{
XObject newsf[] = new XObject[_sf.length + (1024 * 4) + size];
System.arraycopy(_sf, 0, newsf, 0, _sf.length);
_sf = newsf;
}
if (_linksTop+1 >= _links.length)
{
int newlinks[] = new int[_links.length + (1024 * 2)];
System.arraycopy(_links, 0, newlinks, 0, _links.length);
_links = newlinks;
}
_links[_linksTop++] = _cfb;
return _cfb;
}
/**
* Free up the stack frame that was last allocated with
* {@link link(int size)}.
*/
public final void unlink()
{
_top = _links[--_linksTop];
_cfb = _links[_linksTop - 1];
}
/**
* Set a local variable or parameter in the current stack frame.
*
*
* @param index Local variable index relative to the current stack
* frame bottom.
*
* @param val The value of the variable that is being set.
*/
public final void setLocalVariable(int index, XObject val)
{
_sf[index+_cfb] = val;
}
/**
* Set a local variable or parameter in the specified stack frame.
*
*
* @param index Local variable index relative to the current stack
* frame bottom.
*
* @param val The value of the variable that is being set.
*/
public final void setLocalVariable(int index, XObject val, int stackFrame)
{
_sf[index+stackFrame] = val;
}
/**
* Get a local variable or parameter in the current stack frame.
*
*
* @param xctxt The XPath context, which must be passed in order to
* lazy evaluate variables.
*
* @param index Local variable index relative to the current stack
* frame bottom.
*
* @return The value of the variable.
*
* @throws TransformerException
*/
public final XObject getLocalVariable(XPathContext xctxt, int index)
throws TransformerException
{
index += _cfb;
XObject val = _sf[index];
// Lazy execution of variables.
if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
return (_sf[index] = val.execute(xctxt));
return val;
}
/**
* Get a local variable or parameter in the current stack frame.
*
*
* @param index Local variable index relative to the given
* frame bottom.
*
* @return The value of the variable.
*
* @throws TransformerException
*/
public final XObject getLocalVariable(int index, int frame)
throws TransformerException
{
index += frame;
XObject val = _sf[index];
return val;
}
/**
* Tell if a local variable has been set or not.
*
* @param index Local variable index relative to the current stack
* frame bottom.
*
* @return true if the value at the index is not null.
*
* @throws TransformerException
*/
public final boolean isLocalSet(int index)
throws TransformerException
{
return (_sf[index + _cfb] != null);
}
private static XObject[] m_nulls = new XObject[1024];
/**
* Use this to clear the variables in a section of the stack. This is
* used to clear the parameter section of the stack, so that default param
* values can tell if they've already been set. It is important to note that
* this function has a 1K limitation.
*
* @param start The start position, relative to the current local stack frame.
* @param len The number of slots to be cleared.
*/
public final void clearLocalSlots(int start, int len)
{
start+=_cfb;
System.arraycopy(m_nulls, 0, _sf, start, len);
}
/**
* Set a global variable or parameter in the global stack frame.
*
*
* @param index Local variable index relative to the global stack frame
* bottom.
*
* @param val The value of the variable that is being set.
*/
public final void setGlobalVariable(final int index, final XObject val)
{
_sf[index] = val;
}
/**
* Get a global variable or parameter from the global stack frame.
*
*
* @param xctxt The XPath context, which must be passed in order to
* lazy evaluate variables.
*
* @param index Global variable index relative to the global stack
* frame bottom.
*
* @return The value of the variable.
*
* @throws TransformerException
*/
public final XObject getGlobalVariable(XPathContext xctxt, final int index)
throws TransformerException
{
XObject val = _sf[index];
// Lazy execution of variables.
if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
return (_sf[index] = val.execute(xctxt));
return val;
}
} // end VariableStack