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 part of dart._runtime; | 4 part of dart._runtime; |
5 | 5 |
6 /// This library defines a set of general javascript utilities for us | 6 /// This library defines a set of general javascript utilities for us |
7 /// by the Dart runtime. | 7 /// by the Dart runtime. |
8 // TODO(ochafik): Rewrite some of these in Dart when possible. | 8 // TODO(ochafik): Rewrite some of these in Dart when possible. |
9 | 9 |
10 final defineProperty = JS('', 'Object.defineProperty'); | 10 defineProperty(obj, name, desc) => |
11 final getOwnPropertyDescriptor = JS('', 'Object.getOwnPropertyDescriptor'); | 11 JS('', 'Object.defineProperty(#, #, #)', obj, name, desc); |
12 final getOwnPropertyNames = JS('', 'Object.getOwnPropertyNames'); | 12 |
13 final getOwnPropertySymbols = JS('', 'Object.getOwnPropertySymbols'); | 13 getOwnPropertyDescriptor(obj, name) => |
| 14 JS('', 'Object.getOwnPropertyDescriptor(#, #)', obj, name); |
| 15 |
| 16 getOwnPropertyNames(obj) => JS('', 'Object.getOwnPropertyNames(#)', obj); |
| 17 |
| 18 getOwnPropertySymbols(obj) => JS('', 'Object.getOwnPropertySymbols(#)', obj); |
14 | 19 |
15 final hasOwnProperty = JS('', 'Object.prototype.hasOwnProperty'); | 20 final hasOwnProperty = JS('', 'Object.prototype.hasOwnProperty'); |
16 | 21 |
17 // TODO(ochafik): Add ES6 class syntax support to JS intrinsics to avoid this. | 22 // TODO(ochafik): Add ES6 class syntax support to JS intrinsics to avoid this. |
18 final StrongModeError = JS('', '''(function() { | 23 final StrongModeError = JS('', '''(function() { |
19 function StrongModeError(message) { | 24 function StrongModeError(message) { |
20 Error.call(this); | 25 Error.call(this); |
21 this.message = message; | 26 this.message = message; |
22 }; | 27 }; |
23 Object.setPrototypeOf(StrongModeError.prototype, Error.prototype); | 28 Object.setPrototypeOf(StrongModeError.prototype, Error.prototype); |
24 return StrongModeError; | 29 return StrongModeError; |
25 })()'''); | 30 })()'''); |
26 | 31 |
27 /// This error indicates a strong mode specific failure. | 32 /// This error indicates a strong mode specific failure. |
28 void throwStrongModeError(String message) => JS('', '''(() => { | 33 void throwStrongModeError(String message) { |
29 throw new $StrongModeError($message); | 34 JS('', 'throw new #(#);', StrongModeError, message); |
30 })()'''); | 35 } |
31 | 36 |
32 /// This error indicates a bug in the runtime or the compiler. | 37 /// This error indicates a bug in the runtime or the compiler. |
33 void throwInternalError(String message) => JS('', '''(() => { | 38 void throwInternalError(String message) { |
34 throw Error($message); | 39 JS('', 'throw Error(#)', message); |
35 })()'''); | 40 } |
36 | 41 |
37 getOwnNamesAndSymbols(obj) => JS('', '''(() => { | 42 getOwnNamesAndSymbols(obj) { |
38 return $getOwnPropertyNames($obj).concat($getOwnPropertySymbols($obj)); | 43 var names = getOwnPropertyNames(obj); |
39 })()'''); | 44 var symbols = getOwnPropertySymbols(obj); |
| 45 return JS('', '#.concat(#)', names, symbols); |
| 46 } |
40 | 47 |
41 safeGetOwnProperty(obj, String name) => JS('', '''(() => { | 48 safeGetOwnProperty(obj, String name) { |
42 let desc = $getOwnPropertyDescriptor($obj, $name); | 49 var desc = getOwnPropertyDescriptor(obj, name); |
43 if (desc) return desc.value; | 50 if (desc != null) return JS('', '#.value', desc); |
44 })()'''); | 51 } |
45 | 52 |
46 /// Defines a lazy property. | 53 /// Defines a lazy property. |
47 /// After initial get or set, it will replace itself with a value property. | 54 /// After initial get or set, it will replace itself with a value property. |
48 // TODO(jmesserly): reusing descriptor objects has been shown to improve | 55 // TODO(jmesserly): reusing descriptor objects has been shown to improve |
49 // performance in other projects (e.g. webcomponents.js ShadowDOM polyfill). | 56 // performance in other projects (e.g. webcomponents.js ShadowDOM polyfill). |
50 defineLazyProperty(to, name, desc) => JS('', '''(() => { | 57 defineLazyProperty(to, name, desc) => JS('', '''(() => { |
51 let init = $desc.get; | 58 let init = $desc.get; |
52 let value = null; | 59 let value = null; |
53 | 60 |
54 function lazySetter(x) { | 61 function lazySetter(x) { |
(...skipping 17 matching lines...) Expand all Loading... |
72 if ($desc.set) $desc.set = lazySetter; | 79 if ($desc.set) $desc.set = lazySetter; |
73 return $defineProperty($to, $name, $desc); | 80 return $defineProperty($to, $name, $desc); |
74 })()'''); | 81 })()'''); |
75 | 82 |
76 void defineLazy(to, from) => JS('', '''(() => { | 83 void defineLazy(to, from) => JS('', '''(() => { |
77 for (let name of $getOwnNamesAndSymbols($from)) { | 84 for (let name of $getOwnNamesAndSymbols($from)) { |
78 $defineLazyProperty($to, name, $getOwnPropertyDescriptor($from, name)); | 85 $defineLazyProperty($to, name, $getOwnPropertyDescriptor($from, name)); |
79 } | 86 } |
80 })()'''); | 87 })()'''); |
81 | 88 |
82 defineMemoizedGetter(obj, String name, getter) => JS('', '''(() => { | 89 defineMemoizedGetter(obj, String name, getter) { |
83 return $defineLazyProperty($obj, $name, {get: $getter}); | 90 return defineLazyProperty(obj, name, JS('', '{get: #}', getter)); |
84 })()'''); | 91 } |
85 | 92 |
86 | |
87 // TODO(jmesserly): don't stomp on native Symbol.iterator. | |
88 // We need to find a better solution for this. | |
89 // See: https://github.com/dart-lang/dev_compiler/issues/487 | |
90 copyTheseProperties(to, from, names) => JS('', '''(() => { | 93 copyTheseProperties(to, from, names) => JS('', '''(() => { |
91 for (let name of $names) { | 94 for (let name of $names) { |
92 let desc = $getOwnPropertyDescriptor($from, name); | 95 $copyProperty($to, $from, name); |
93 if (desc != void 0) { | |
94 if (name == Symbol.iterator) { | |
95 // On native types, Symbol.iterator may already be present. | |
96 let existing = $getOwnPropertyDescriptor($to, name); | |
97 if (existing != null) { | |
98 if (existing.writable) $to[Symbol.iterator] = desc.value; | |
99 continue; | |
100 } | |
101 } | |
102 $defineProperty($to, name, desc); | |
103 } else { | |
104 $defineLazyProperty($to, name, () => $from[name]); | |
105 } | |
106 } | 96 } |
107 return $to; | 97 return $to; |
108 })()'''); | 98 })()'''); |
109 | 99 |
| 100 copyProperty(to, from, name) { |
| 101 var desc = getOwnPropertyDescriptor(from, name); |
| 102 if (JS('bool', '# == Symbol.iterator', name)) { |
| 103 // On native types, Symbol.iterator may already be present. |
| 104 // TODO(jmesserly): investigate if we still need this. |
| 105 // If so, we need to find a better solution. |
| 106 // See: https://github.com/dart-lang/dev_compiler/issues/487 |
| 107 var existing = getOwnPropertyDescriptor(to, name); |
| 108 if (existing != null) { |
| 109 if (JS('bool', '#.writable', existing)) { |
| 110 JS('', '#[#] = #.value', to, name, desc); |
| 111 } |
| 112 return; |
| 113 } |
| 114 } |
| 115 defineProperty(to, name, desc); |
| 116 } |
| 117 |
110 /// Copy properties from source to destination object. | 118 /// Copy properties from source to destination object. |
111 /// This operation is commonly called `mixin` in JS. | 119 /// This operation is commonly called `mixin` in JS. |
112 copyProperties(to, from) => JS('', '''(() => { | 120 copyProperties(to, from) { |
113 return $copyTheseProperties($to, $from, $getOwnNamesAndSymbols($from)); | 121 return copyTheseProperties(to, from, getOwnNamesAndSymbols(from)); |
114 })()'''); | 122 } |
OLD | NEW |