| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 /// This library defines the operations that define and manipulate Dart | 5 /// This library defines the operations that define and manipulate Dart |
| 6 /// classes. Included in this are: | 6 /// classes. Included in this are: |
| 7 /// - Generics | 7 /// - Generics |
| 8 /// - Class metadata | 8 /// - Class metadata |
| 9 /// - Extension methods | 9 /// - Extension methods |
| 10 /// | 10 /// |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 let initMethod = proto[$name]; | 252 let initMethod = proto[$name]; |
| 253 let ctor = function() { return initMethod.apply(this, arguments); }; | 253 let ctor = function() { return initMethod.apply(this, arguments); }; |
| 254 ctor.prototype = proto; | 254 ctor.prototype = proto; |
| 255 // Use defineProperty so we don't hit a property defined on Function, | 255 // Use defineProperty so we don't hit a property defined on Function, |
| 256 // like `caller` and `arguments`. | 256 // like `caller` and `arguments`. |
| 257 $defineProperty($clazz, $name, { value: ctor, configurable: true }); | 257 $defineProperty($clazz, $name, { value: ctor, configurable: true }); |
| 258 })()'''); | 258 })()'''); |
| 259 | 259 |
| 260 final _extensionType = JS('', 'Symbol("extensionType")'); | 260 final _extensionType = JS('', 'Symbol("extensionType")'); |
| 261 | 261 |
| 262 getExtensionType(obj) => JS('', '$obj[$_extensionType]'); |
| 263 |
| 262 final dartx = JS('', '{}'); | 264 final dartx = JS('', '{}'); |
| 263 | 265 |
| 264 getExtensionSymbol(name) => JS('', '''(() => { | 266 getExtensionSymbol(name) => JS('', '''(() => { |
| 265 let sym = $dartx[$name]; | 267 let sym = $dartx[$name]; |
| 266 if (!sym) $dartx[$name] = sym = Symbol('dartx.' + $name); | 268 if (!sym) $dartx[$name] = sym = Symbol('dartx.' + $name); |
| 267 return sym; | 269 return sym; |
| 268 })()'''); | 270 })()'''); |
| 269 | 271 |
| 270 defineExtensionNames(names) => JS('', '$names.forEach($getExtensionSymbol)'); | 272 defineExtensionNames(names) => JS('', '$names.forEach($getExtensionSymbol)'); |
| 271 | 273 |
| 274 // Install properties in prototype order. Properties / descriptors from |
| 275 // more specific types should overwrite ones from less specific types. |
| 276 _installProperties(jsProto, extProto) => JS('', '''(() => { |
| 277 if (extProto !== $Object.prototype && extProto !== jsProto) { |
| 278 $_installProperties(jsProto, extProto.__proto__); |
| 279 } |
| 280 $copyTheseProperties(jsProto, extProto, $getOwnPropertySymbols(extProto)); |
| 281 })()'''); |
| 282 |
| 272 /// | 283 /// |
| 273 /// Copy symbols from the prototype of the source to destination. | 284 /// Copy symbols from the prototype of the source to destination. |
| 274 /// These are the only properties safe to copy onto an existing public | 285 /// These are the only properties safe to copy onto an existing public |
| 275 /// JavaScript class. | 286 /// JavaScript class. |
| 276 /// | 287 /// |
| 277 registerExtension(jsType, dartExtType) => JS('', '''(() => { | 288 registerExtension(jsType, dartExtType) => JS('', '''(() => { |
| 278 let extProto = $dartExtType.prototype; | 289 let extProto = $dartExtType.prototype; |
| 279 let jsProto = $jsType.prototype; | 290 let jsProto = $jsType.prototype; |
| 280 | 291 |
| 281 // Mark the JS type's instances so we can easily check for extensions. | 292 // Mark the JS type's instances so we can easily check for extensions. |
| 282 $assert_(jsProto[$_extensionType] === void 0); | 293 $assert_(jsProto[$_extensionType] === void 0); |
| 283 jsProto[$_extensionType] = extProto; | 294 jsProto[$_extensionType] = $dartExtType; |
| 284 | 295 $_installProperties(jsProto, extProto); |
| 285 let dartObjProto = $Object.prototype; | |
| 286 while (extProto !== dartObjProto && extProto !== jsProto) { | |
| 287 $copyTheseProperties(jsProto, extProto, $getOwnPropertySymbols(extProto)); | |
| 288 extProto = extProto.__proto__; | |
| 289 } | |
| 290 let originalSigFn = $getOwnPropertyDescriptor($dartExtType, $_methodSig).get; | 296 let originalSigFn = $getOwnPropertyDescriptor($dartExtType, $_methodSig).get; |
| 291 $assert_(originalSigFn); | 297 $assert_(originalSigFn); |
| 292 $defineMemoizedGetter($jsType, $_methodSig, originalSigFn); | 298 $defineMemoizedGetter($jsType, $_methodSig, originalSigFn); |
| 293 })()'''); | 299 })()'''); |
| 294 | 300 |
| 295 /// | 301 /// |
| 296 /// Mark a concrete type as implementing extension methods. | 302 /// Mark a concrete type as implementing extension methods. |
| 297 /// For example: `class MyIter implements Iterable`. | 303 /// For example: `class MyIter implements Iterable`. |
| 298 /// | 304 /// |
| 299 /// This takes a list of names, which are the extension methods implemented. | 305 /// This takes a list of names, which are the extension methods implemented. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 // Check for certain names that we can't use in JS | 344 // Check for certain names that we can't use in JS |
| 339 if ($name == 'constructor' || $name == 'prototype') { | 345 if ($name == 'constructor' || $name == 'prototype') { |
| 340 $name = '+' + $name; | 346 $name = '+' + $name; |
| 341 } | 347 } |
| 342 return $name; | 348 return $name; |
| 343 })()'''); | 349 })()'''); |
| 344 | 350 |
| 345 /// Sets the type of `obj` to be `type` | 351 /// Sets the type of `obj` to be `type` |
| 346 setType(obj, type) => JS('', '''(() => { | 352 setType(obj, type) => JS('', '''(() => { |
| 347 $obj.__proto__ = $type.prototype; | 353 $obj.__proto__ = $type.prototype; |
| 354 // TODO(vsm): This should be set in registerExtension, but that is only |
| 355 // invoked on the generic type (e.g., JSArray<dynamic>, not JSArray<int>). |
| 356 $obj.__proto__[$_extensionType] = $type; |
| 348 return $obj; | 357 return $obj; |
| 349 })()'''); | 358 })()'''); |
| 350 | 359 |
| 351 /// Sets the element type of a list literal. | 360 /// Sets the element type of a list literal. |
| 352 list(obj, elementType) => | 361 list(obj, elementType) => |
| 353 JS('', '$setType($obj, ${getGenericClass(JSArray)}($elementType))'); | 362 JS('', '$setType($obj, ${getGenericClass(JSArray)}($elementType))'); |
| 354 | 363 |
| 355 setBaseClass(derived, base) => JS('', '''(() => { | 364 setBaseClass(derived, base) => JS('', '''(() => { |
| 356 // Link the extension to the type it's extending as a base class. | 365 // Link the extension to the type it's extending as a base class. |
| 357 $derived.prototype.__proto__ = $base.prototype; | 366 $derived.prototype.__proto__ = $base.prototype; |
| 358 })()'''); | 367 })()'''); |
| OLD | NEW |