| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #library('core'); |
| 6 |
| 7 #import('coreimpl.dart'); |
| 8 |
| 9 #import('js_helper.dart'); // TODO(ahe): remove this import. |
| 10 |
| 5 void print(var obj) { | 11 void print(var obj) { |
| 6 obj = obj.toString(); | 12 obj = obj.toString(); |
| 7 var hasConsole = JS("bool", @"typeof console == 'object'"); | 13 var hasConsole = JS("bool", @"typeof console == 'object'"); |
| 8 if (hasConsole) { | 14 if (hasConsole) { |
| 9 JS("void", @"console.log($0)", obj); | 15 JS("void", @"console.log($0)", obj); |
| 10 } else { | 16 } else { |
| 11 JS("void", @"write($0)", obj); | 17 JS("void", @"write($0)", obj); |
| 12 JS("void", @"write('\n')"); | 18 JS("void", @"write('\n')"); |
| 13 } | 19 } |
| 14 } | 20 } |
| 15 | 21 |
| 16 $throw(String msg) { | |
| 17 var e = JS("Object", @"new Error($0)", msg); | |
| 18 var hasTrace = JS("bool", @"Error.captureStackTrace !== (void 0)"); | |
| 19 if (hasTrace) { | |
| 20 JS("void", @"Error.captureStackTrace($0)", e); | |
| 21 } | |
| 22 throw e; | |
| 23 } | |
| 24 | |
| 25 /** | |
| 26 * Returns true if both arguments are numbers. | |
| 27 * If only the first argument is a number, throws the given message as | |
| 28 * exception. | |
| 29 */ | |
| 30 bool checkNumbers(var a, var b, var message) { | |
| 31 if (JS("bool", @"typeof $0 === 'number'", a)) { | |
| 32 if (JS("bool", @"typeof $0 === 'number'", b)) { | |
| 33 return true; | |
| 34 } else { | |
| 35 throw message; | |
| 36 } | |
| 37 } | |
| 38 return false; | |
| 39 } | |
| 40 | |
| 41 | |
| 42 bool isJSArray(var value) { | |
| 43 return JS("bool", @"$0.constructor === Array", value); | |
| 44 } | |
| 45 | |
| 46 | |
| 47 add(var a, var b) { | |
| 48 if (checkNumbers(a, b, "num+ expects a number as second operand.")) { | |
| 49 return JS("num", @"$0 + $1", a, b); | |
| 50 } else if (JS("bool", @"typeof $0 === 'string'", a)) { | |
| 51 b = b.toString(); | |
| 52 if (JS("bool", @"typeof $0 === 'string'", b)) { | |
| 53 return JS("String", @"$0 + $1", a, b); | |
| 54 } | |
| 55 // The following line is too long, but we can't break it using the + | |
| 56 // operator, since that's what we are defining here. | |
| 57 throw "calling toString() on right hand operand of operator + did not return
a String"; | |
| 58 } | |
| 59 return UNINTERCEPTED(a + b); | |
| 60 } | |
| 61 | |
| 62 div(var a, var b) { | |
| 63 if (checkNumbers(a, b, "num/ expects a number as second operand.")) { | |
| 64 return JS("num", @"$0 / $1", a, b); | |
| 65 } | |
| 66 return UNINTERCEPTED(a / b); | |
| 67 } | |
| 68 | |
| 69 mul(var a, var b) { | |
| 70 if (checkNumbers(a, b, "num* expects a number as second operand.")) { | |
| 71 return JS("num", @"$0 * $1", a, b); | |
| 72 } | |
| 73 return UNINTERCEPTED(a * b); | |
| 74 } | |
| 75 | |
| 76 sub(var a, var b) { | |
| 77 if (checkNumbers(a, b, "num- expects a number as second operand.")) { | |
| 78 return JS("num", @"$0 - $1", a, b); | |
| 79 } | |
| 80 return UNINTERCEPTED(a - b); | |
| 81 } | |
| 82 | |
| 83 mod(var a, var b) { | |
| 84 if (checkNumbers(a, b, "int% expects an int as second operand.")) { | |
| 85 // Euclidean Modulo. | |
| 86 int result = JS("num", @"$0 % $1", a, b); | |
| 87 if (result == 0) return 0; // Make sure we don't return -0.0. | |
| 88 if (result > 0) return result; | |
| 89 if (b < 0) { | |
| 90 return result - b; | |
| 91 } else { | |
| 92 return result + b; | |
| 93 } | |
| 94 } | |
| 95 return UNINTERCEPTED(a % b); | |
| 96 } | |
| 97 | |
| 98 tdiv(var a, var b) { | |
| 99 if (checkNumbers(a, b, "num~/ expects a number as second operand.")) { | |
| 100 var tmp = a / b; | |
| 101 // TODO(ngeoffray): Use tmp.floor and tmp.ceil when | |
| 102 // we can handle them. | |
| 103 if (tmp < 0) { | |
| 104 return JS("num", @"Math.ceil($0)", tmp); | |
| 105 } else { | |
| 106 return JS("num", @"Math.floor($0)", tmp); | |
| 107 } | |
| 108 } | |
| 109 return UNINTERCEPTED(a ~/ b); | |
| 110 } | |
| 111 | |
| 112 eq(var a, var b) { | |
| 113 if (JS("bool", @"typeof $0 === 'object'", a)) { | |
| 114 if (JS_HAS_EQUALS(a)) { | |
| 115 return UNINTERCEPTED(a == b) === true; | |
| 116 } else { | |
| 117 return JS("bool", @"$0 === $1", a, b); | |
| 118 } | |
| 119 } | |
| 120 // TODO(lrn): is NaN === NaN ? Is -0.0 === 0.0 ? | |
| 121 return JS("bool", @"$0 === $1", a, b); | |
| 122 } | |
| 123 | |
| 124 eqq(var a, var b) { | |
| 125 return JS("bool", @"$0 === $1", a, b); | |
| 126 } | |
| 127 | |
| 128 eqNull(var a) { | |
| 129 if (JS("bool", @"typeof $0 === 'object'", a)) { | |
| 130 if (JS_HAS_EQUALS(a)) { | |
| 131 return UNINTERCEPTED(a == null) === true; | |
| 132 } else { | |
| 133 return false; | |
| 134 } | |
| 135 } else { | |
| 136 return JS("bool", @"typeof $0 === 'undefined'", a); | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 gt(var a, var b) { | |
| 141 if (checkNumbers(a, b, "num> expects a number as second operand.")) { | |
| 142 return JS("bool", @"$0 > $1", a, b); | |
| 143 } | |
| 144 return UNINTERCEPTED(a > b); | |
| 145 } | |
| 146 | |
| 147 ge(var a, var b) { | |
| 148 if (checkNumbers(a, b, "num>= expects a number as second operand.")) { | |
| 149 return JS("bool", @"$0 >= $1", a, b); | |
| 150 } | |
| 151 return UNINTERCEPTED(a >= b); | |
| 152 } | |
| 153 | |
| 154 lt(var a, var b) { | |
| 155 if (checkNumbers(a, b, "num< expects a number as second operand.")) { | |
| 156 return JS("bool", @"$0 < $1", a, b); | |
| 157 } | |
| 158 return UNINTERCEPTED(a < b); | |
| 159 } | |
| 160 | |
| 161 le(var a, var b) { | |
| 162 if (checkNumbers(a, b, "num<= expects a number as second operand.")) { | |
| 163 return JS("bool", @"$0 <= $1", a, b); | |
| 164 } | |
| 165 return UNINTERCEPTED(a <= b); | |
| 166 } | |
| 167 | |
| 168 shl(var a, var b) { | |
| 169 // TODO(floitsch): inputs must be integers. | |
| 170 if (checkNumbers(a, b, "int<< expects an int as second operand.")) { | |
| 171 return JS("num", @"$0 << $1", a, b); | |
| 172 } | |
| 173 return UNINTERCEPTED(a << b); | |
| 174 } | |
| 175 | |
| 176 shr(var a, var b) { | |
| 177 // TODO(floitsch): inputs must be integers. | |
| 178 if (checkNumbers(a, b, "int>> expects an int as second operand.")) { | |
| 179 return JS("num", @"$0 >> $1", a, b); | |
| 180 } | |
| 181 return UNINTERCEPTED(a >> b); | |
| 182 } | |
| 183 | |
| 184 and(var a, var b) { | |
| 185 // TODO(floitsch): inputs must be integers. | |
| 186 if (checkNumbers(a, b, "int& expects an int as second operand.")) { | |
| 187 return JS("num", @"$0 & $1", a, b); | |
| 188 } | |
| 189 return UNINTERCEPTED(a & b); | |
| 190 } | |
| 191 | |
| 192 or(var a, var b) { | |
| 193 // TODO(floitsch): inputs must be integers. | |
| 194 if (checkNumbers(a, b, "int| expects an int as second operand.")) { | |
| 195 return JS("num", @"$0 | $1", a, b); | |
| 196 } | |
| 197 return UNINTERCEPTED(a | b); | |
| 198 } | |
| 199 | |
| 200 xor(var a, var b) { | |
| 201 // TODO(floitsch): inputs must be integers. | |
| 202 if (checkNumbers(a, b, "int^ expects an int as second operand.")) { | |
| 203 return JS("num", @"$0 ^ $1", a, b); | |
| 204 } | |
| 205 return UNINTERCEPTED(a ^ b); | |
| 206 } | |
| 207 | |
| 208 not(var a) { | |
| 209 if (JS("bool", @"typeof $0 === 'number'", a)) return JS("num", @"~$0", a); | |
| 210 return UNINTERCEPTED(~a); | |
| 211 } | |
| 212 | |
| 213 neg(var a) { | |
| 214 if (JS("bool", @"typeof $0 === 'number'", a)) return JS("num", @"-$0", a); | |
| 215 return UNINTERCEPTED(-a); | |
| 216 } | |
| 217 | |
| 218 index(var a, var index) { | |
| 219 if (JS("bool", @"typeof $0 === 'string'", a) || isJSArray(a)) { | |
| 220 if (!isInt(index)) $throw('Illegal argument'); | |
| 221 if (index < 0 || index >= a.length) $throw('Out of bounds'); | |
| 222 return JS("Object", @"$0[$1]", a, index); | |
| 223 } | |
| 224 return UNINTERCEPTED(a[index]); | |
| 225 } | |
| 226 | |
| 227 indexSet(var a, var index, var value) { | |
| 228 if (isJSArray(a)) { | |
| 229 if (!isInt(index)) $throw('Illegal argument'); | |
| 230 if (index < 0 || index >= a.length) $throw('Out of bounds'); | |
| 231 return JS("Object", @"$0[$1] = $2", a, index, value); | |
| 232 } | |
| 233 return UNINTERCEPTED(a[index] = value); | |
| 234 } | |
| 235 | |
| 236 builtin$add$1(var receiver, var value) { | |
| 237 if (isJSArray(receiver)) { | |
| 238 JS("Object", @"$0.push($1)", receiver, value); | |
| 239 return; | |
| 240 } | |
| 241 return UNINTERCEPTED(receiver.add(value)); | |
| 242 } | |
| 243 | |
| 244 builtin$removeLast$0(var receiver) { | |
| 245 if (isJSArray(receiver)) { | |
| 246 return JS("Object", @"$0.pop()", receiver); | |
| 247 } | |
| 248 return UNINTERCEPTED(receiver.removeLast()); | |
| 249 } | |
| 250 | |
| 251 builtin$filter$1(var receiver, var predicate) { | |
| 252 if (isJSArray(receiver)) { | |
| 253 return JS("Object", @"$0.filter(function(v) { return $1(v) === true; })", | |
| 254 receiver, predicate); | |
| 255 } | |
| 256 return UNINTERCEPTED(receiver.filter(predicate)); | |
| 257 } | |
| 258 | |
| 259 | |
| 260 builtin$get$length(var receiver) { | |
| 261 if (JS("bool", @"typeof $0 === 'string'", receiver) || isJSArray(receiver)) { | |
| 262 return JS("num", @"$0.length", receiver); | |
| 263 } | |
| 264 return UNINTERCEPTED(receiver.length); | |
| 265 } | |
| 266 | |
| 267 | |
| 268 builtin$toString$0(var value) { | |
| 269 if (JS("bool", @"typeof $0 == 'object'", value)) { | |
| 270 if (isJSArray(value)) { | |
| 271 return "Instance of 'List'"; | |
| 272 } | |
| 273 return UNINTERCEPTED(value.toString()); | |
| 274 } | |
| 275 if (JS("bool", @"$0 === 0 && (1 / $0) < 0", value)) { | |
| 276 return "-0.0"; | |
| 277 } | |
| 278 if (value === null) return "null"; | |
| 279 return JS("string", @"String($0)", value); | |
| 280 } | |
| 281 | |
| 282 | |
| 283 builtin$iterator$0(var receiver) { | |
| 284 if (isJSArray(receiver)) { | |
| 285 return new ListIterator(receiver); | |
| 286 } | |
| 287 return UNINTERCEPTED(receiver.iterator()); | |
| 288 } | |
| 289 | |
| 290 builtin$charCodeAt$1(var receiver, int index) { | |
| 291 if (JS("bool", @"typeof receiver === 'string'")) { | |
| 292 return JS("string", @"$0.charCodeAt($1)", receiver, index); | |
| 293 } else { | |
| 294 return UNINTERCEPTED(receiver.charCodeAt(index)); | |
| 295 } | |
| 296 } | |
| 297 | |
| 298 builtin$isEmpty$0(var receiver) { | |
| 299 if (JS("bool", @"typeof $0 === 'string'", receiver) || isJSArray(receiver)) { | |
| 300 return JS("bool", @"$0.length === 0", receiver); | |
| 301 } | |
| 302 return UNINTERCEPTED(receiver.isEmpty()); | |
| 303 } | |
| 304 | |
| 305 | |
| 306 bool isInt(var v) { | |
| 307 return JS("bool", @"($0 | 0) === $1", v, v); | |
| 308 } | |
| 309 | |
| 310 /* Include when interfaces are implemented | 22 /* Include when interfaces are implemented |
| 311 interface Iterable<T> { | 23 interface Iterable<T> { |
| 312 Iterator<T> iterator(); | 24 Iterator<T> iterator(); |
| 313 } | 25 } |
| 314 | 26 |
| 315 interface Iterator<T> { | 27 interface Iterator<T> { |
| 316 bool hasNext(); | 28 bool hasNext(); |
| 317 T next(); | 29 T next(); |
| 318 } | 30 } |
| 319 */ | 31 */ |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 static void equals(var expected, var actual) { | 87 static void equals(var expected, var actual) { |
| 376 if (expected == actual) return; | 88 if (expected == actual) return; |
| 377 _fail('Expect.equals(expected: <$expected>, actual:<$actual> fails.'); | 89 _fail('Expect.equals(expected: <$expected>, actual:<$actual> fails.'); |
| 378 } | 90 } |
| 379 | 91 |
| 380 static void fail(String message) { | 92 static void fail(String message) { |
| 381 _fail("Expect.fail('$message')"); | 93 _fail("Expect.fail('$message')"); |
| 382 } | 94 } |
| 383 | 95 |
| 384 static void _fail(String message) { | 96 static void _fail(String message) { |
| 385 $throw(message); | 97 throw message; |
| 386 } | 98 } |
| 387 | 99 |
| 388 static void isTrue(var actual) { | 100 static void isTrue(var actual) { |
| 389 if (actual === true) return; | 101 if (actual === true) return; |
| 390 _fail("Expect.isTrue($actual) fails."); | 102 _fail("Expect.isTrue($actual) fails."); |
| 391 } | 103 } |
| 392 | 104 |
| 393 static void isFalse(var actual) { | 105 static void isFalse(var actual) { |
| 394 if (actual === false) return; | 106 if (actual === false) return; |
| 395 _fail("Expect.isFalse($actual) fails."); | 107 _fail("Expect.isFalse($actual) fails."); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 450 } else { | 162 } else { |
| 451 return | 163 return |
| 452 JS("num", @"Math.floor($0 + (Date.now() - $1))", elapsedMs, startMs); | 164 JS("num", @"Math.floor($0 + (Date.now() - $1))", elapsedMs, startMs); |
| 453 } | 165 } |
| 454 } | 166 } |
| 455 | 167 |
| 456 int frequency() { | 168 int frequency() { |
| 457 return 1000; | 169 return 1000; |
| 458 } | 170 } |
| 459 } | 171 } |
| OLD | NEW |