PageRenderTime 128ms CodeModel.GetById 119ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre3/bsh/BSHPrimarySuffix.java

#
Java | 216 lines | 123 code | 24 blank | 69 comment | 17 complexity | f0de1882d345e066a7419d2e1633b056 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
 34
 35/*
 36	Warning: this is a hack... should be unified with BSHLHSPrimarySuffix
 37*/
 38package bsh;
 39
 40import java.util.Hashtable;
 41import java.lang.reflect.Array;
 42import java.lang.reflect.InvocationTargetException;
 43
 44class BSHPrimarySuffix extends SimpleNode
 45{
 46	public static final int
 47		CLASS = 0,
 48		INDEX = 1,
 49		NAME = 2,
 50		PROPERTY = 3;
 51
 52	public int operation;
 53	Object index;
 54	public String field;
 55
 56	BSHPrimarySuffix(int id) { super(id); }
 57
 58	/*
 59		Perform a suffix operation on the given object and return the 
 60		new value.
 61
 62		obj will be a Node when suffix evaluation begins, allowing us to
 63		interpret it contextually. (e.g. for .class) Thereafter it will be 
 64		a normal object.
 65	*/
 66	public Object doSuffix(
 67		Object obj, CallStack callstack, Interpreter interpreter) 
 68		throws EvalError
 69	{
 70		// Handle ".class" suffix operation
 71		/*
 72		if ( operation == CLASS )
 73			if ( obj instanceof BSHAmbiguousName ) {
 74				NameSpace namespace = callstack.top();
 75				return ((BSHAmbiguousName)obj).toClass( namespace );
 76			} else
 77				throw new EvalError(
 78					"Attemp to .class on non class...", this);
 79		*/
 80		if ( operation == CLASS )
 81			if ( obj instanceof BSHType ) {
 82				NameSpace namespace = callstack.top();
 83				return ((BSHType)obj).getType( namespace );
 84			} else
 85				throw new EvalError(
 86					"Attemp to invoke .class on non class.", this);
 87
 88		// Handle other suffix operations
 89
 90		/*
 91			eval( ) the node to an object
 92
 93			Note: This construct is now necessary where the node may be
 94			an ambiguous name.  If this becomes common we might want to 
 95			make a static method nodeToObject() or something.
 96		*/
 97		if ( obj instanceof SimpleNode )
 98			if ( obj instanceof BSHAmbiguousName )
 99				obj = ((BSHAmbiguousName)obj).toObject(callstack, interpreter);
100			else
101				obj = ((SimpleNode)obj).eval(callstack, interpreter);	
102
103		try
104		{
105			switch(operation)
106			{
107				case INDEX:
108					return doIndex(obj, callstack, interpreter );
109
110				case NAME:
111					return doName(obj, callstack, interpreter );
112
113				case PROPERTY:
114					return doProperty(obj, callstack, interpreter );
115
116				default:
117					throw new InterpreterError("LHS suffix");
118			} 
119		}
120		catch(ReflectError e)
121		{
122			throw new EvalError("reflection error: " + e, this);
123		}
124		catch(InvocationTargetException e)
125		{
126			throw new TargetError(
127				"target exception", e.getTargetException(), this, true);
128		}
129	}
130
131	/*
132		Field access or a method invocation
133		Field access might be .length on an array
134	*/
135	private Object doName(
136		Object obj, CallStack callstack, Interpreter interpreter) 
137		throws EvalError, ReflectError, InvocationTargetException
138	{
139		if(field.equals("length") && obj.getClass().isArray())
140			return new Primitive(Array.getLength(obj));
141		
142		if (jjtGetNumChildren() == 0)
143			// field access
144			return Reflect.getObjectField(obj, field);
145		else
146		{
147			// method invocation
148			Object[] oa = ((BSHArguments)jjtGetChild(0)).getArguments(
149				callstack, interpreter);
150			try {
151				return Reflect.invokeObjectMethod(interpreter, obj, field, oa, this);
152			} catch ( EvalError ee ) {
153				// catch and re-throw to get line number right
154				throw new EvalError( ee.getMessage(), this );
155			}
156		}
157	}
158
159	private Object doIndex(
160		Object obj, CallStack callstack, Interpreter interpreter) 
161		throws EvalError, ReflectError
162	{
163		if(!obj.getClass().isArray())
164			throw new EvalError("Not an array", this);
165
166		int index;
167		try
168		{
169			Primitive val = (Primitive)(((SimpleNode)jjtGetChild(0)).eval(
170				callstack, interpreter ));
171			index = val.intValue();
172		}
173		catch(Exception e)
174		{
175			throw new EvalError("You can only index arrays by integer types", this);
176		}
177
178		return Reflect.getIndex(obj, index);
179	}
180
181	private Object doProperty( 
182		Object obj, CallStack callstack, Interpreter interpreter ) 
183		throws EvalError
184	{
185		if(obj == Primitive.VOID)
186			throw new EvalError("Attempt to access property on undefined variable or class name", this);
187
188		if(obj instanceof Primitive)
189			throw new EvalError("Attempt to access property on a primitive", this);
190
191		Object value = ((SimpleNode)jjtGetChild(0)).eval(
192			callstack, interpreter);
193		if(!(value instanceof String))
194			throw new EvalError("Property expression must be a String or identifier.", this);
195
196		// property style access to hashtable
197		if(obj instanceof Hashtable)
198		{
199			Object val = ((Hashtable)obj).get((String)value);
200			if(val == null)
201				val = Primitive.NULL;
202			return val;
203		}
204
205		try
206		{
207			return Reflect.getObjectProperty(obj, (String)value);
208		}
209		catch(ReflectError e)
210		{
211			Interpreter.debug(e.toString());
212			throw new EvalError("No such property: " + value, this);
213		}
214	}
215}
216