OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 /// This library defines the association between runtime objects and | |
6 /// runtime types. | |
7 part of dart._runtime; | |
8 | |
9 /// | |
10 /// Runtime type information. This module defines the mapping from | |
11 /// runtime objects to their runtime type information. See the types | |
12 /// module for the definition of how type information is represented. | |
13 /// | |
14 /// Runtime objects fall into four main categories: | |
15 /// | |
16 /// - Things represented by javascript primitives, such as | |
17 /// null, numbers, booleans, strings, and symbols. For these | |
18 /// we map directly from the javascript type (given by typeof) | |
19 /// to the appropriate class type from core, which serves as their | |
20 /// rtti. | |
21 /// | |
22 /// - Functions, which are represented by javascript functions. | |
23 /// Representations of Dart functions always have a | |
24 /// _runtimeType property attached to them with the appropriate | |
25 /// rtti. | |
26 /// | |
27 /// - Objects (instances) which are represented by instances of | |
28 /// javascript (ES6) classes. Their types are given by their | |
29 /// classes, and the rtti is accessed by projecting out their | |
30 /// constructor field. | |
31 /// | |
32 /// - Types objects, which are represented as described in the types | |
33 /// module. Types always have a _runtimeType property attached to | |
34 /// them with the appropriate rtti. The rtti for these is always | |
35 /// core.Type. TODO(leafp): consider the possibility that we can | |
36 /// reliably recognize type objects and map directly to core.Type | |
37 /// rather than attaching this property everywhere. | |
38 /// | |
39 /// | |
40 | |
41 /// | |
42 ///Tag a closure with a type, using one of three forms: | |
43 /// dart.fn(cls) marks cls has having no optional or named | |
44 /// parameters, with all argument and return types as dynamic | |
45 /// dart.fn(cls, func) marks cls with the lazily computed | |
46 /// runtime type as computed by func() | |
47 /// dart.fn(cls, rType, argsT, extras) marks cls as having the | |
48 /// runtime type dart.functionType(rType, argsT, extras) | |
49 /// | |
50 /// Note that since we are producing a type for a concrete function, | |
51 /// it is sound to use the definite arrow type. | |
52 /// | |
53 fn(closure, @rest args) => JS('', '''(() => { | |
54 // Closure and a lazy type constructor | |
55 if ($args.length == 1) { | |
56 $defineLazyProperty($closure, $_runtimeType, {get : $args[0]}); | |
57 return $closure; | |
58 } | |
59 let t; | |
60 if ($args.length == 0) { | |
61 // No type arguments, it's all dynamic | |
62 t = $definiteFunctionType( | |
63 $dynamicR, Array($closure.length).fill($dynamicR)); | |
64 } else { | |
65 // We're passed the piecewise components of the function type, | |
66 // construct it. | |
67 t = $definiteFunctionType.apply(null, $args); | |
68 } | |
69 tag($closure, t); | |
70 return $closure; | |
71 })()'''); | |
72 | |
73 // TODO(vsm): How should we encode the runtime type? | |
74 final _runtimeType = JS('', 'Symbol("_runtimeType")'); | |
75 | |
76 checkPrimitiveType(obj) => JS('', '''(() => { | |
77 switch (typeof $obj) { | |
78 case "undefined": | |
79 return $Null; | |
80 case "number": | |
81 return Math.floor($obj) == $obj ? $int : $double; | |
82 case "boolean": | |
83 return $bool; | |
84 case "string": | |
85 return $String; | |
86 case "symbol": | |
87 return Symbol; | |
88 } | |
89 // Undefined is handled above. For historical reasons, | |
90 // typeof null == "object" in JS. | |
91 if ($obj === null) return $Null; | |
92 return null; | |
93 })()'''); | |
94 | |
95 runtimeType(obj) => JS('', '''(() => { | |
96 // Lookup primitive (int/double/string) | |
97 let result = $checkPrimitiveType($obj); | |
98 if (result !== null) return result; | |
99 | |
100 // Lookup recorded type | |
101 result = $obj.runtimeType; | |
102 if (result) return result; | |
103 | |
104 return $_nonPrimitiveRuntimeType(obj); | |
105 })()'''); | |
106 | |
107 getFunctionType(obj) => JS('', '''(() => { | |
108 // TODO(vsm): Encode this properly on the function for Dart-generated code. | |
109 let args = Array($obj.length).fill($dynamicR); | |
110 return $definiteFunctionType($bottom, args); | |
111 })()'''); | |
112 | |
113 /// | |
114 /// Returns the runtime type of obj. This is the same as `obj.realRuntimeType` | |
115 /// but will not call an overridden getter. | |
116 /// | |
117 /// Currently this will return null for non-Dart objects. | |
118 /// | |
119 realRuntimeType(obj) => JS('', '''(() => { | |
120 // Lookup primitive type | |
121 let result = $checkPrimitiveType($obj); | |
122 if (result !== null) return result; | |
123 | |
124 return $_nonPrimitiveRuntimeType(obj); | |
125 })()'''); | |
126 | |
127 _nonPrimitiveRuntimeType(obj) => JS('', '''(() => { | |
128 // Lookup recorded *real* type (not user definable runtimeType) | |
129 // TODO(vsm): Should we treat Dart and JS objects differently here? | |
130 // E.g., we can check if obj instanceof core.Object to differentiate. | |
131 let result = $obj[$_runtimeType]; | |
132 if (result) return result; | |
133 | |
134 // Lookup extension type | |
135 result = $obj[$_extensionType]; | |
136 if (result) return result; | |
137 | |
138 // Fallback on constructor for class types | |
139 result = $obj.constructor; | |
140 if (result == Function) { | |
141 // An undecorated Function should have come from | |
142 // JavaScript. Treat as untyped. | |
143 return $jsobject; | |
144 } | |
145 return result; | |
146 })()'''); | |
147 | |
148 LazyTagged(infoFn) => JS('', '''(() => { | |
149 class _Tagged { | |
150 get [$_runtimeType]() {return $infoFn();} | |
151 } | |
152 return _Tagged; | |
153 })()'''); | |
154 | |
155 read(value) => JS('', '''(() => { | |
156 return $value[$_runtimeType]; | |
157 })()'''); | |
158 | |
159 tag(value, info) => JS('', '''(() => { | |
160 $value[$_runtimeType] = $info; | |
161 })()'''); | |
162 | |
163 tagComputed(value, compute) => JS('', '''(() => { | |
164 $defineProperty($value, $_runtimeType, { get: $compute }); | |
165 })()'''); | |
166 | |
167 tagMemoized(value, compute) => JS('', '''(() => { | |
168 let cache = null; | |
169 function getter() { | |
170 if ($compute == null) return cache; | |
171 cache = $compute(); | |
172 $compute = null; | |
173 return cache; | |
174 } | |
175 $tagComputed($value, getter); | |
176 })()'''); | |
OLD | NEW |