PageRenderTime 156ms CodeModel.GetById 144ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 1ms

/jEdit/tags/jedit-4-2-pre4/bsh/ClassNameSpace.java

#
Java | 310 lines | 160 code | 36 blank | 114 comment | 38 complexity | 245a6bf69e61f92934ae109a4de3b1e0 MD5 | raw file
  1/*****************************************************************************
  2 *                                                                           *
  3 *  This file is part of the BeanShell Java Scripting distribution.          *
  4 *  Documentation and updates may be found at http://www.beanshell.org/      *
  5 *                                                                           *
  6 *  Sun Public License Notice:                                               *
  7 *                                                                           *
  8 *  The contents of this file are subject to the Sun Public License Version  *
  9 *  1.0 (the "License"); you may not use this file except in compliance with *
 10 *  the License. A copy of the License is available at http://www.sun.com    * 
 11 *                                                                           *
 12 *  The Original Code is BeanShell. The Initial Developer of the Original    *
 13 *  Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright     *
 14 *  (C) 2000.  All Rights Reserved.                                          *
 15 *                                                                           *
 16 *  GNU Public License Notice:                                               *
 17 *                                                                           *
 18 *  Alternatively, the contents of this file may be used under the terms of  *
 19 *  the GNU Lesser General Public License (the "LGPL"), in which case the    *
 20 *  provisions of LGPL are applicable instead of those above. If you wish to *
 21 *  allow use of your version of this file only under the  terms of the LGPL *
 22 *  and not to allow others to use your version of this file under the SPL,  *
 23 *  indicate your decision by deleting the provisions above and replace      *
 24 *  them with the notice and other provisions required by the LGPL.  If you  *
 25 *  do not delete the provisions above, a recipient may use your version of  *
 26 *  this file under either the SPL or the LGPL.                              *
 27 *                                                                           *
 28 *  Patrick Niemeyer (pat@pat.net)                                           *
 29 *  Author of Learning Java, O'Reilly & Associates                           *
 30 *  http://www.pat.net/~pat/                                                 *
 31 *                                                                           *
 32 *****************************************************************************/
 33
 34package	bsh;
 35
 36import java.util.Vector;
 37
 38/**
 39	A ClassNameSpace represents the body a scripted class definition or
 40	scripted class instance.  In the case of the class definition it serves as
 41	the Class object and holds the class initializer method (called before the
 42	constructor).
 43	<p/>
 44	When serving as a class definition, only static members are visible and
 45	attempting to access an instance member will cause a "can't reach instance
 46	from static context" exception.
 47	<p/>
 48	When serving as a class instance static members are dissallowed (except
 49	by the initializer) and are ignored, allowing them to be seen in the class
 50	definition.
 51	<p/>
 52	Class instances also serve as the top scope of instance variables declared
 53	within the class (by the initializer).
 54*/
 55/*
 56	This would obviously be cleaner if we made a second subclass of NameSpace:
 57	ClassInstanceNameSpace, however with code generation I think we'll only
 58	need one entity (the instance namespace) so let's leave both in here 
 59	for now. 
 60*/
 61class ClassNameSpace extends NameSpace 
 62{
 63	public static final int CLASS=1, INSTANCE=2;
 64	int type;
 65	//Class [] interfaces;
 66
 67    public ClassNameSpace( 
 68		NameSpace parent, String name, int type ) 
 69		throws EvalError
 70	{
 71		super( parent, name );
 72		this.type = type;
 73    }
 74
 75	/**
 76		Set the interfaces.  This is used by constructClassInstance() on 
 77		CLASS types.
 78	public setInterfaces( Class [] interfaces ) {
 79		this.interfaces = interfaces;
 80	}
 81	*/
 82
 83	/**
 84		@return may return null
 85	Class [] getInterfaces() 
 86	{
 87		if ( getParent() instanceof ClassNameSpace
 88			&& ((ClassNameSpace)getParent()).isClass() 
 89		)
 90		{
 91			// collect all interfaces from super chain
 92			ClassNameSpace cns = (ClassNameSpace)getParent();
 93			Vector v = new Vector();
 94		}
 95		else
 96			return interfaces;
 97	}
 98	*/
 99
100    public void	setVariable( String name, Object value, boolean strictJava ) 
101		throws UtilEvalError 
102	{
103		// class instance is top scope for loose vars
104		if ( isClassInstance() ) {
105			boolean recurse = false;
106			super.setVariable( name, value, strictJava, recurse );
107		}
108		super.setVariable( name, value, strictJava );
109	}
110
111	/**
112		This is a hook to allow ClassNameSpace to add functionality in
113		getVariableImpl()
114	*/
115	protected boolean isVisible( Variable var )
116		throws UtilEvalError
117	{
118		// If we are a class declaration space being asked for an instance
119		// variable throw an exception.
120		if ( isClass() && var != null && !var.hasModifier("static") )
121			throw new UtilEvalError( "Can't reach instance var: "+var.name
122					+" from static context: "+this);
123
124		// If we are a class instance ignore any static variables and allow
125		// them to be found in the static class space.
126		if ( isClassInstance() && var != null && var.hasModifier("static") )
127			return false;
128
129		return true;
130	}
131
132	/**
133		This is a hook to allow ClassNameSpace to add functionality to 
134		getMethod() 
135	*/
136	protected boolean isVisible( BshMethod method )
137		throws UtilEvalError
138	{
139		String name = null;
140		if ( method != null )
141			name = method.getName();
142
143		// If we are a class def space being asked for an instance
144		// method throw an exception.
145		if ( isClass() && method != null && !method.hasModifier("static") 
146			// Bit of a hack, allow us to see default constructor
147			&& !name.equals( BSHClassDeclaration.CLASSINITNAME )
148			// See regular constructors
149			&& !nsName.equals( name )
150		)
151			throw new UtilEvalError(
152				"Can't reach instance method: "+name
153				+" from static context: "+this);
154
155		// If we are a class instance ignore any static methods and allow
156		// them to be found in the static class space.
157		if ( isClassInstance() && method != null 
158			&& method.hasModifier("static") 
159		)
160			return false;
161
162		return true;
163	}
164
165	public boolean isClassInstance() { return type == INSTANCE ; }
166	public boolean isClass() { return type == CLASS; }
167
168	public This constructClassInstance( Object[] args, 
169		Interpreter interpreter, CallStack callstack, SimpleNode callerInfo ) 
170		throws EvalError
171	{
172		NameSpace classNameSpace = this;
173		String className = classNameSpace.getName();
174
175		// Get the default constructor
176		BshMethod classInitializer = null;
177		try {
178			classInitializer = 
179				classNameSpace.getMethod( 
180					BSHClassDeclaration.CLASSINITNAME, new Class[0] );
181		} catch ( UtilEvalError e ) { // shouldn't happen
182			throw e.toEvalError(
183				"Error getting default constructor", callerInfo, callstack );
184		}
185		if ( classInitializer == null )
186			throw new EvalError("Unable to find initializer for class.",
187				callerInfo, callstack);
188
189		// Get the (non-initializer) constructor, if any
190		Class [] sig = Reflect.getTypes( args );
191		BshMethod constructor = null;
192		try {
193			constructor = 
194				classNameSpace.getMethod( className, sig );
195		} catch ( UtilEvalError e ) { // shouldn't happen
196			throw e.toEvalError(
197				"Error getting constructor", callerInfo, callstack );
198		}
199		// No constructor found
200		if ( constructor == null )
201		{
202			// args constructor not found
203			if ( args.length > 0 )
204				throw new EvalError("Constructor not found: "+
205					StringUtil.methodString( className, sig ),
206					callerInfo, callstack );
207			else
208			// no args constructor missing. Ok if no other constructors exist
209			{
210				BshMethod [] methods = classNameSpace.getMethods();
211				for(int i=0; i<methods.length; i++)
212					if ( methods[i].getName().equals( className ) )
213						throw new EvalError(
214							"Default (no args) constructor not found: "+
215							StringUtil.methodString( className, sig ), 
216							callerInfo, callstack );
217			}
218		}
219
220		// Invoke the constructors
221
222		// Recurse to handle superclasses 
223		NameSpace superNameSpace = null; 
224		if ( classNameSpace.getParent() instanceof ClassNameSpace
225			&& ((ClassNameSpace)classNameSpace.getParent()).isClass()
226		)
227		{
228			// Call the superClass's default constructor
229
230			// Note: this isn't always right -
231			// We need to allow super() in the constructor()
232
233			This superInstance = 
234				((ClassNameSpace)classNameSpace.getParent())
235				.constructClassInstance( 
236					new Object[0], interpreter, callstack, callerInfo );
237
238			superNameSpace = superInstance.getNameSpace();
239		}
240
241		// Chain the instance namespaces
242		NameSpace instanceNameSpace;
243		if ( superNameSpace != null )
244			instanceNameSpace = new ClassNameSpace( 
245				superNameSpace, className, INSTANCE );
246		else
247			instanceNameSpace = new ClassNameSpace( 
248				classNameSpace, className, INSTANCE );
249
250		callstack.push( instanceNameSpace );
251
252		// Invoke the class initializer method
253		try {
254			classInitializer.invoke( 
255				new Object[0], interpreter, callstack, callerInfo, 
256				true/*overrideNameSpace*/ );
257		} catch ( EvalError e ) {
258			e.reThrow("Exception in default constructor: "+e);
259		}
260
261		// Call the specific constructor if any
262		if ( constructor != null )
263		{
264			try {
265				constructor.invoke( 
266					args, interpreter, callstack, callerInfo, 
267					true/*overrideNameSpace*/ );
268			} catch ( EvalError e ) {
269				e.reThrow("Exception in constructor: "+e);
270			}
271		}
272
273		callstack.pop();
274		
275		// return the initialized object
276		This instance = instanceNameSpace.getThis( interpreter );
277		return instance;
278	}
279
280	protected void checkVariableModifiers( String name, Modifiers modifiers )
281		throws UtilEvalError
282	{
283		// allow all valid inside class
284	}
285
286
287	protected void checkMethodModifiers( BshMethod method )
288		throws UtilEvalError
289	{
290		// allow all valid inside class
291	}
292
293
294	public String toString() 
295	{
296		return
297			"Scripted Class "
298			+(isClassInstance() ?  "Instance " : "")
299			+" : " +super.toString();
300	}
301
302	public static boolean isScriptedClass( Object obj )
303	{
304		return 
305			obj instanceof This 
306			&& ((This)obj).getNameSpace() instanceof ClassNameSpace 
307			&& ((ClassNameSpace)((This)obj).getNameSpace()).isClass();
308	}
309}
310