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>). | |
Jennifer Messerly
2016/02/10 00:20:30
Given a generic type T, it's possible to get its r
vsm
2016/02/11 22:36:06
I need this to go the other way around - i.e., to
Jennifer Messerly
2016/02/11 23:04:57
I'm 99% sure this should not be needed. In JavaScr
| |
356 $obj.__proto__[$_extensionType] = type; | |
Jennifer Messerly
2016/02/10 00:20:30
(possibly moot based on above comment)
I think th
vsm
2016/02/11 22:36:06
Done.
| |
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 |