001: /*****************************************************************************
002: * *
003: * This file is part of the BeanShell Java Scripting distribution. *
004: * Documentation and updates may be found at http://www.beanshell.org/ *
005: * *
006: * Sun Public License Notice: *
007: * *
008: * The contents of this file are subject to the Sun Public License Version *
009: * 1.0 (the "License"); you may not use this file except in compliance with *
010: * the License. A copy of the License is available at http://www.sun.com *
011: * *
012: * The Original Code is BeanShell. The Initial Developer of the Original *
013: * Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright *
014: * (C) 2000. All Rights Reserved. *
015: * *
016: * GNU Public License Notice: *
017: * *
018: * Alternatively, the contents of this file may be used under the terms of *
019: * the GNU Lesser General Public License (the "LGPL"), in which case the *
020: * provisions of LGPL are applicable instead of those above. If you wish to *
021: * allow use of your version of this file only under the terms of the LGPL *
022: * and not to allow others to use your version of this file under the SPL, *
023: * indicate your decision by deleting the provisions above and replace *
024: * them with the notice and other provisions required by the LGPL. If you *
025: * do not delete the provisions above, a recipient may use your version of *
026: * this file under either the SPL or the LGPL. *
027: * *
028: * Patrick Niemeyer (pat@pat.net) *
029: * Author of Learning Java, O'Reilly & Associates *
030: * http://www.pat.net/~pat/ *
031: * *
032: *****************************************************************************/package bsh;
033:
034: import java.util.Vector;
035:
036: /**
037: A stack of NameSpaces representing the call path.
038: Each method invocation, for example, pushes a new NameSpace onto the stack.
039: The top of the stack is always the current namespace of evaluation.
040: <p>
041:
042: This is used to support the this.caller magic reference and to print
043: script "stack traces" when evaluation errors occur.
044: <p>
045:
046: Note: it would be awefully nice to use the java.util.Stack here.
047: Sigh... have to stay 1.1 compatible.
048: <p>
049:
050: Note: How can this be thread safe, you might ask? Wouldn't a thread
051: executing various beanshell methods be mutating the callstack? Don't we
052: need one CallStack per Thread in the interpreter? The answer is that we do.
053: Any java.lang.Thread enters our script via an external (hard) Java
054: reference via a This type interface, e.g. the Runnable interface
055: implemented by This or an arbitrary interface implemented by XThis.
056: In that case the This invokeMethod() method (called by any interface that
057: it exposes) creates a new CallStack for each external call.
058: <p>
059: */
060: public class CallStack {
061: private Vector stack = new Vector(2);
062:
063: public CallStack() {
064: }
065:
066: public CallStack(NameSpace namespace) {
067: push(namespace);
068: }
069:
070: public void clear() {
071: stack.removeAllElements();
072: }
073:
074: public void push(NameSpace ns) {
075: stack.insertElementAt(ns, 0);
076: }
077:
078: public NameSpace top() {
079: return get(0);
080: }
081:
082: /**
083: zero based.
084: */
085: public NameSpace get(int depth) {
086: if (depth >= depth())
087: return NameSpace.JAVACODE;
088: else
089: return (NameSpace) (stack.elementAt(depth));
090: }
091:
092: /**
093: This is kind of crazy, but used by the setNameSpace command.
094: zero based.
095: */
096: public void set(int depth, NameSpace ns) {
097: stack.setElementAt(ns, depth);
098: }
099:
100: public NameSpace pop() {
101: if (depth() < 1)
102: throw new InterpreterError("pop on empty CallStack");
103: NameSpace top = top();
104: stack.removeElementAt(0);
105: return top;
106: }
107:
108: /**
109: Swap in the value as the new top of the stack and return the old
110: value.
111: */
112: public NameSpace swap(NameSpace newTop) {
113: NameSpace oldTop = (NameSpace) (stack.elementAt(0));
114: stack.setElementAt(newTop, 0);
115: return oldTop;
116: }
117:
118: public int depth() {
119: return stack.size();
120: }
121:
122: public NameSpace[] toArray() {
123: NameSpace[] nsa = new NameSpace[depth()];
124: stack.copyInto(nsa);
125: return nsa;
126: }
127:
128: public String toString() {
129: StringBuffer sb = new StringBuffer();
130: sb.append("CallStack:\n");
131: NameSpace[] nsa = toArray();
132: for (int i = 0; i < nsa.length; i++)
133: sb.append("\t" + nsa[i] + "\n");
134:
135: return sb.toString();
136: }
137:
138: /**
139: Occasionally we need to freeze the callstack for error reporting
140: purposes, etc.
141: */
142: public CallStack copy() {
143: CallStack cs = new CallStack();
144: cs.stack = (Vector) this.stack.clone();
145: return cs;
146: }
147: }
|