sboag 00/12/19 21:00:35
Modified: java/src/org/apache/xpath VariableStack.java
Log:
Changed variable stack to be a stack of frames, which makes
everything a hell of a lot easier. When a frame is first pushed, it
is a static empty frame, and then is switched to a real frame if
a parameter or variable is pushed.
Revision Changes Path
1.16 +124 -63 xml-xalan/java/src/org/apache/xpath/VariableStack.java
Index: VariableStack.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/VariableStack.java,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- VariableStack.java 2000/12/18 00:04:53 1.15
+++ VariableStack.java 2000/12/20 05:00:34 1.16
@@ -74,15 +74,9 @@
/**
* <meta name="usage" content="internal"/>
* Defines a class to keep track of a stack for
- * template arguments and variables, since we can't
- * simply bind the variables to templates and walk
- * the preceding children and ancestors. The stack
- * is delimited by context markers which bound call
- * frames, and which you can't search past for a variable,
- * and by element frames, which are Arg objects with
- * the given ElemTemplateElement instead of a qname. You
- * can search past element frames, and they accumulate
- * until they are popped.
+ * template arguments and variables. The VariableStack extends
+ * Stack, and each element in the stack is a stack frame, i.e. a
+ * Stack itself. The zero element is the global stack frame.
*
* Note: Someone recently made the suggestion that the
* globals should not be kept at the bottom of the stack,
@@ -98,19 +92,24 @@
{
pushContextMarker();
}
-
+
/**
- * Hold the position of the start of the current element contexts.
+ * Pushes an item onto the top of this stack. This has exactly
+ * the same effect as:
+ * <blockquote><pre>
+ * addElement(item)</pre></blockquote>
+ *
+ * @param item the item to be pushed onto this stack.
+ * @return the <code>item</code> argument.
+ * @see java.util.Vector#addElement
*/
- private IntStack m_contextPositions = new IntStack();
+ public Object push(Object item)
+ {
+ if(!(item instanceof Stack))
+ throw new RuntimeException("You can only push a Stack on the
variable stack!");
- /** The top of the globals space. */
- private int m_globalStackFrameIndex = -1;
-
- /** Where to start the current search for a variable.
- * If this is -1, the search should start at the top
- * of the stack. */
- private int m_searchStart = -1;
+ return super.push(item);
+ }
/**
* Set where to start the current search for a variable.
@@ -135,7 +134,7 @@
*/
public int getSearchStartOrTop()
{
- return (-1 == m_searchStart) ? this.size() : m_searchStart;
+ return (-1 == m_searchStart) ? this.size()-1 : m_searchStart;
}
/**
@@ -151,11 +150,6 @@
}
/**
- * Hold the position of the start of the current element frame.
- */
- private IntStack m_elemFramePos = new IntStack();
-
- /**
* Mark the top of the global stack frame.
*/
public void markGlobalStackFrame()
@@ -170,7 +164,7 @@
*/
public void pushContextPosition(int pos)
{
- m_contextPositions.push(pos);
+ // m_contextPositions.push(pos);
}
/**
@@ -179,7 +173,7 @@
*/
public void popContextPosition()
{
- m_contextPositions.pop();
+ // m_contextPositions.pop();
}
/**
@@ -190,7 +184,8 @@
*/
public int getContextPos()
{
- return m_contextPositions.peek();
+ // return m_contextPositions.peek();
+ return this.size()-1;
}
/**
@@ -201,7 +196,8 @@
*/
public void pushContextMarker()
{
- m_contextPositions.push(this.size());
+ // m_contextPositions.push(this.size());
+ push(m_emptyStackFrame);
}
/**
@@ -210,12 +206,37 @@
public void popCurrentContext()
{
- int newSize = m_contextPositions.pop();
+ // int newSize = m_contextPositions.pop();
- setSize(newSize);
+ // setSize(newSize);
+ pop();
}
/**
+ * Get the current stack frame.
+ *
+ * @return non-null reference to current stack frame, which may be
+ * the global stack.
+ */
+ private Stack getCurrentFrame()
+ {
+ int stackFrameIndex = (-1 == m_searchStart) ? this.size()-1 :
m_searchStart;
+ return (Stack)this.elementAt(stackFrameIndex);
+ }
+
+ /**
+ * Allocate variables frame.
+ */
+ private Stack allocateCurrentFrame()
+ {
+ int stackFrameIndex = (-1 == m_searchStart) ? this.size()-1 :
m_searchStart;
+ Stack newFrame = new Stack();
+ this.setElementAt(newFrame, stackFrameIndex);
+ return newFrame;
+ }
+
+
+ /**
* Push an argument onto the stack, or replace it
* if it already exists. Don't forget
* to call startContext before pushing a series of
@@ -226,17 +247,18 @@
*/
public void pushOrReplaceVariable(QName qname, XObject xval)
{
- int n = this.size();
- for(int i = n-1; i >= 0; i--)
+ Stack frame = getCurrentFrame();
+
+ for (int i = (frame.size() - 1); i >= 0; i--)
{
- Arg arg = (Arg)this.elementAt(i);
+ Arg arg = (Arg)frame.elementAt(i);
if(arg.getQName().equals(qname))
{
this.setElementAt(new Arg(qname, xval), i);
return;
}
}
- push(new Arg(qname, xval, false));
+ frame.push(new Arg(qname, xval, false));
}
@@ -250,10 +272,29 @@
*/
public void pushVariable(QName qname, XObject val)
{
- push(new Arg(qname, val, false));
+ Stack frame = getCurrentFrame();
+ if(frame == m_emptyStackFrame)
+ frame = allocateCurrentFrame();
+ frame.push(new Arg(qname, val, false));
}
/**
+ * Push an argument onto the stack. Don't forget
+ * to call startContext before pushing a series of
+ * arguments for a given macro call.
+ *
+ * @param arg The variable argument.
+ */
+ public void pushVariableArg(Arg arg)
+ {
+ Stack frame = getCurrentFrame();
+ if(frame == m_emptyStackFrame)
+ frame = allocateCurrentFrame();
+ frame.push(arg);
+ }
+
+
+ /**
* Tell if a variable or parameter is already declared,
* either in the current context or in the global space.
*
@@ -266,26 +307,25 @@
public boolean variableIsDeclared(QName qname) throws TransformerException
{
- int nElems = (-1 == m_searchStart) ? this.size() : m_searchStart;
- int endContextPos = m_contextPositions.peek();
-
- for (int i = (nElems - 1); i >= endContextPos; i--)
+ Stack frame = getCurrentFrame();
+
+ for (int i = (frame.size() - 1); i >= 0; i--)
{
- Object obj = elementAt(i);
+ Object obj = frame.elementAt(i);
if (((Arg) obj).getQName().equals(qname))
{
return true;
}
}
-
- if(endContextPos < m_globalStackFrameIndex)
+
+ Stack gframe = (Stack)this.elementAt(0);
+ if(gframe == frame)
return false;
- // Look in the global space
- for (int i = (m_globalStackFrameIndex - 1); i >= 0; i--)
+ for (int i = (gframe.size() - 1); i >= 0; i--)
{
- Object obj = elementAt(i);
+ Object obj = gframe.elementAt(i);
if (((Arg) obj).getQName().equals(qname))
{
@@ -311,12 +351,11 @@
{
XObject val = null;
- int nElems = (-1 == m_searchStart) ? this.size() : m_searchStart;
- int endContextPos = m_contextPositions.peek();
-
- for (int i = (nElems - 1); i >= endContextPos; i--)
+ Stack frame = getCurrentFrame();
+
+ for (int i = (frame.size() - 1); i >= 0; i--)
{
- Arg arg = (Arg)elementAt(i);
+ Arg arg = (Arg)frame.elementAt(i);
if (arg.getQName().equals(qname))
{
@@ -347,13 +386,12 @@
*/
public XObject getVariable(XPathContext xctxt, QName name) throws
TransformerException
{
-
- int nElems = (-1 == m_searchStart) ? this.size() : m_searchStart;
- int endContextPos = m_contextPositions.peek();
- for (int i = (nElems - 1); i >= endContextPos; i--)
+ Stack frame = getCurrentFrame();
+
+ for (int i = (frame.size() - 1); i >= 0; i--)
{
- Arg arg = (Arg) elementAt(i);
+ Arg arg = (Arg)frame.elementAt(i);
if (arg.getQName().equals(name))
{
@@ -367,13 +405,13 @@
}
}
- if(endContextPos < m_globalStackFrameIndex)
+ Stack gframe = (Stack)this.elementAt(0);
+ if(gframe == frame)
return null;
-
- // Look in the global space
- for (int i = (m_globalStackFrameIndex - 1); i >= 0; i--)
+
+ for (int i = (gframe.size() - 1); i >= 0; i--)
{
- Arg arg = (Arg)elementAt(i);
+ Arg arg = (Arg)gframe.elementAt(i);
if (arg.getQName().equals(name))
{
@@ -397,7 +435,9 @@
*/
public void pushElemFrame()
{
- m_elemFramePos.push(this.size());
+ Stack frame = getCurrentFrame();
+
+ m_elemFramePos.push(frame.size());
}
/**
@@ -406,9 +446,30 @@
public void popElemFrame()
{
+ Stack frame = getCurrentFrame();
int newSize = m_elemFramePos.pop();
- setSize(newSize);
+ frame.setSize(newSize);
}
+
+
+ /**
+ * Hold the position of the start of the current element frame.
+ */
+ private IntStack m_elemFramePos = new IntStack();
+
+ /**
+ * Hold the position of the start of the current element contexts.
+ */
+ private static final Stack m_emptyStackFrame = new Stack();
+
+ /** The top of the globals space. */
+ private int m_globalStackFrameIndex = -1;
+
+ /** Where to start the current search for a variable.
+ * If this is -1, the search should start at the top
+ * of the stack. */
+ private int m_searchStart = -1;
+
} // end XSLArgStack