KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > bsh > BSHBinaryExpression


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 package bsh;
36
37 /**
38     Implement binary expressions...
39     Note: this is too complicated... need some cleanup and simplification.
40     @see Primitive.binaryOperation
41 */

42 class BSHBinaryExpression extends SimpleNode
43     implements ParserConstants
44 {
45     public int kind;
46
47     BSHBinaryExpression(int id) { super(id); }
48
49     public Object JavaDoc eval( CallStack callstack, Interpreter interpreter)
50         throws EvalError
51     {
52         Object JavaDoc lhs = ((SimpleNode)jjtGetChild(0)).eval(callstack, interpreter);
53
54         /*
55             Doing instanceof? Next node is a type.
56         */

57         if (kind == INSTANCEOF)
58         {
59             // null object ref is not instance of any type
60
if ( lhs == Primitive.NULL )
61                 return new Primitive(false);
62
63             Class JavaDoc rhs = ((BSHType)jjtGetChild(1)).getType(
64                 callstack, interpreter );
65         /*
66             // primitive (number or void) cannot be tested for instanceof
67             if (lhs instanceof Primitive)
68                 throw new EvalError("Cannot be instance of primitive type." );
69         */

70             /*
71                 Primitive (number or void) is not normally an instanceof
72                 anything. But for internal use we'll test true for the
73                 bsh.Primitive class.
74                 i.e. (5 instanceof bsh.Primitive) will be true
75             */

76             if ( lhs instanceof Primitive )
77                 if ( rhs == bsh.Primitive.class )
78                     return new Primitive(true);
79                 else
80                     return new Primitive(false);
81
82             // General case - performe the instanceof based on assignability
83
boolean ret = Types.isJavaBaseAssignable( rhs, lhs.getClass() );
84             return new Primitive(ret);
85         }
86
87
88         // The following two boolean checks were tacked on.
89
// This could probably be smoothed out.
90

91         /*
92             Look ahead and short circuit evaluation of the rhs if:
93                 we're a boolean AND and the lhs is false.
94         */

95         if ( kind == BOOL_AND || kind == BOOL_ANDX ) {
96             Object JavaDoc obj = lhs;
97             if ( isPrimitiveValue(lhs) )
98                 obj = ((Primitive)lhs).getValue();
99             if ( obj instanceof Boolean JavaDoc &&
100                 ( ((Boolean JavaDoc)obj).booleanValue() == false ) )
101                 return new Primitive(false);
102         }
103         /*
104             Look ahead and short circuit evaluation of the rhs if:
105                 we're a boolean AND and the lhs is false.
106         */

107         if ( kind == BOOL_OR || kind == BOOL_ORX ) {
108             Object JavaDoc obj = lhs;
109             if ( isPrimitiveValue(lhs) )
110                 obj = ((Primitive)lhs).getValue();
111             if ( obj instanceof Boolean JavaDoc &&
112                 ( ((Boolean JavaDoc)obj).booleanValue() == true ) )
113                 return new Primitive(true);
114         }
115
116         // end stuff that was tacked on for boolean short-circuiting.
117

118         /*
119             Are both the lhs and rhs either wrappers or primitive values?
120             do binary op
121         */

122         boolean isLhsWrapper = isWrapper( lhs );
123         Object JavaDoc rhs = ((SimpleNode)jjtGetChild(1)).eval(callstack, interpreter);
124         boolean isRhsWrapper = isWrapper( rhs );
125         if (
126             ( isLhsWrapper || isPrimitiveValue( lhs ) )
127             && ( isRhsWrapper || isPrimitiveValue( rhs ) )
128         )
129         {
130             // Special case for EQ on two wrapper objects
131
if ( (isLhsWrapper && isRhsWrapper && kind == EQ))
132             {
133                 /*
134                     Don't auto-unwrap wrappers (preserve identity semantics)
135                     FALL THROUGH TO OBJECT OPERATIONS BELOW.
136                 */

137             } else
138                 try {
139                     return Primitive.binaryOperation(lhs, rhs, kind);
140                 } catch ( UtilEvalError e ) {
141                     throw e.toEvalError( this, callstack );
142                 }
143         }
144     /*
145     Doing the following makes it hard to use untyped vars...
146     e.g. if ( arg == null ) ...what if arg is a primitive?
147     The answer is that we should test only if the var is typed...?
148     need to get that info here...
149
150         else
151         {
152         // Do we have a mixture of primitive values and non-primitives ?
153         // (primitiveValue = not null, not void)
154
155         int primCount = 0;
156         if ( isPrimitiveValue( lhs ) )
157             ++primCount;
158         if ( isPrimitiveValue( rhs ) )
159             ++primCount;
160
161         if ( primCount > 1 )
162             // both primitive types, should have been handled above
163             throw new InterpreterError("should not be here");
164         else
165         if ( primCount == 1 )
166             // mixture of one and the other
167             throw new EvalError("Operator: '" + tokenImage[kind]
168                 +"' inappropriate for object / primitive combination.",
169                 this, callstack );
170
171         // else fall through to handle both non-primitive types
172
173         // end check for primitive and non-primitive mix
174         }
175     */

176
177         /*
178             Treat lhs and rhs as arbitrary objects and do the operation.
179             (including NULL and VOID represented by their Primitive types)
180         */

181         //System.out.println("binary op arbitrary obj: {"+lhs+"}, {"+rhs+"}");
182
switch(kind)
183         {
184             case EQ:
185                 return new Primitive((lhs == rhs));
186
187             case NE:
188                 return new Primitive((lhs != rhs));
189
190             case PLUS:
191                 if(lhs instanceof String JavaDoc || rhs instanceof String JavaDoc)
192                     return lhs.toString() + rhs.toString();
193
194             // FALL THROUGH TO DEFAULT CASE!!!
195

196             default:
197                 if(lhs instanceof Primitive || rhs instanceof Primitive)
198                     if ( lhs == Primitive.VOID || rhs == Primitive.VOID )
199                         throw new EvalError(
200                 "illegal use of undefined variable, class, or 'void' literal",
201                             this, callstack );
202                     else
203                     if ( lhs == Primitive.NULL || rhs == Primitive.NULL )
204                         throw new EvalError(
205                 "illegal use of null value or 'null' literal", this, callstack);
206
207                 throw new EvalError("Operator: '" + tokenImage[kind] +
208                     "' inappropriate for objects", this, callstack );
209         }
210     }
211
212     /*
213         object is a non-null and non-void Primitive type
214     */

215     private boolean isPrimitiveValue( Object JavaDoc obj ) {
216         return ( (obj instanceof Primitive)
217             && (obj != Primitive.VOID) && (obj != Primitive.NULL) );
218     }
219
220     /*
221         object is a java.lang wrapper for boolean, char, or number type
222     */

223     private boolean isWrapper( Object JavaDoc obj ) {
224         return ( obj instanceof Boolean JavaDoc ||
225             obj instanceof Character JavaDoc || obj instanceof Number JavaDoc );
226     }
227 }
228
Popular Tags