PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

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

#
Java | 788 lines | 537 code | 146 blank | 105 comment | 118 complexity | f5ed4b9e609f2b11c5df6c6d7967f5bb 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. Wrapper for primitive types in Bsh. This is package public because it
  36. is used in the implementation of some bsh commands.
  37. See the note in LHS.java about wrapping objects.
  38. */
  39. public class Primitive implements ParserConstants, java.io.Serializable
  40. {
  41. // stored internally in java.lang. wrappers
  42. private Object value;
  43. private static class Special implements java.io.Serializable
  44. {
  45. private Special() { }
  46. public static final Special NULL_VALUE = new Special();
  47. public static final Special VOID_TYPE = new Special();
  48. }
  49. /*
  50. NULL means "no value".
  51. This ia a placeholder for primitive null value.
  52. */
  53. public static final Primitive NULL = new Primitive(Special.NULL_VALUE);
  54. /**
  55. VOID means "no type".
  56. Strictly speaking, this makes no sense here. But for practical
  57. reasons we'll consider the lack of a type to be a special value.
  58. */
  59. public static final Primitive VOID = new Primitive(Special.VOID_TYPE);
  60. // private to prevent invocation with param that isn't a primitive-wrapper
  61. private Primitive(Object value)
  62. {
  63. if(value == null)
  64. throw new InterpreterError(
  65. "Use Primitve.NULL instead of Primitive(null)");
  66. this.value = value;
  67. }
  68. public Primitive(Number number) { this((Object)number); }
  69. public Primitive(Boolean value) { this((Object)value); }
  70. public Primitive(Byte value) { this((Object)value); }
  71. public Primitive(Short value) { this((Object)value); }
  72. public Primitive(Character value) { this((Object)value); }
  73. public Primitive(Integer value) { this((Object)value); }
  74. public Primitive(Long value) { this((Object)value); }
  75. public Primitive(Float value) { this((Object)value); }
  76. public Primitive(Double value) { this((Object)value); }
  77. public Primitive(boolean value) { this(new Boolean(value)); }
  78. public Primitive(byte value) { this(new Byte(value)); }
  79. public Primitive(short value) { this(new Short(value)); }
  80. public Primitive(char value) { this(new Character(value)); }
  81. public Primitive(int value) { this(new Integer(value)); }
  82. public Primitive(long value) { this(new Long(value)); }
  83. public Primitive(float value) { this(new Float(value)); }
  84. public Primitive(double value) { this(new Double(value)); }
  85. public Object getValue()
  86. {
  87. if(value == Special.NULL_VALUE)
  88. return null;
  89. else if(value == Special.VOID_TYPE)
  90. throw new InterpreterError("attempt to unwrap void type");
  91. else
  92. return value;
  93. }
  94. public String toString()
  95. {
  96. if(value == Special.NULL_VALUE)
  97. return "null";
  98. else if(value == Special.VOID_TYPE)
  99. return "void";
  100. else
  101. return value.toString();
  102. }
  103. public Class getType()
  104. {
  105. return getType(value);
  106. }
  107. private Class getType(Object o)
  108. {
  109. if(o instanceof Boolean)
  110. return Boolean.TYPE;
  111. else if(o instanceof Byte)
  112. return Byte.TYPE;
  113. else if(o instanceof Short)
  114. return Short.TYPE;
  115. else if(o instanceof Character)
  116. return Character.TYPE;
  117. else if(o instanceof Integer)
  118. return Integer.TYPE;
  119. else if(o instanceof Long)
  120. return Long.TYPE;
  121. else if(o instanceof Float)
  122. return Float.TYPE;
  123. else if(o instanceof Double)
  124. return Double.TYPE;
  125. return null;
  126. }
  127. /*
  128. public static Primitive binaryOperation(
  129. Primitive p1, Primitive p2, int kind )
  130. throws EvalError
  131. {
  132. return new Primitive( binaryOperation( p1, p2, kind ) );
  133. }
  134. */
  135. /**
  136. Allow primitive operations on wrapper types such as Integer and Boolean.
  137. This is static so that it can be reached from wherever...
  138. */
  139. public static Object binaryOperation(
  140. Object obj1, Object obj2, int kind)
  141. throws EvalError
  142. {
  143. // special primitive types
  144. if(obj1 == NULL || obj2 == NULL)
  145. throw new EvalError(
  146. "Null value or 'null' literal in binary operation");
  147. if(obj1 == VOID || obj2 == VOID)
  148. throw new EvalError(
  149. "Undefined variable, class, or 'void' literal in binary operation");
  150. // keep track of the original types
  151. Class lhsOrgType = obj1.getClass();
  152. Class rhsOrgType = obj2.getClass();
  153. // Unwrap primitives
  154. if(obj1 instanceof Primitive)
  155. obj1 = ((Primitive)obj1).getValue();
  156. if(obj2 instanceof Primitive)
  157. obj2 = ((Primitive)obj2).getValue();
  158. Object[] operands = promotePrimitives(obj1, obj2);
  159. Object lhs = operands[0];
  160. Object rhs = operands[1];
  161. if(lhs.getClass() != rhs.getClass())
  162. throw new EvalError("type mismatch in operator. "
  163. + lhs.getClass() + " cannot be used with " + rhs.getClass() );
  164. Object result;
  165. try {
  166. result = binaryOperationImpl( lhs, rhs, kind );
  167. } catch ( ArithmeticException e ) {
  168. throw new TargetError("Arithemetic Exception in binary op", e);
  169. }
  170. // If both original args were Primitives return a Primitive result
  171. // else it was mixed (wrapper/primitive) return the wrapper type
  172. if ( lhsOrgType == Primitive.class && rhsOrgType == Primitive.class )
  173. return new Primitive( result );
  174. else
  175. return result;
  176. }
  177. static Object binaryOperationImpl( Object lhs, Object rhs, int kind )
  178. throws EvalError
  179. {
  180. if(lhs instanceof Boolean)
  181. return booleanBinaryOperation((Boolean)lhs, (Boolean)rhs, kind);
  182. else if(lhs instanceof Integer)
  183. return intBinaryOperation( (Integer)lhs, (Integer)rhs, kind );
  184. else if(lhs instanceof Long)
  185. return longBinaryOperation((Long)lhs, (Long)rhs, kind);
  186. else if(lhs instanceof Float)
  187. return floatBinaryOperation((Float)lhs, (Float)rhs, kind);
  188. else if(lhs instanceof Double)
  189. return doubleBinaryOperation( (Double)lhs, (Double)rhs, kind);
  190. else
  191. throw new EvalError("Invalid types in binary operator" );
  192. }
  193. static Boolean booleanBinaryOperation(Boolean B1, Boolean B2, int kind)
  194. throws EvalError
  195. {
  196. boolean lhs = B1.booleanValue();
  197. boolean rhs = B2.booleanValue();
  198. switch(kind)
  199. {
  200. case EQ:
  201. return new Boolean(lhs == rhs);
  202. case NE:
  203. return new Boolean(lhs != rhs);
  204. case BOOL_OR:
  205. case BOOL_ORX:
  206. return new Boolean( lhs || rhs );
  207. case BOOL_AND:
  208. case BOOL_ANDX:
  209. return new Boolean( lhs && rhs );
  210. default:
  211. throw new InterpreterError("unimplemented binary operator");
  212. }
  213. }
  214. // returns Object covering both Long and Boolean return types
  215. static Object longBinaryOperation(Long L1, Long L2, int kind)
  216. {
  217. long lhs = L1.longValue();
  218. long rhs = L2.longValue();
  219. switch(kind)
  220. {
  221. // boolean
  222. case LT:
  223. case LTX:
  224. return new Boolean(lhs < rhs);
  225. case GT:
  226. case GTX:
  227. return new Boolean(lhs > rhs);
  228. case EQ:
  229. return new Boolean(lhs == rhs);
  230. case LE:
  231. case LEX:
  232. return new Boolean(lhs <= rhs);
  233. case GE:
  234. case GEX:
  235. return new Boolean(lhs >= rhs);
  236. case NE:
  237. return new Boolean(lhs != rhs);
  238. // arithmetic
  239. case PLUS:
  240. return new Long(lhs + rhs);
  241. case MINUS:
  242. return new Long(lhs - rhs);
  243. case STAR:
  244. return new Long(lhs * rhs);
  245. case SLASH:
  246. return new Long(lhs / rhs);
  247. case MOD:
  248. return new Long(lhs % rhs);
  249. // bitwise
  250. case LSHIFT:
  251. case LSHIFTX:
  252. return new Long(lhs << rhs);
  253. case RSIGNEDSHIFT:
  254. case RSIGNEDSHIFTX:
  255. return new Long(lhs >> rhs);
  256. case RUNSIGNEDSHIFT:
  257. case RUNSIGNEDSHIFTX:
  258. return new Long(lhs >>> rhs);
  259. case BIT_AND:
  260. case BIT_ANDX:
  261. return new Long(lhs & rhs);
  262. case BIT_OR:
  263. case BIT_ORX:
  264. return new Long(lhs | rhs);
  265. case XOR:
  266. return new Long(lhs ^ rhs);
  267. default:
  268. throw new InterpreterError("Unimplemented binary long operator");
  269. }
  270. }
  271. // returns Object covering both Integer and Boolean return types
  272. static Object intBinaryOperation(Integer I1, Integer I2, int kind)
  273. {
  274. int lhs = I1.intValue();
  275. int rhs = I2.intValue();
  276. switch(kind)
  277. {
  278. // boolean
  279. case LT:
  280. case LTX:
  281. return new Boolean(lhs < rhs);
  282. case GT:
  283. case GTX:
  284. return new Boolean(lhs > rhs);
  285. case EQ:
  286. return new Boolean(lhs == rhs);
  287. case LE:
  288. case LEX:
  289. return new Boolean(lhs <= rhs);
  290. case GE:
  291. case GEX:
  292. return new Boolean(lhs >= rhs);
  293. case NE:
  294. return new Boolean(lhs != rhs);
  295. // arithmetic
  296. case PLUS:
  297. return new Integer(lhs + rhs);
  298. case MINUS:
  299. return new Integer(lhs - rhs);
  300. case STAR:
  301. return new Integer(lhs * rhs);
  302. case SLASH:
  303. return new Integer(lhs / rhs);
  304. case MOD:
  305. return new Integer(lhs % rhs);
  306. // bitwise
  307. case LSHIFT:
  308. case LSHIFTX:
  309. return new Integer(lhs << rhs);
  310. case RSIGNEDSHIFT:
  311. case RSIGNEDSHIFTX:
  312. return new Integer(lhs >> rhs);
  313. case RUNSIGNEDSHIFT:
  314. case RUNSIGNEDSHIFTX:
  315. return new Integer(lhs >>> rhs);
  316. case BIT_AND:
  317. case BIT_ANDX:
  318. return new Integer(lhs & rhs);
  319. case BIT_OR:
  320. case BIT_ORX:
  321. return new Integer(lhs | rhs);
  322. case XOR:
  323. return new Integer(lhs ^ rhs);
  324. default:
  325. throw new InterpreterError("Unimplemented binary integer operator");
  326. }
  327. }
  328. // returns Object covering both Double and Boolean return types
  329. static Object doubleBinaryOperation(Double D1, Double D2, int kind)
  330. throws EvalError
  331. {
  332. double lhs = D1.doubleValue();
  333. double rhs = D2.doubleValue();
  334. switch(kind)
  335. {
  336. // boolean
  337. case LT:
  338. case LTX:
  339. return new Boolean(lhs < rhs);
  340. case GT:
  341. case GTX:
  342. return new Boolean(lhs > rhs);
  343. case EQ:
  344. return new Boolean(lhs == rhs);
  345. case LE:
  346. case LEX:
  347. return new Boolean(lhs <= rhs);
  348. case GE:
  349. case GEX:
  350. return new Boolean(lhs >= rhs);
  351. case NE:
  352. return new Boolean(lhs != rhs);
  353. // arithmetic
  354. case PLUS:
  355. return new Double(lhs + rhs);
  356. case MINUS:
  357. return new Double(lhs - rhs);
  358. case STAR:
  359. return new Double(lhs * rhs);
  360. case SLASH:
  361. return new Double(lhs / rhs);
  362. case MOD:
  363. return new Double(lhs % rhs);
  364. // can't shift floating-point values
  365. case LSHIFT:
  366. case LSHIFTX:
  367. case RSIGNEDSHIFT:
  368. case RSIGNEDSHIFTX:
  369. case RUNSIGNEDSHIFT:
  370. case RUNSIGNEDSHIFTX:
  371. throw new EvalError("Can't shift doubles");
  372. default:
  373. throw new InterpreterError("Unimplemented binary double operator");
  374. }
  375. }
  376. // returns Object covering both Long and Boolean return types
  377. static Object floatBinaryOperation(Float F1, Float F2, int kind)
  378. throws EvalError
  379. {
  380. float lhs = F1.floatValue();
  381. float rhs = F2.floatValue();
  382. switch(kind)
  383. {
  384. // boolean
  385. case LT:
  386. case LTX:
  387. return new Boolean(lhs < rhs);
  388. case GT:
  389. case GTX:
  390. return new Boolean(lhs > rhs);
  391. case EQ:
  392. return new Boolean(lhs == rhs);
  393. case LE:
  394. case LEX:
  395. return new Boolean(lhs <= rhs);
  396. case GE:
  397. case GEX:
  398. return new Boolean(lhs >= rhs);
  399. case NE:
  400. return new Boolean(lhs != rhs);
  401. // arithmetic
  402. case PLUS:
  403. return new Float(lhs + rhs);
  404. case MINUS:
  405. return new Float(lhs - rhs);
  406. case STAR:
  407. return new Float(lhs * rhs);
  408. case SLASH:
  409. return new Float(lhs / rhs);
  410. case MOD:
  411. return new Float(lhs % rhs);
  412. // can't shift floats
  413. case LSHIFT:
  414. case LSHIFTX:
  415. case RSIGNEDSHIFT:
  416. case RSIGNEDSHIFTX:
  417. case RUNSIGNEDSHIFT:
  418. case RUNSIGNEDSHIFTX:
  419. throw new EvalError("Can't shift floats ");
  420. default:
  421. throw new InterpreterError("Unimplemented binary float operator");
  422. }
  423. }
  424. /**
  425. Promote primitive wrapper type to to Integer wrapper type
  426. Can we use the castPrimitive() (in BSHCastExpression) for this?
  427. */
  428. static Object promoteToInteger(Object primitive)
  429. {
  430. if(primitive instanceof Character)
  431. return new Integer(((Character)primitive).charValue());
  432. else if((primitive instanceof Byte) || (primitive instanceof Short))
  433. return new Integer(((Number)primitive).intValue());
  434. return primitive;
  435. }
  436. /**
  437. Promote the pair of primitives to the maximum type of the two.
  438. e.g. [int,long]->[long,long]
  439. */
  440. static Object[] promotePrimitives(Object lhs, Object rhs)
  441. {
  442. lhs = promoteToInteger(lhs);
  443. rhs = promoteToInteger(rhs);
  444. if((lhs instanceof Number) && (rhs instanceof Number))
  445. {
  446. Number lnum = (Number)lhs;
  447. Number rnum = (Number)rhs;
  448. boolean b;
  449. if((b = (lnum instanceof Double)) || (rnum instanceof Double))
  450. {
  451. if(b)
  452. rhs = new Double(rnum.doubleValue());
  453. else
  454. lhs = new Double(lnum.doubleValue());
  455. }
  456. else if((b = (lnum instanceof Float)) || (rnum instanceof Float))
  457. {
  458. if(b)
  459. rhs = new Float(rnum.floatValue());
  460. else
  461. lhs = new Float(lnum.floatValue());
  462. }
  463. else if((b = (lnum instanceof Long)) || (rnum instanceof Long))
  464. {
  465. if(b)
  466. rhs = new Long(rnum.longValue());
  467. else
  468. lhs = new Long(lnum.longValue());
  469. }
  470. }
  471. return new Object[] { lhs, rhs };
  472. }
  473. public static Primitive unaryOperation(Primitive val, int kind)
  474. throws EvalError
  475. {
  476. if(val == NULL)
  477. throw new EvalError("illegal use of null object or 'null' literal");
  478. if(val == VOID)
  479. throw new EvalError("illegal use of undefined object or 'void' literal");
  480. Class operandType = val.getType();
  481. Object operand = promoteToInteger(val.getValue());
  482. if(operand instanceof Boolean)
  483. return new Primitive(booleanUnaryOperation((Boolean)operand, kind));
  484. else if(operand instanceof Integer)
  485. {
  486. int result = intUnaryOperation((Integer)operand, kind);
  487. // ++ and -- must be cast back the original type
  488. if(kind == INCR || kind == DECR)
  489. {
  490. if(operandType == Byte.TYPE)
  491. return new Primitive((byte)result);
  492. if(operandType == Short.TYPE)
  493. return new Primitive((short)result);
  494. if(operandType == Character.TYPE)
  495. return new Primitive((char)result);
  496. }
  497. return new Primitive(result);
  498. }
  499. else if(operand instanceof Long)
  500. return new Primitive(longUnaryOperation((Long)operand, kind));
  501. else if(operand instanceof Float)
  502. return new Primitive(floatUnaryOperation((Float)operand, kind));
  503. else if(operand instanceof Double)
  504. return new Primitive(doubleUnaryOperation((Double)operand, kind));
  505. else
  506. throw new InterpreterError("An error occurred. Please call technical support.");
  507. }
  508. static boolean booleanUnaryOperation(Boolean B, int kind) throws EvalError
  509. {
  510. boolean operand = B.booleanValue();
  511. switch(kind)
  512. {
  513. case BANG:
  514. return !operand;
  515. default:
  516. throw new EvalError("Operator inappropriate for boolean");
  517. }
  518. }
  519. static int intUnaryOperation(Integer I, int kind)
  520. {
  521. int operand = I.intValue();
  522. switch(kind)
  523. {
  524. case PLUS:
  525. return operand;
  526. case MINUS:
  527. return -operand;
  528. case TILDE:
  529. return ~operand;
  530. case INCR:
  531. return operand + 1;
  532. case DECR:
  533. return operand - 1;
  534. default:
  535. throw new InterpreterError("bad integer unaryOperation");
  536. }
  537. }
  538. static long longUnaryOperation(Long L, int kind)
  539. {
  540. long operand = L.longValue();
  541. switch(kind)
  542. {
  543. case PLUS:
  544. return operand;
  545. case MINUS:
  546. return -operand;
  547. case TILDE:
  548. return ~operand;
  549. case INCR:
  550. return operand + 1;
  551. case DECR:
  552. return operand - 1;
  553. default:
  554. throw new InterpreterError("bad long unaryOperation");
  555. }
  556. }
  557. static float floatUnaryOperation(Float F, int kind)
  558. {
  559. float operand = F.floatValue();
  560. switch(kind)
  561. {
  562. case PLUS:
  563. return operand;
  564. case MINUS:
  565. return -operand;
  566. default:
  567. throw new InterpreterError("bad float unaryOperation");
  568. }
  569. }
  570. static double doubleUnaryOperation(Double D, int kind)
  571. {
  572. double operand = D.doubleValue();
  573. switch(kind)
  574. {
  575. case PLUS:
  576. return operand;
  577. case MINUS:
  578. return -operand;
  579. default:
  580. throw new InterpreterError("bad double unaryOperation");
  581. }
  582. }
  583. public int intValue() throws EvalError
  584. {
  585. if(value instanceof Number)
  586. return((Number)value).intValue();
  587. else
  588. throw new EvalError("Primitive not a number");
  589. }
  590. public boolean booleanValue() throws EvalError
  591. {
  592. if(value instanceof Boolean)
  593. return((Boolean)value).booleanValue();
  594. else
  595. throw new EvalError("Primitive not a boolean");
  596. }
  597. /**
  598. Determine if this primitive is a numeric type.
  599. i.e. not boolean, null, or void (but including char)
  600. */
  601. public boolean isNumber() {
  602. return ( !(value instanceof Boolean)
  603. && !(this == NULL) && !(this == VOID) );
  604. }
  605. public Number numberValue() throws EvalError
  606. {
  607. Object value = this.value;
  608. // Promote character to Number type for these purposes
  609. if (value instanceof Character)
  610. value = new Integer(((Character)value).charValue());
  611. if (value instanceof Number)
  612. return (Number)value;
  613. else
  614. throw new EvalError("Primitive not a number");
  615. }
  616. public boolean equals( Object obj ) {
  617. if ( obj instanceof Primitive )
  618. return ((Primitive)obj).value.equals( this.value );
  619. else
  620. return obj.equals( this.value );
  621. }
  622. /**
  623. Unwrap primitive values and map voids to nulls.
  624. Normal (non Primitive) types remain unchanged.
  625. @param obj object type which may be bsh.Primitive
  626. @return corresponding "normal" Java type, "unwrapping"
  627. any bsh.Primitive types to their wrapper types.
  628. */
  629. public static Object unwrap( Object obj ) {
  630. if ( obj == null )
  631. return null;
  632. // map voids to nulls for the outside world
  633. if(obj == Primitive.VOID)
  634. return null;
  635. // unwrap primitives
  636. if(obj instanceof Primitive)
  637. return((Primitive)obj).getValue();
  638. else
  639. return obj;
  640. }
  641. }