Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(250)

Side by Side Diff: tool/input_sdk/private/operations.dart

Issue 1771713002: Reorganize tool/input_sdk/private (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tool/input_sdk/private/generators.dart ('k') | tool/input_sdk/private/rtti.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 runtime operations on objects used by the code
6 /// generator.
7 part of dart._runtime;
8
9 _canonicalFieldName(obj, name, args, displayName) => JS('', '''(() => {
10 $name = $canonicalMember($obj, $name);
11 if ($name) return $name;
12 // TODO(jmesserly): in the future we might have types that "overlay" Dart
13 // methods while also exposing the full native API, e.g. dart:html vs
14 // dart:dom. To support that we'd need to fall back to the normal name
15 // if an extension method wasn't found.
16 $throwNoSuchMethodFunc($obj, $displayName, $args);
17 })()''');
18
19 dload(obj, field) => JS('', '''(() => {
20 $field = $_canonicalFieldName($obj, $field, [], $field);
21 if ($hasMethod($obj, $field)) {
22 return $bind($obj, $field);
23 }
24 // TODO(vsm): Implement NSM robustly. An 'in' check breaks on certain
25 // types. hasOwnProperty doesn't chase the proto chain.
26 // Also, do we want an NSM on regular JS objects?
27 // See: https://github.com/dart-lang/dev_compiler/issues/169
28 let result = $obj[$field];
29 return result;
30 })()''');
31
32 dput(obj, field, value) => JS('', '''(() => {
33 $field = $_canonicalFieldName($obj, $field, [$value], $field);
34 // TODO(vsm): Implement NSM and type checks.
35 // See: https://github.com/dart-lang/dev_compiler/issues/170
36 $obj[$field] = $value;
37 return $value;
38 })()''');
39
40 /// Check that a function of a given type can be applied to
41 /// actuals.
42 checkApply(type, actuals) => JS('', '''(() => {
43 if ($actuals.length < $type.args.length) return false;
44 let index = 0;
45 for(let i = 0; i < $type.args.length; ++i) {
46 if (!$instanceOfOrNull($actuals[i], $type.args[i])) return false;
47 ++index;
48 }
49 if ($actuals.length == $type.args.length) return true;
50 let extras = $actuals.length - $type.args.length;
51 if ($type.optionals.length > 0) {
52 if (extras > $type.optionals.length) return false;
53 for(let i = 0, j=index; i < extras; ++i, ++j) {
54 if (!$instanceOfOrNull($actuals[j], $type.optionals[i])) return false;
55 }
56 return true;
57 }
58 // TODO(leafp): We can't tell when someone might be calling
59 // something expecting an optional argument with named arguments
60
61 if (extras != 1) return false;
62 // An empty named list means no named arguments
63 if ($getOwnPropertyNames($type.named).length == 0) return false;
64 let opts = $actuals[index];
65 let names = $getOwnPropertyNames(opts);
66 // Type is something other than a map
67 if (names.length == 0) return false;
68 for (var name of names) {
69 if (!($hasOwnProperty.call($type.named, name))) {
70 return false;
71 }
72 if (!$instanceOfOrNull(opts[name], $type.named[name])) return false;
73 }
74 return true;
75 })()''');
76
77
78 throwNoSuchMethod(obj, name, pArgs, nArgs, extras) => JS('', '''(() => {
79 $throw_(new $NoSuchMethodError($obj, $name, $pArgs, $nArgs, $extras));
80 })()''');
81
82 throwNoSuchMethodFunc(obj, name, pArgs, opt_func) => JS('', '''(() => {
83 if ($obj === void 0) $obj = $opt_func;
84 $throwNoSuchMethod($obj, $name, $pArgs);
85 })()''');
86
87 checkAndCall(f, ftype, obj, args, name) => JS('', '''(() => {
88 let originalFunction = $f;
89 if (!($f instanceof Function)) {
90 // We're not a function (and hence not a method either)
91 // Grab the `call` method if it's not a function.
92 if ($f != null) {
93 $ftype = $getMethodType($f, 'call');
94 $f = $f.call;
95 }
96 if (!($f instanceof Function)) {
97 $throwNoSuchMethodFunc($obj, $name, $args, originalFunction);
98 }
99 }
100 // If f is a function, but not a method (no method type)
101 // then it should have been a function valued field, so
102 // get the type from the function.
103 if ($ftype === void 0) {
104 $ftype = $read($f);
105 }
106
107 if (!$ftype) {
108 // TODO(leafp): Allow JS objects to go through?
109 // This includes the DOM.
110 return $f.apply($obj, $args);
111 }
112
113 if ($checkApply($ftype, $args)) {
114 return $f.apply($obj, $args);
115 }
116
117 // TODO(leafp): throw a type error (rather than NSM)
118 // if the arity matches but the types are wrong.
119 $throwNoSuchMethodFunc($obj, $name, $args, originalFunction);
120 })()''');
121
122 dcall(f, @rest args) => JS('', '''(() => {
123 let ftype = $read($f);
124 return $checkAndCall($f, ftype, void 0, $args, 'call');
125 })()''');
126
127 /// Shared code for dsend, dindex, and dsetindex. */
128 callMethod(obj, name, args, displayName) => JS('', '''(() => {
129 let symbol = $_canonicalFieldName($obj, $name, $args, $displayName);
130 let f = $obj != null ? $obj[symbol] : null;
131 let ftype = $getMethodType($obj, $name);
132 return $checkAndCall(f, ftype, $obj, $args, $displayName);
133 })()''');
134
135 dsend(obj, method, @rest args) => JS('', '''(() => {
136 return $callMethod($obj, $method, $args, $method);
137 })()''');
138
139 dindex(obj, index) => JS('', '''(() => {
140 return $callMethod($obj, 'get', [$index], '[]');
141 })()''');
142
143 dsetindex(obj, index, value) => JS('', '''(() => {
144 $callMethod($obj, 'set', [$index, $value], '[]=');
145 return $value;
146 })()''');
147
148 _ignoreTypeFailure(actual, type) => JS('', '''(() => {
149 // TODO(vsm): Remove this hack ...
150 // This is primarily due to the lack of generic methods,
151 // but we need to triage all the types.
152 if (isSubtype($type, $Iterable) && isSubtype($actual, $Iterable) ||
153 isSubtype($type, $Future) && isSubtype($actual, $Future) ||
154 isSubtype($type, $Map) && isSubtype($actual, $Map) ||
155 isSubtype($type, $Function) && isSubtype($actual, $Function) ||
156 isSubtype($type, $Stream) && isSubtype($actual, $Stream) ||
157 isSubtype($type, $StreamSubscription) &&
158 isSubtype($actual, $StreamSubscription)) {
159 console.warn('Ignoring cast fail from ' + $typeName($actual) +
160 ' to ' + $typeName($type));
161 return true;
162 }
163 return false;
164 })()''');
165
166 strongInstanceOf(obj, type, ignoreFromWhiteList) => JS('', '''(() => {
167 let actual = $realRuntimeType($obj);
168 if ($isSubtype(actual, $type) || actual == $jsobject ||
169 actual == $int && type == $double) return true;
170 if ($ignoreFromWhiteList == void 0) return false;
171 if ($isGroundType($type)) return false;
172 if ($_ignoreTypeFailure(actual, $type)) return true;
173 return false;
174 })()''');
175
176 instanceOfOrNull(obj, type) => JS('', '''(() => {
177 if (($obj == null) || $strongInstanceOf($obj, $type, true)) return true;
178 return false;
179 })()''');
180
181 instanceOf(obj, type) => JS('', '''(() => {
182 if ($strongInstanceOf($obj, $type)) return true;
183 // TODO(#296): This is perhaps too eager to throw a StrongModeError?
184 // It will throw on <int>[] is List<String>.
185 // TODO(vsm): We can statically detect many cases where this
186 // check is unnecessary.
187 if ($isGroundType($type)) return false;
188 let actual = $realRuntimeType($obj);
189 $throwStrongModeError('Strong mode is check failure: ' +
190 $typeName(actual) + ' does not soundly subtype ' +
191 $typeName($type));
192 })()''');
193
194 cast(obj, type) => JS('', '''(() => {
195 // TODO(#296): This is perhaps too eager to throw a StrongModeError?
196 // TODO(vsm): handle non-nullable types
197 if ($instanceOfOrNull($obj, $type)) return $obj;
198 let actual = $realRuntimeType($obj);
199 if ($isGroundType($type)) $throwCastError(actual, $type);
200
201 if ($_ignoreTypeFailure(actual, $type)) return $obj;
202
203 $throwStrongModeError('Strong mode cast failure from ' +
204 $typeName(actual) + ' to ' + $typeName($type));
205 })()''');
206
207 asInt(obj) => JS('', '''(() => {
208 if ($obj == null) {
209 return null;
210 }
211 if (Math.floor($obj) != $obj) {
212 // Note: null will also be caught by this check
213 $throwCastError($realRuntimeType($obj), $int);
214 }
215 return $obj;
216 })()''');
217
218 arity(f) => JS('', '''(() => {
219 // TODO(jmesserly): need to parse optional params.
220 // In ES6, length is the number of required arguments.
221 return { min: $f.length, max: $f.length };
222 })()''');
223
224 equals(x, y) => JS('', '''(() => {
225 if ($x == null || $y == null) return $x == $y;
226 let eq = $x['=='];
227 return eq ? eq.call($x, $y) : $x === $y;
228 })()''');
229
230 /// Checks that `x` is not null or undefined. */
231 notNull(x) => JS('', '''(() => {
232 if ($x == null) $throwNullValueError();
233 return $x;
234 })()''');
235
236 ///
237 /// Creates a dart:collection LinkedHashMap.
238 ///
239 /// For a map with string keys an object literal can be used, for example
240 /// `map({'hi': 1, 'there': 2})`.
241 ///
242 /// Otherwise an array should be used, for example `map([1, 2, 3, 4])` will
243 /// create a map with keys [1, 3] and values [2, 4]. Each key-value pair
244 /// should be adjacent entries in the array.
245 ///
246 /// For a map with no keys the function can be called with no arguments, for
247 /// example `map()`.
248 ///
249 // TODO(jmesserly): this could be faster
250 // TODO(jmesserly): we can use default values `= dynamic` once #417 is fixed.
251 // TODO(jmesserly): move this to classes for consistentcy with list literals?
252 map(values, [K, V]) => JS('', '''(() => {
253 if ($K == null) $K = $dynamicR;
254 if ($V == null) $V = $dynamicR;
255 let map = ${getGenericClass(LinkedHashMap)}($K, $V).new();
256 if (Array.isArray($values)) {
257 for (let i = 0, end = $values.length - 1; i < end; i += 2) {
258 let key = $values[i];
259 let value = $values[i + 1];
260 map.set(key, value);
261 }
262 } else if (typeof $values === 'object') {
263 for (let key of $getOwnPropertyNames($values)) {
264 map.set(key, $values[key]);
265 }
266 }
267 return map;
268 })()''');
269
270 @JSExportName('assert')
271 assert_(condition) => JS('', '''(() => {
272 if (!$condition) $throwAssertionError();
273 })()''');
274
275 final _stack = JS('', 'new WeakMap()');
276 @JSExportName('throw')
277 throw_(obj) => JS('', '''(() => {
278 if ($obj != null && (typeof $obj == 'object' || typeof $obj == 'function')) {
279 // TODO(jmesserly): couldn't we store the most recent stack in a single
280 // variable? There should only be one active stack trace. That would
281 // allow it to work for things like strings and numbers.
282 $_stack.set($obj, new Error());
283 }
284 throw $obj;
285 })()''');
286
287 getError(exception) => JS('', '''(() => {
288 var stack = $_stack.get($exception);
289 return stack !== void 0 ? stack : $exception;
290 })()''');
291
292 // This is a utility function: it is only intended to be called from dev
293 // tools.
294 stackPrint(exception) => JS('', '''(() => {
295 var error = $getError($exception);
296 console.log(error.stack ? error.stack : 'No stack trace for: ' + error);
297 })()''');
298
299 stackTrace(exception) => JS('', '''(() => {
300 var error = $getError($exception);
301 return $getTraceFromException(error);
302 })()''');
303
304 ///
305 /// Implements a sequence of .? operations.
306 ///
307 /// Will call each successive callback, unless one returns null, which stops
308 /// the sequence.
309 ///
310 nullSafe(obj, @rest callbacks) => JS('', '''(() => {
311 if ($obj == null) return $obj;
312 for (const callback of $callbacks) {
313 $obj = callback($obj);
314 if ($obj == null) break;
315 }
316 return $obj;
317 })()''');
318
319 final _value = JS('', 'Symbol("_value")');
320 ///
321 /// Looks up a sequence of [keys] in [map], recursively, and
322 /// returns the result. If the value is not found, [valueFn] will be called to
323 /// add it. For example:
324 ///
325 /// let map = new Map();
326 /// putIfAbsent(map, [1, 2, 'hi ', 'there '], () => 'world');
327 ///
328 /// ... will create a Map with a structure like:
329 ///
330 /// { 1: { 2: { 'hi ': { 'there ': 'world' } } } }
331 ///
332 multiKeyPutIfAbsent(map, keys, valueFn) => JS('', '''(() => {
333 for (let k of $keys) {
334 let value = $map.get(k);
335 if (!value) {
336 // TODO(jmesserly): most of these maps are very small (e.g. 1 item),
337 // so it may be worth optimizing for that.
338 $map.set(k, value = new Map());
339 }
340 $map = value;
341 }
342 if ($map.has($_value)) return $map.get($_value);
343 let value = $valueFn();
344 $map.set($_value, value);
345 return value;
346 })()''');
347
348 /// The global constant table. */
349 final constants = JS('', 'new Map()');
350
351 ///
352 /// Canonicalize a constant object.
353 ///
354 /// Preconditions:
355 /// - `obj` is an objects or array, not a primitive.
356 /// - nested values of the object are themselves already canonicalized.
357 ///
358 @JSExportName('const')
359 const_(obj) => JS('', '''(() => {
360 let objectKey = [$realRuntimeType($obj)];
361 // TODO(jmesserly): there's no guarantee in JS that names/symbols are
362 // returned in the same order.
363 //
364 // We could probably get the same order if we're judicious about
365 // initializing fields in a consistent order across all const constructors.
366 // Alternatively we need a way to sort them to make consistent.
367 //
368 // Right now we use the (name,value) pairs in sequence, which prevents
369 // an object with incorrect field values being returned, but won't
370 // canonicalize correctly if key order is different.
371 for (let name of $getOwnNamesAndSymbols($obj)) {
372 objectKey.push(name);
373 objectKey.push($obj[name]);
374 }
375 return $multiKeyPutIfAbsent($constants, objectKey, () => $obj);
376 })()''');
377
378
379 // The following are helpers for Object methods when the receiver
380 // may be null or primitive. These should only be generated by
381 // the compiler.
382 hashCode(obj) => JS('', '''(() => {
383 if ($obj == null) {
384 return 0;
385 }
386 // TODO(vsm): What should we do for primitives and non-Dart objects?
387 switch (typeof $obj) {
388 case "number":
389 case "boolean":
390 return $obj & 0x1FFFFFFF;
391 case "string":
392 // TODO(vsm): Call the JSString hashCode?
393 return $obj.length;
394 }
395 return $obj.hashCode;
396 })()''');
397
398 toString(obj) => JS('', '''(() => {
399 if ($obj == null) {
400 return "null";
401 }
402 return $obj.toString();
403 })()''');
404
405 noSuchMethod(obj, invocation) => JS('', '''(() => {
406 if ($obj == null) {
407 $throwNoSuchMethod($obj, $invocation.memberName,
408 $invocation.positionalArguments, $invocation.namedArguments);
409 }
410 switch (typeof $obj) {
411 case "number":
412 case "boolean":
413 case "string":
414 $throwNoSuchMethod($obj, $invocation.memberName,
415 $invocation.positionalArguments, $invocation.namedArguments);
416 }
417 return $obj.noSuchMethod($invocation);
418 })()''');
419
420 final JsIterator = JS('', '''
421 class JsIterator {
422 constructor(dartIterator) {
423 this.dartIterator = dartIterator;
424 }
425 next() {
426 let i = this.dartIterator;
427 let done = !i.moveNext();
428 return { done: done, value: done ? void 0 : i.current };
429 }
430 }
431 ''');
OLDNEW
« no previous file with comments | « tool/input_sdk/private/generators.dart ('k') | tool/input_sdk/private/rtti.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698