PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/bsh/BSHBinaryExpression.java

#
Java | 227 lines | 89 code | 21 blank | 117 comment | 52 complexity | 8f8c2c36f01e38ec5a6300475162b912 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  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. package bsh;
  34. /**
  35. Implement binary expressions...
  36. Note: this is too complicated... need some cleanup and simplification.
  37. @see Primitive.binaryOperation
  38. */
  39. class BSHBinaryExpression extends SimpleNode
  40. implements ParserConstants
  41. {
  42. public int kind;
  43. BSHBinaryExpression(int id) { super(id); }
  44. public Object eval( CallStack callstack, Interpreter interpreter)
  45. throws EvalError
  46. {
  47. Object lhs = ((SimpleNode)jjtGetChild(0)).eval(callstack, interpreter);
  48. /*
  49. Doing instanceof? Next node is a type.
  50. */
  51. if (kind == INSTANCEOF)
  52. {
  53. // null object ref is not instance of any type
  54. if ( lhs == Primitive.NULL )
  55. return new Primitive(false);
  56. Class rhs = ((BSHType)jjtGetChild(1)).getType(
  57. callstack, interpreter );
  58. /*
  59. // primitive (number or void) cannot be tested for instanceof
  60. if (lhs instanceof Primitive)
  61. throw new EvalError("Cannot be instance of primitive type." );
  62. */
  63. /*
  64. Primitive (number or void) is not normally an instanceof
  65. anything. But for internal use we'll test true for the
  66. bsh.Primitive class.
  67. i.e. (5 instanceof bsh.Primitive) will be true
  68. */
  69. if ( lhs instanceof Primitive )
  70. if ( rhs == bsh.Primitive.class )
  71. return new Primitive(true);
  72. else
  73. return new Primitive(false);
  74. // General case - performe the instanceof based on assignability
  75. boolean ret = Types.isJavaAssignable( rhs, lhs.getClass() );
  76. return new Primitive(ret);
  77. }
  78. // The following two boolean checks were tacked on.
  79. // This could probably be smoothed out.
  80. /*
  81. Look ahead and short circuit evaluation of the rhs if:
  82. we're a boolean AND and the lhs is false.
  83. */
  84. if ( kind == BOOL_AND || kind == BOOL_ANDX ) {
  85. Object obj = lhs;
  86. if ( isPrimitiveValue(lhs) )
  87. obj = ((Primitive)lhs).getValue();
  88. if ( obj instanceof Boolean &&
  89. ( ((Boolean)obj).booleanValue() == false ) )
  90. return new Primitive(false);
  91. }
  92. /*
  93. Look ahead and short circuit evaluation of the rhs if:
  94. we're a boolean AND and the lhs is false.
  95. */
  96. if ( kind == BOOL_OR || kind == BOOL_ORX ) {
  97. Object obj = lhs;
  98. if ( isPrimitiveValue(lhs) )
  99. obj = ((Primitive)lhs).getValue();
  100. if ( obj instanceof Boolean &&
  101. ( ((Boolean)obj).booleanValue() == true ) )
  102. return new Primitive(true);
  103. }
  104. // end stuff that was tacked on for boolean short-circuiting.
  105. /*
  106. Are both the lhs and rhs either wrappers or primitive values?
  107. do binary op
  108. */
  109. boolean isLhsWrapper = isWrapper( lhs );
  110. Object rhs = ((SimpleNode)jjtGetChild(1)).eval(callstack, interpreter);
  111. boolean isRhsWrapper = isWrapper( rhs );
  112. if (
  113. ( isLhsWrapper || isPrimitiveValue( lhs ) )
  114. && ( isRhsWrapper || isPrimitiveValue( rhs ) )
  115. )
  116. {
  117. // Special case for EQ on two wrapper objects
  118. if ( (isLhsWrapper && isRhsWrapper && kind == EQ))
  119. {
  120. /*
  121. Don't auto-unwrap wrappers (preserve identity semantics)
  122. FALL THROUGH TO OBJECT OPERATIONS BELOW.
  123. */
  124. } else
  125. try {
  126. return Primitive.binaryOperation(lhs, rhs, kind);
  127. } catch ( UtilEvalError e ) {
  128. throw e.toEvalError( this, callstack );
  129. }
  130. }
  131. /*
  132. Doing the following makes it hard to use untyped vars...
  133. e.g. if ( arg == null ) ...what if arg is a primitive?
  134. The answer is that we should test only if the var is typed...?
  135. need to get that info here...
  136. else
  137. {
  138. // Do we have a mixture of primitive values and non-primitives ?
  139. // (primitiveValue = not null, not void)
  140. int primCount = 0;
  141. if ( isPrimitiveValue( lhs ) )
  142. ++primCount;
  143. if ( isPrimitiveValue( rhs ) )
  144. ++primCount;
  145. if ( primCount > 1 )
  146. // both primitive types, should have been handled above
  147. throw new InterpreterError("should not be here");
  148. else
  149. if ( primCount == 1 )
  150. // mixture of one and the other
  151. throw new EvalError("Operator: '" + tokenImage[kind]
  152. +"' inappropriate for object / primitive combination.",
  153. this, callstack );
  154. // else fall through to handle both non-primitive types
  155. // end check for primitive and non-primitive mix
  156. }
  157. */
  158. /*
  159. Treat lhs and rhs as arbitrary objects and do the operation.
  160. (including NULL and VOID represented by their Primitive types)
  161. */
  162. //System.out.println("binary op arbitrary obj: {"+lhs+"}, {"+rhs+"}");
  163. switch(kind)
  164. {
  165. case EQ:
  166. return new Primitive((lhs == rhs));
  167. case NE:
  168. return new Primitive((lhs != rhs));
  169. case PLUS:
  170. if(lhs instanceof String || rhs instanceof String)
  171. return lhs.toString() + rhs.toString();
  172. // FALL THROUGH TO DEFAULT CASE!!!
  173. default:
  174. if(lhs instanceof Primitive || rhs instanceof Primitive)
  175. if ( lhs == Primitive.VOID || rhs == Primitive.VOID )
  176. throw new EvalError(
  177. "illegal use of undefined variable, class, or 'void' literal",
  178. this, callstack );
  179. else
  180. if ( lhs == Primitive.NULL || rhs == Primitive.NULL )
  181. throw new EvalError(
  182. "illegal use of null value or 'null' literal", this, callstack);
  183. throw new EvalError("Operator: '" + tokenImage[kind] +
  184. "' inappropriate for objects", this, callstack );
  185. }
  186. }
  187. /*
  188. object is a non-null and non-void Primitive type
  189. */
  190. private boolean isPrimitiveValue( Object obj ) {
  191. return ( (obj instanceof Primitive)
  192. && (obj != Primitive.VOID) && (obj != Primitive.NULL) );
  193. }
  194. /*
  195. object is a java.lang wrapper for boolean, char, or number type
  196. */
  197. private boolean isWrapper( Object obj ) {
  198. return ( obj instanceof Boolean ||
  199. obj instanceof Character || obj instanceof Number );
  200. }
  201. }