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

Side by Side Diff: lib/runtime/dart/_operations.js

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

Powered by Google App Engine
This is Rietveld 408576698