/interpreter/tags/at2dist091109/src/edu/vub/at/objects/natives/NATNumber.java

http://ambienttalk.googlecode.com/ · Java · 351 lines · 194 code · 41 blank · 116 comment · 25 complexity · d6e46e48fe9aaa59d43832c0dad9116c 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.eval.Evaluator;
  30. import edu.vub.at.exceptions.InterpreterException;
  31. import edu.vub.at.exceptions.XIllegalArgument;
  32. import edu.vub.at.exceptions.XTypeMismatch;
  33. import edu.vub.at.objects.ATBoolean;
  34. import edu.vub.at.objects.ATClosure;
  35. import edu.vub.at.objects.ATFraction;
  36. import edu.vub.at.objects.ATNil;
  37. import edu.vub.at.objects.ATNumber;
  38. import edu.vub.at.objects.ATNumeric;
  39. import edu.vub.at.objects.ATObject;
  40. import edu.vub.at.objects.ATTable;
  41. import edu.vub.at.objects.coercion.NativeTypeTags;
  42. /**
  43. * The native implementation of an AmbientTalk number.
  44. * A number is implemented by a Java int.
  45. *
  46. * @author smostinc
  47. */
  48. public final class NATNumber extends NATNumeric implements ATNumber {
  49. public static final NATNumber ZERO = new NATNumber(0);
  50. public static final NATNumber ONE = new NATNumber(1);
  51. public static final NATNumber MONE = new NATNumber(-1);
  52. public final int javaValue;
  53. /**
  54. * This method currently serves as a hook for number creation.
  55. * Currently number objects are not reused, but this might change in the future.
  56. */
  57. public static final NATNumber atValue(int javaNumber) {
  58. return new NATNumber(javaNumber);
  59. }
  60. private NATNumber(int javaNumber) {
  61. javaValue = javaNumber;
  62. }
  63. public ATBoolean base__opeql__opeql_(ATObject comparand) throws XTypeMismatch {
  64. if (comparand.isNativeNumber()) {
  65. return NATBoolean.atValue(javaValue == comparand.asNativeNumber().javaValue);
  66. } else {
  67. return NATBoolean._FALSE_;
  68. }
  69. }
  70. public ATNumber asNumber() throws XTypeMismatch { return this; }
  71. public boolean isNativeNumber() { return true; }
  72. public NATNumber asNativeNumber() { return this; }
  73. public NATText meta_print() throws InterpreterException {
  74. return NATText.atValue(String.valueOf(javaValue));
  75. }
  76. public ATTable meta_typeTags() throws InterpreterException {
  77. return NATTable.of(NativeTypeTags._NUMBER_, NativeTypeTags._ISOLATE_);
  78. }
  79. // contract with NATNumeric
  80. protected double getJavaValue() { return javaValue; }
  81. public int hashCode() { return javaValue; }
  82. /* -----------------------------------
  83. * - base-level interface to numbers -
  84. * ----------------------------------- */
  85. // iteration constructs
  86. /**
  87. * NBR(n).doTimes: { |i| code } => for i = 1 to n do code.eval(i) ; nil
  88. */
  89. public ATNil base_doTimes_(ATClosure code) throws InterpreterException {
  90. for (int i = 1; i <= javaValue; i++) {
  91. code.base_apply(NATTable.atValue(new ATObject[] { NATNumber.atValue(i) }));
  92. }
  93. return Evaluator.getNil();
  94. }
  95. /**
  96. * NBR(start).to: NBR(stop) do: { |i| code } => for i = start to stop do code.eval(i) ; nil
  97. * Also works if stop > start, in which case it becomes a downTo.
  98. *
  99. * If start = stop, the code is not executed.
  100. */
  101. public ATNil base_to_do_(ATNumber end, ATClosure code) throws InterpreterException {
  102. return this.base_to_step_do_(end, NATNumber.ONE, code);
  103. }
  104. /**
  105. * NBR(start).to: NBR(stop) step: NBR(inc) do: { |i| code } =>
  106. * for i = start; i < stop; i++ do code.eval(i) ; nil
  107. * Also works if stop > start, in which case it becomes a downTo.
  108. */
  109. public ATNil base_to_step_do_(ATNumber end, ATNumber inc, ATClosure code) throws InterpreterException {
  110. int stop = end.asNativeNumber().javaValue;
  111. int step = inc.asNativeNumber().javaValue;
  112. int start = javaValue;
  113. if (start > stop) {
  114. for (int i = start; i > stop; i -= step) {
  115. code.base_apply(NATTable.atValue(new ATObject[] { NATNumber.atValue(i) }));
  116. }
  117. } else {
  118. for (int i = start; i < stop; i+= step) {
  119. code.base_apply(NATTable.atValue(new ATObject[] { NATNumber.atValue(i) }));
  120. }
  121. }
  122. return Evaluator.getNil();
  123. }
  124. /**
  125. * NBR(start) ** NBR(stop) => [ start, ..., stop [
  126. *
  127. * Example:
  128. * 2 ** 5 => [ 2, 3, 4 ]
  129. * 5 ** 2 => [ 5, 4, 3 ]
  130. */
  131. public ATTable base__optms__optms_(ATNumber end) throws InterpreterException {
  132. int stop = end.asNativeNumber().javaValue;
  133. int start = javaValue;
  134. if (start < stop) {
  135. ATObject[] tbl = new ATObject[stop - start];
  136. for (int i = 0; i < tbl.length; i++) {
  137. tbl[i] = NATNumber.atValue(start + i);
  138. }
  139. return NATTable.atValue(tbl);
  140. } else {
  141. ATObject[] tbl = new ATObject[start - stop];
  142. for (int i = 0; i < tbl.length; i++) {
  143. tbl[i] = NATNumber.atValue(start - i);
  144. }
  145. return NATTable.atValue(tbl);
  146. }
  147. }
  148. /**
  149. * NBR(start) *** NBR(stop) => [ start, ..., stop ]
  150. *
  151. * Example:
  152. * 2 *** 5 => [ 2, 3, 4, 5 ]
  153. * 5 *** 2 => [ 5, 4, 3, 2 ]
  154. */
  155. public ATTable base__optms__optms__optms_(ATNumber end) throws InterpreterException {
  156. // x *** y == x ** y+1 iff x < y
  157. // x *** y == x ** y-1 iff y > x
  158. int stop = end.asNativeNumber().javaValue;
  159. if (javaValue <= stop)
  160. return this.base__optms__optms_(end.base_inc().asNumber());
  161. else
  162. return this.base__optms__optms_(end.base_dec().asNumber());
  163. }
  164. // Number arithmetic operations
  165. /**
  166. * NBR(n).inc() => NBR(n+1)
  167. */
  168. public ATNumber base_inc() {
  169. return NATNumber.atValue(javaValue+1);
  170. }
  171. /**
  172. * NBR(n).dec() => NBR(n-1)
  173. */
  174. public ATNumber base_dec() {
  175. return NATNumber.atValue(javaValue-1);
  176. }
  177. /**
  178. * NBR(n).abs() => NBR(abs(n))
  179. */
  180. public ATNumber base_abs() {
  181. return NATNumber.atValue(Math.abs(javaValue));
  182. }
  183. public ATNumber base_ceiling() throws InterpreterException {
  184. return this;
  185. }
  186. public ATNumber base_floor() throws InterpreterException {
  187. return this;
  188. }
  189. public ATNumber base_round() throws InterpreterException {
  190. return this;
  191. }
  192. /**
  193. * NBR(start) ?? NBR(stop) => FRC(n) where n chosen randomly in [ start, stop [
  194. */
  195. public ATFraction base__opque__opque_(ATNumber nbr) throws InterpreterException {
  196. int stop = nbr.asNativeNumber().javaValue;
  197. double rnd = Math.random(); // 0 <= rnd < 1.0
  198. double frc = (rnd * (stop - javaValue)) + javaValue;
  199. return NATFraction.atValue(frc);
  200. }
  201. /**
  202. * NBR(n) % NBR(r) => NBR(n % r)
  203. */
  204. public ATNumber base__oprem_(ATNumber n) throws InterpreterException {
  205. return NATNumber.atValue(javaValue % n.asNativeNumber().javaValue);
  206. }
  207. /**
  208. * NBR(n) /- NBR(d) => NBR(n / d)
  209. */
  210. public ATNumber base__opdiv__opmns_(ATNumber n) throws InterpreterException {
  211. return NATNumber.atValue(javaValue / n.asNativeNumber().javaValue);
  212. }
  213. // Numeric arithmetic operations
  214. // addition +
  215. public ATNumeric base__oppls_(ATNumeric other) throws InterpreterException {
  216. return other.base_addNumber(this);
  217. }
  218. public ATNumeric base_addNumber(ATNumber other) throws InterpreterException {
  219. return NATNumber.atValue(other.asNativeNumber().javaValue + javaValue);
  220. }
  221. public ATNumeric base_addFraction(ATFraction other) throws InterpreterException {
  222. return NATFraction.atValue(other.asNativeFraction().javaValue + javaValue);
  223. }
  224. // subtraction -
  225. public ATNumeric base__opmns_(ATNumeric other) throws InterpreterException {
  226. return other.base_subtractNumber(this);
  227. }
  228. public ATNumeric base_subtractNumber(ATNumber other) throws InterpreterException {
  229. return NATNumber.atValue(other.asNativeNumber().javaValue - javaValue);
  230. }
  231. public ATNumeric base_subtractFraction(ATFraction other) throws InterpreterException {
  232. return NATFraction.atValue(other.asNativeFraction().javaValue - javaValue);
  233. }
  234. // multiplication *
  235. public ATNumeric base__optms_(ATNumeric other) throws InterpreterException {
  236. return other.base_timesNumber(this);
  237. }
  238. public ATNumeric base_timesNumber(ATNumber other) throws InterpreterException {
  239. return NATNumber.atValue(other.asNativeNumber().javaValue * javaValue);
  240. }
  241. public ATNumeric base_timesFraction(ATFraction other) throws InterpreterException {
  242. return NATFraction.atValue(other.asNativeFraction().javaValue * javaValue);
  243. }
  244. // division /
  245. public ATNumeric base__opdiv_(ATNumeric other) throws InterpreterException {
  246. return other.base_divideNumber(this);
  247. }
  248. public ATNumeric base_divideNumber(ATNumber other) throws InterpreterException {
  249. if (javaValue == 0)
  250. throw new XIllegalArgument("Division by zero: " + other);
  251. return NATFraction.atValue((other.asNativeNumber().javaValue * 1.0) / javaValue);
  252. }
  253. public ATNumeric base_divideFraction(ATFraction other) throws InterpreterException {
  254. if (javaValue == 0)
  255. throw new XIllegalArgument("Division by zero: " + other);
  256. return NATFraction.atValue(other.asNativeFraction().javaValue / javaValue);
  257. }
  258. // comparison: generalized equality <=>
  259. public ATNumeric base__opltx__opeql__opgtx_(ATNumeric other) throws InterpreterException {
  260. return other.base_gequalsNumber(this);
  261. }
  262. public ATNumeric base_gequalsNumber(ATNumber other) throws InterpreterException {
  263. int n = other.asNativeNumber().javaValue;
  264. if (n < javaValue) {
  265. return NATNumber.MONE; // -1
  266. } else if (n > javaValue) {
  267. return NATNumber.ONE; // +1
  268. } else {
  269. return NATNumber.ZERO; // 0
  270. }
  271. }
  272. public ATNumeric base_gequalsFraction(ATFraction other) throws InterpreterException {
  273. double n = other.asNativeFraction().javaValue;
  274. if (n < javaValue) {
  275. return NATNumber.MONE; // -1
  276. } else if (n > javaValue) {
  277. return NATNumber.ONE; // +1
  278. } else {
  279. return NATNumber.ZERO; // 0
  280. }
  281. }
  282. /**
  283. * Converts an AmbientTalk number representing a time period in milliseconds
  284. * into a Java long representing the same time period in milliseconds.
  285. *
  286. * @return a Java long representation of self.
  287. */
  288. public long base_millisec() throws InterpreterException {
  289. return javaValue;
  290. }
  291. /**
  292. * Converts an AmbientTalk number representing a time period in seconds
  293. * into a Java long * 1000 representing a time period in milliseconds.
  294. *
  295. * @return a Java long representation of self * 1000.
  296. */
  297. public long base_seconds() throws InterpreterException {
  298. return javaValue * 1000;
  299. }
  300. /**
  301. * Converts an AmbientTalk number representing a minute time period
  302. * into a Java long * 1000 * 60 representing a
  303. * millisecond time period.
  304. *
  305. * @return a Java long representation of self * 1000 * 60.
  306. */
  307. public long base_minutes() throws InterpreterException {
  308. return javaValue * 60 * 1000;
  309. }
  310. }