/interpreter/tags/at2-build270707/src/edu/vub/at/objects/natives/NATNumber.java

http://ambienttalk.googlecode.com/ · Java · 304 lines · 173 code · 34 blank · 97 comment · 23 complexity · 563103623e7d9ec9fdc01f63ff318241 MD5 · raw file

  1. /**
  2. * AmbientTalk/2 Project
  3. * NATNumber.java created on 26-jul-2006 at 16:32:54
  4. * (c) Programming Technology Lab, 2006 - 2007
  5. * Authors: Tom Van Cutsem & Stijn Mostinckx
  6. *
  7. * Permission is hereby granted, free of charge, to any person
  8. * obtaining a copy of this software and associated documentation
  9. * files (the "Software"), to deal in the Software without
  10. * restriction, including without limitation the rights to use,
  11. * copy, modify, merge, publish, distribute, sublicense, and/or
  12. * sell copies of the Software, and to permit persons to whom the
  13. * Software is furnished to do so, subject to the following
  14. * conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be
  17. * included in all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  20. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  21. * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  22. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  23. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  24. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  25. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  26. * OTHER DEALINGS IN THE SOFTWARE.
  27. */
  28. package edu.vub.at.objects.natives;
  29. import edu.vub.at.exceptions.InterpreterException;
  30. import edu.vub.at.exceptions.XIllegalArgument;
  31. import edu.vub.at.exceptions.XTypeMismatch;
  32. import edu.vub.at.objects.ATBoolean;
  33. import edu.vub.at.objects.ATClosure;
  34. import edu.vub.at.objects.ATFraction;
  35. import edu.vub.at.objects.ATNil;
  36. import edu.vub.at.objects.ATNumber;
  37. import edu.vub.at.objects.ATNumeric;
  38. import edu.vub.at.objects.ATObject;
  39. import edu.vub.at.objects.ATTable;
  40. import edu.vub.at.objects.coercion.NativeTypeTags;
  41. /**
  42. * The native implementation of an AmbientTalk number.
  43. * A number is implemented by a Java int.
  44. *
  45. * @author smostinc
  46. */
  47. public final class NATNumber extends NATNumeric implements ATNumber {
  48. public static final NATNumber ZERO = new NATNumber(0);
  49. public static final NATNumber ONE = new NATNumber(1);
  50. public static final NATNumber MONE = new NATNumber(-1);
  51. public final int javaValue;
  52. /**
  53. * This method currently serves as a hook for number creation.
  54. * Currently number objects are not reused, but this might change in the future.
  55. */
  56. public static final NATNumber atValue(int javaNumber) {
  57. return new NATNumber(javaNumber);
  58. }
  59. private NATNumber(int javaNumber) {
  60. javaValue = javaNumber;
  61. }
  62. public ATBoolean base__opeql__opeql_(ATObject comparand) {
  63. return NATBoolean.atValue(this.equals(comparand));
  64. }
  65. public boolean equals(Object comparand) {
  66. return (comparand instanceof NATNumber) &&
  67. (javaValue == ((NATNumber) comparand).javaValue);
  68. }
  69. public ATNumber asNumber() throws XTypeMismatch { return this; }
  70. public NATNumber asNativeNumber() { return this; }
  71. public NATText meta_print() throws InterpreterException {
  72. return NATText.atValue(String.valueOf(javaValue));
  73. }
  74. public ATTable meta_typeTags() throws InterpreterException {
  75. return NATTable.of(NativeTypeTags._NUMBER_, NativeTypeTags._ISOLATE_);
  76. }
  77. // contract with NATNumeric
  78. protected double getJavaValue() { return javaValue; }
  79. /* -----------------------------------
  80. * - base-level interface to numbers -
  81. * ----------------------------------- */
  82. // iteration constructs
  83. /**
  84. * NBR(n).doTimes: { |i| code } => for i = 1 to n do code.eval(i) ; nil
  85. */
  86. public ATNil base_doTimes_(ATClosure code) throws InterpreterException {
  87. for (int i = 1; i <= javaValue; i++) {
  88. code.base_apply(NATTable.atValue(new ATObject[] { NATNumber.atValue(i) }));
  89. }
  90. return OBJNil._INSTANCE_;
  91. }
  92. /**
  93. * NBR(start).to: NBR(stop) do: { |i| code } => for i = start to stop do code.eval(i) ; nil
  94. * Also works if stop > start, in which case it becomes a downTo.
  95. *
  96. * If start = stop, the code is not executed.
  97. */
  98. public ATNil base_to_do_(ATNumber end, ATClosure code) throws InterpreterException {
  99. return this.base_to_step_do_(end, NATNumber.ONE, code);
  100. }
  101. /**
  102. * NBR(start).to: NBR(stop) step: NBR(inc) do: { |i| code } =>
  103. * for i = start; i < stop; i++ do code.eval(i) ; nil
  104. * Also works if stop > start, in which case it becomes a downTo.
  105. */
  106. public ATNil base_to_step_do_(ATNumber end, ATNumber inc, ATClosure code) throws InterpreterException {
  107. int stop = end.asNativeNumber().javaValue;
  108. int step = inc.asNativeNumber().javaValue;
  109. int start = javaValue;
  110. if (start > stop) {
  111. for (int i = start; i > stop; i -= step) {
  112. code.base_apply(NATTable.atValue(new ATObject[] { NATNumber.atValue(i) }));
  113. }
  114. } else {
  115. for (int i = start; i < stop; i+= step) {
  116. code.base_apply(NATTable.atValue(new ATObject[] { NATNumber.atValue(i) }));
  117. }
  118. }
  119. return OBJNil._INSTANCE_;
  120. }
  121. /**
  122. * NBR(start) ** NBR(stop) => [ start, ..., stop [
  123. *
  124. * Example:
  125. * 2 ** 5 => [ 2, 3, 4 ]
  126. * 5 ** 2 => [ 5, 4, 3 ]
  127. */
  128. public ATTable base__optms__optms_(ATNumber end) throws InterpreterException {
  129. int stop = end.asNativeNumber().javaValue;
  130. int start = javaValue;
  131. if (start < stop) {
  132. ATObject[] tbl = new ATObject[stop - start];
  133. for (int i = 0; i < tbl.length; i++) {
  134. tbl[i] = NATNumber.atValue(start + i);
  135. }
  136. return NATTable.atValue(tbl);
  137. } else {
  138. ATObject[] tbl = new ATObject[start - stop];
  139. for (int i = 0; i < tbl.length; i++) {
  140. tbl[i] = NATNumber.atValue(start - i);
  141. }
  142. return NATTable.atValue(tbl);
  143. }
  144. }
  145. /**
  146. * NBR(start) *** NBR(stop) => [ start, ..., stop ]
  147. *
  148. * Example:
  149. * 2 *** 5 => [ 2, 3, 4, 5 ]
  150. * 5 *** 2 => [ 5, 4, 3, 2 ]
  151. */
  152. public ATTable base__optms__optms__optms_(ATNumber end) throws InterpreterException {
  153. // x *** y == x ** y+1 iff x < y
  154. // x *** y == x ** y-1 iff y > x
  155. int stop = end.asNativeNumber().javaValue;
  156. if (javaValue <= stop)
  157. return this.base__optms__optms_(end.base_inc().asNumber());
  158. else
  159. return this.base__optms__optms_(end.base_dec().asNumber());
  160. }
  161. // Number arithmetic operations
  162. /**
  163. * NBR(n).inc() => NBR(n+1)
  164. */
  165. public ATNumber base_inc() {
  166. return NATNumber.atValue(javaValue+1);
  167. }
  168. /**
  169. * NBR(n).dec() => NBR(n-1)
  170. */
  171. public ATNumber base_dec() {
  172. return NATNumber.atValue(javaValue-1);
  173. }
  174. /**
  175. * NBR(n).abs() => NBR(abs(n))
  176. */
  177. public ATNumber base_abs() {
  178. return NATNumber.atValue(Math.abs(javaValue));
  179. }
  180. /**
  181. * NBR(start) ?? NBR(stop) => FRC(n) where n chosen randomly in [ start, stop [
  182. */
  183. public ATFraction base__opque__opque_(ATNumber nbr) throws InterpreterException {
  184. int stop = nbr.asNativeNumber().javaValue;
  185. double rnd = Math.random(); // 0 <= rnd < 1.0
  186. double frc = (rnd * (stop - javaValue)) + javaValue;
  187. return NATFraction.atValue(frc);
  188. }
  189. /**
  190. * NBR(n) % NBR(r) => NBR(n % r)
  191. */
  192. public ATNumber base__oprem_(ATNumber n) throws InterpreterException {
  193. return NATNumber.atValue(javaValue % n.asNativeNumber().javaValue);
  194. }
  195. /**
  196. * NBR(n) /- NBR(d) => NBR(n / d)
  197. */
  198. public ATNumber base__opdiv__opmns_(ATNumber n) throws InterpreterException {
  199. return NATNumber.atValue(javaValue / n.asNativeNumber().javaValue);
  200. }
  201. // Numeric arithmetic operations
  202. // addition +
  203. public ATNumeric base__oppls_(ATNumeric other) throws InterpreterException {
  204. return other.base_addNumber(this);
  205. }
  206. public ATNumeric base_addNumber(ATNumber other) throws InterpreterException {
  207. return NATNumber.atValue(other.asNativeNumber().javaValue + javaValue);
  208. }
  209. public ATNumeric base_addFraction(ATFraction other) throws InterpreterException {
  210. return NATFraction.atValue(other.asNativeFraction().javaValue + javaValue);
  211. }
  212. // subtraction -
  213. public ATNumeric base__opmns_(ATNumeric other) throws InterpreterException {
  214. return other.base_subtractNumber(this);
  215. }
  216. public ATNumeric base_subtractNumber(ATNumber other) throws InterpreterException {
  217. return NATNumber.atValue(other.asNativeNumber().javaValue - javaValue);
  218. }
  219. public ATNumeric base_subtractFraction(ATFraction other) throws InterpreterException {
  220. return NATFraction.atValue(other.asNativeFraction().javaValue - javaValue);
  221. }
  222. // multiplication *
  223. public ATNumeric base__optms_(ATNumeric other) throws InterpreterException {
  224. return other.base_timesNumber(this);
  225. }
  226. public ATNumeric base_timesNumber(ATNumber other) throws InterpreterException {
  227. return NATNumber.atValue(other.asNativeNumber().javaValue * javaValue);
  228. }
  229. public ATNumeric base_timesFraction(ATFraction other) throws InterpreterException {
  230. return NATFraction.atValue(other.asNativeFraction().javaValue * javaValue);
  231. }
  232. // division /
  233. public ATNumeric base__opdiv_(ATNumeric other) throws InterpreterException {
  234. return other.base_divideNumber(this);
  235. }
  236. public ATNumeric base_divideNumber(ATNumber other) throws InterpreterException {
  237. if (javaValue == 0)
  238. throw new XIllegalArgument("Division by zero: " + other);
  239. return NATFraction.atValue((other.asNativeNumber().javaValue * 1.0) / javaValue);
  240. }
  241. public ATNumeric base_divideFraction(ATFraction other) throws InterpreterException {
  242. if (javaValue == 0)
  243. throw new XIllegalArgument("Division by zero: " + other);
  244. return NATFraction.atValue(other.asNativeFraction().javaValue / javaValue);
  245. }
  246. // comparison: generalized equality <=>
  247. public ATNumeric base__opltx__opeql__opgtx_(ATNumeric other) throws InterpreterException {
  248. return other.base_gequalsNumber(this);
  249. }
  250. public ATNumeric base_gequalsNumber(ATNumber other) throws InterpreterException {
  251. int n = other.asNativeNumber().javaValue;
  252. if (n < javaValue) {
  253. return NATNumber.MONE; // -1
  254. } else if (n > javaValue) {
  255. return NATNumber.ONE; // +1
  256. } else {
  257. return NATNumber.ZERO; // 0
  258. }
  259. }
  260. public ATNumeric base_gequalsFraction(ATFraction other) throws InterpreterException {
  261. double n = other.asNativeFraction().javaValue;
  262. if (n < javaValue) {
  263. return NATNumber.MONE; // -1
  264. } else if (n > javaValue) {
  265. return NATNumber.ONE; // +1
  266. } else {
  267. return NATNumber.ZERO; // 0
  268. }
  269. }
  270. }