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: /**
035: A specialized namespace for Blocks (e.g. the body of a "for" statement).
036: The Block acts like a child namespace but only for typed variables
037: declared within it (block local scope) or untyped variables explicitly set
038: in it via setBlockVariable(). Otherwise variable assignment
039: (including untyped variable usage) acts like it is part of the containing
040: block.
041: <p>
042: */
043: /*
044: Note: This class essentially just delegates most of its methods to its
045: parent. The setVariable() indirection is very small. We could probably
046: fold this functionality back into the base NameSpace as a special case.
047: But this has changed a few times so I'd like to leave this abstraction for
048: now.
049: */
050: class BlockNameSpace extends NameSpace {
051: public BlockNameSpace(NameSpace parent) throws EvalError {
052: super (parent, parent.getName() + "/BlockNameSpace");
053: }
054:
055: /**
056: Override the standard namespace behavior to make assignments
057: happen in our parent (enclosing) namespace, unless the variable has
058: already been assigned here via a typed declaration or through
059: the special setBlockVariable() (used for untyped args in try/catch).
060: <p>
061: i.e. only allow typed var declaration to happen in this namespace.
062: Typed vars are handled in the ordinary way local scope. All untyped
063: assignments are delegated to the enclosing context.
064: */
065: /*
066: Note: it may see like with the new 1.3 scoping this test could be
067: removed, but it cannot. When recurse is false we still need to set the
068: variable in our parent, not here.
069: */
070: public void setVariable(String name, Object value,
071: boolean strictJava, boolean recurse) throws UtilEvalError {
072: if (weHaveVar(name))
073: // set the var here in the block namespace
074: super .setVariable(name, value, strictJava, false);
075: else
076: // set the var in the enclosing (parent) namespace
077: getParent().setVariable(name, value, strictJava, recurse);
078: }
079:
080: /**
081: Set an untyped variable in the block namespace.
082: The BlockNameSpace would normally delegate this set to the parent.
083: Typed variables are naturally set locally.
084: This is used in try/catch block argument.
085: */
086: public void setBlockVariable(String name, Object value)
087: throws UtilEvalError {
088: super .setVariable(name, value, false/*strict?*/, false);
089: }
090:
091: /**
092: We have the variable: either it was declared here with a type, giving
093: it block local scope or an untyped var was explicitly set here via
094: setBlockVariable().
095: */
096: private boolean weHaveVar(String name) {
097: // super.variables.containsKey( name ) not any faster, I checked
098: try {
099: return super .getVariableImpl(name, false) != null;
100: } catch (UtilEvalError e) {
101: return false;
102: }
103: }
104:
105: /**
106: Get the actual BlockNameSpace 'this' reference.
107: <p/>
108: Normally a 'this' reference to a BlockNameSpace (e.g. if () { } )
109: resolves to the parent namespace (e.g. the namespace containing the
110: "if" statement). However when code inside the BlockNameSpace needs to
111: resolve things relative to 'this' we must use the actual block's 'this'
112: reference. Name.java is smart enough to handle this using
113: getBlockThis().
114: @see #getThis( Interpreter )
115: This getBlockThis( Interpreter declaringInterpreter )
116: {
117: return super.getThis( declaringInterpreter );
118: }
119: */
120:
121: //
122: // Begin methods which simply delegate to our parent (enclosing scope)
123: //
124: /**
125: This method recurses to find the nearest non-BlockNameSpace parent.
126:
127: public NameSpace getParent()
128: {
129: NameSpace parent = super.getParent();
130: if ( parent instanceof BlockNameSpace )
131: return parent.getParent();
132: else
133: return parent;
134: }
135: */
136: /** do we need this? */
137: private NameSpace getNonBlockParent() {
138: NameSpace parent = super .getParent();
139: if (parent instanceof BlockNameSpace)
140: return ((BlockNameSpace) parent).getNonBlockParent();
141: else
142: return parent;
143: }
144:
145: /**
146: Get a 'this' reference is our parent's 'this' for the object closure.
147: e.g. Normally a 'this' reference to a BlockNameSpace (e.g. if () { } )
148: resolves to the parent namespace (e.g. the namespace containing the
149: "if" statement).
150: @see #getBlockThis( Interpreter )
151: */
152: public This getThis(Interpreter declaringInterpreter) {
153: return getNonBlockParent().getThis(declaringInterpreter);
154: }
155:
156: /**
157: super is our parent's super
158: */
159: public This getSuper(Interpreter declaringInterpreter) {
160: return getNonBlockParent().getSuper(declaringInterpreter);
161: }
162:
163: /**
164: delegate import to our parent
165: */
166: public void importClass(String name) {
167: getParent().importClass(name);
168: }
169:
170: /**
171: delegate import to our parent
172: */
173: public void importPackage(String name) {
174: getParent().importPackage(name);
175: }
176:
177: public void setMethod(String name, BshMethod method)
178: throws UtilEvalError {
179: getParent().setMethod(name, method);
180: }
181: }
|