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 org.gjt.sp.jedit.bsh;
033:
034: import java.util.Vector;
035:
036: class BSHTryStatement extends SimpleNode {
037: BSHTryStatement(int id) {
038: super (id);
039: }
040:
041: public Object eval(CallStack callstack, Interpreter interpreter)
042: throws EvalError {
043: BSHBlock tryBlock = ((BSHBlock) jjtGetChild(0));
044:
045: Vector catchParams = new Vector();
046: Vector catchBlocks = new Vector();
047:
048: int nchild = jjtGetNumChildren();
049: Node node = null;
050: int i = 1;
051: while ((i < nchild)
052: && ((node = jjtGetChild(i++)) instanceof BSHFormalParameter)) {
053: catchParams.addElement(node);
054: catchBlocks.addElement(jjtGetChild(i++));
055: node = null;
056: }
057: // finaly block
058: BSHBlock finallyBlock = null;
059: if (node != null)
060: finallyBlock = (BSHBlock) node;
061:
062: // Why both of these?
063:
064: TargetError target = null;
065: Throwable thrown = null;
066: Object ret = null;
067:
068: /*
069: Evaluate the contents of the try { } block and catch any resulting
070: TargetErrors generated by the script.
071: We save the callstack depth and if an exception is thrown we pop
072: back to that depth before contiuing. The exception short circuited
073: any intervening method context pops.
074:
075: Note: we the stack info... what do we do with it? append
076: to exception message?
077: */
078: int callstackDepth = callstack.depth();
079: try {
080: ret = tryBlock.eval(callstack, interpreter);
081: } catch (TargetError e) {
082: target = e;
083: String stackInfo = "Bsh Stack: ";
084: while (callstack.depth() > callstackDepth)
085: stackInfo += "\t" + callstack.pop() + "\n";
086: }
087:
088: // unwrap the target error
089: if (target != null)
090: thrown = target.getTarget();
091:
092: // If we have an exception, find a catch
093: if (thrown != null) {
094: int n = catchParams.size();
095: for (i = 0; i < n; i++) {
096: // Get catch block
097: BSHFormalParameter fp = (BSHFormalParameter) catchParams
098: .elementAt(i);
099:
100: // Should cache this subject to classloader change message
101: // Evaluation of the formal parameter simply resolves its
102: // type via the specified namespace.. it doesn't modify the
103: // namespace.
104: fp.eval(callstack, interpreter);
105:
106: if (fp.type == null && interpreter.getStrictJava())
107: throw new EvalError(
108: "(Strict Java) Untyped catch block", this ,
109: callstack);
110:
111: // If the param is typed check assignability
112: if (fp.type != null)
113: try {
114: thrown = (Throwable) Types.castObject(
115: thrown/*rsh*/, fp.type/*lhsType*/,
116: Types.ASSIGNMENT);
117: } catch (UtilEvalError e) {
118: /*
119: Catch the mismatch and continue to try the next
120: Note: this is innefficient, should have an
121: isAssignableFrom() that doesn't throw
122: // TODO: we do now have a way to test assignment
123: // in castObject(), use it?
124: */
125: continue;
126: }
127:
128: // Found match, execute catch block
129: BSHBlock cb = (BSHBlock) (catchBlocks.elementAt(i));
130:
131: // Prepare to execute the block.
132: // We must create a new BlockNameSpace to hold the catch
133: // parameter and swap it on the stack after initializing it.
134:
135: NameSpace enclosingNameSpace = callstack.top();
136: BlockNameSpace cbNameSpace = new BlockNameSpace(
137: enclosingNameSpace);
138:
139: try {
140: if (fp.type == BSHFormalParameter.UNTYPED)
141: // set an untyped variable directly in the block
142: cbNameSpace.setBlockVariable(fp.name, thrown);
143: else {
144: // set a typed variable (directly in the block)
145: Modifiers modifiers = new Modifiers();
146: cbNameSpace.setTypedVariable(fp.name, fp.type,
147: thrown, new Modifiers()/*none*/);
148: }
149: } catch (UtilEvalError e) {
150: throw new InterpreterError(
151: "Unable to set var in catch block namespace.");
152: }
153:
154: // put cbNameSpace on the top of the stack
155: callstack.swap(cbNameSpace);
156: try {
157: ret = cb.eval(callstack, interpreter);
158: } finally {
159: // put it back
160: callstack.swap(enclosingNameSpace);
161: }
162:
163: target = null; // handled target
164: break;
165: }
166: }
167:
168: // evaluate finally block
169: if (finallyBlock != null)
170: ret = finallyBlock.eval(callstack, interpreter);
171:
172: // exception fell through, throw it upward...
173: if (target != null)
174: throw target;
175:
176: if (ret instanceof ReturnControl)
177: return ret;
178: else
179: return Primitive.VOID;
180: }
181: }
|