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