PageRenderTime 36ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-1-pre5/bsh/BSHBinaryExpression.java

#
Java | 215 lines | 85 code | 24 blank | 106 comment | 50 complexity | 1cd6163ce9a6cc2c07f58acccb65c87d 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. /*
  57. // primitive (number or void) cannot be tested for instanceof
  58. if (lhs instanceof Primitive)
  59. throw new EvalError("Cannot be instance of primitive type." );
  60. */
  61. // Primitive (number or void) is not an instanceof anything
  62. if (lhs instanceof Primitive)
  63. return new Primitive(false);
  64. // General case - performe the instanceof based on assignability
  65. NameSpace namespace = callstack.top();
  66. Class rhs = ((BSHType)jjtGetChild(1)).getType(namespace);
  67. boolean ret = (Reflect.isAssignableFrom(rhs, lhs.getClass()));
  68. return new Primitive(ret);
  69. }
  70. // The following two boolean checks were tacked on.
  71. // This could probably be smoothed out.
  72. /*
  73. Look ahead and short circuit evaluation of the rhs if:
  74. we're a boolean AND and the lhs is false.
  75. */
  76. if ( kind == BOOL_AND || kind == BOOL_ANDX ) {
  77. Object obj = lhs;
  78. if ( isPrimitiveValue(lhs) )
  79. obj = ((Primitive)lhs).getValue();
  80. if ( obj instanceof Boolean &&
  81. ( ((Boolean)obj).booleanValue() == false ) )
  82. return new Primitive(false);
  83. }
  84. /*
  85. Look ahead and short circuit evaluation of the rhs if:
  86. we're a boolean AND and the lhs is false.
  87. */
  88. if ( kind == BOOL_OR || kind == BOOL_ORX ) {
  89. Object obj = lhs;
  90. if ( isPrimitiveValue(lhs) )
  91. obj = ((Primitive)lhs).getValue();
  92. if ( obj instanceof Boolean &&
  93. ( ((Boolean)obj).booleanValue() == true ) )
  94. return new Primitive(true);
  95. }
  96. // end stuff that was tacked on for boolean short-circuiting.
  97. /*
  98. Are both the lhs and rhs either wrappers or primitive values?
  99. do binary op
  100. */
  101. boolean isLhsWrapper = isWrapper( lhs );
  102. Object rhs = ((SimpleNode)jjtGetChild(1)).eval(callstack, interpreter);
  103. boolean isRhsWrapper = isWrapper( rhs );
  104. if (
  105. ( isLhsWrapper || isPrimitiveValue( lhs ) )
  106. && ( isRhsWrapper || isPrimitiveValue( rhs ) )
  107. )
  108. {
  109. // Special case for EQ on two wrapper objects
  110. if ( (isLhsWrapper && isRhsWrapper && kind == EQ))
  111. {
  112. /*
  113. Don't auto-unwrap wrappers (preserve identity semantics)
  114. FALL THROUGH TO OBJECT OPERATIONS BELOW.
  115. */
  116. } else
  117. try {
  118. return Primitive.binaryOperation(lhs, rhs, kind);
  119. } catch ( TargetError e ) {
  120. // this doesn't really help... need to catch it higher?
  121. e.reThrow( this );
  122. }
  123. }
  124. /*
  125. Do we have a mixture of primitive values and non-primitives ?
  126. (primitiveValue = not null, not void)
  127. god, this is getting ugly...
  128. */
  129. /*
  130. Removing this restriction for now...
  131. int primCount = 0;
  132. if ( isPrimitiveValue( lhs ) )
  133. ++primCount;
  134. if ( isPrimitiveValue( rhs ) )
  135. ++primCount;
  136. if ( primCount > 1 )
  137. // both primitive types, should have been handled above
  138. throw new InterpreterError("should not be here");
  139. else if ( primCount == 1 )
  140. // mixture of one and the other
  141. throw new EvalError( "Invalid use of primitive and non-primitive"
  142. +" values in binary operation.");
  143. // else fall through to handle both non-primitive types
  144. // end check for primitive and non-primitive mix
  145. */
  146. /*
  147. Treat lhs and rhs as arbitrary objects and do the operation.
  148. (including NULL and VOID represented by their Primitive types)
  149. */
  150. //System.out.println("binary op arbitrary obj: {"+lhs+"}, {"+rhs+"}");
  151. switch(kind)
  152. {
  153. case EQ:
  154. return new Primitive((lhs == rhs));
  155. case NE:
  156. return new Primitive((lhs != rhs));
  157. case PLUS:
  158. if(lhs instanceof String || rhs instanceof String)
  159. return lhs.toString() + rhs.toString();
  160. // FALL THROUGH TO DEFAULT CASE!!!
  161. default:
  162. if(lhs instanceof Primitive || rhs instanceof Primitive)
  163. if(lhs == Primitive.VOID || rhs == Primitive.VOID)
  164. throw new EvalError(
  165. "illegal use of undefined variable, class, or 'void' literal", this);
  166. else
  167. if(lhs == Primitive.NULL || rhs == Primitive.NULL)
  168. throw new EvalError(
  169. "illegal use of null value or 'null' literal", this);
  170. throw new EvalError("Operator: '" + tokenImage[kind] +
  171. "' inappropriate for objects", this);
  172. }
  173. }
  174. /*
  175. object is a non-null and non-void Primitive type
  176. */
  177. private boolean isPrimitiveValue( Object obj ) {
  178. return ( (obj instanceof Primitive)
  179. && (obj != Primitive.VOID) && (obj != Primitive.NULL) );
  180. }
  181. /*
  182. object is a java.lang wrapper for boolean, char, or number type
  183. */
  184. private boolean isWrapper( Object obj ) {
  185. return ( obj instanceof Boolean ||
  186. obj instanceof Character || obj instanceof Number );
  187. }
  188. }