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

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

Issue 1413683006: Move runtime js files down to lib/runtime/dart (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 1 month 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 | « lib/runtime/_generators.js ('k') | lib/runtime/_rtti.js » ('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 */
8 dart_library.library('dart_runtime/_operations', null, /* Imports */[
9 ], /* Lazy Imports */[
10 'dart/async',
11 'dart/collection',
12 'dart/core',
13 'dart/_js_helper',
14 'dart_runtime/_classes',
15 'dart_runtime/_errors',
16 'dart_runtime/_rtti',
17 'dart_runtime/_types'
18 ], function(exports, async, collection, core, _js_helper, classes, errors, rtti,
19 types) {
20 'use strict';
21
22 const getOwnNamesAndSymbols = dart_utils.getOwnNamesAndSymbols;
23 const throwError = dart_utils.throwError;
24
25 const getOwnPropertyNames = Object.getOwnPropertyNames;
26 const hasOwnProperty = Object.prototype.hasOwnProperty;
27
28 const slice = [].slice;
29
30 function _canonicalFieldName(obj, name, args, displayName) {
31 name = classes.canonicalMember(obj, name);
32 if (name) return name;
33 // TODO(jmesserly): in the future we might have types that "overlay" Dart
34 // methods while also exposing the full native API, e.g. dart:html vs
35 // dart:dom. To support that we'd need to fall back to the normal name
36 // if an extension method wasn't found.
37 errors.throwNoSuchMethod(obj, displayName, args);
38 }
39
40 function dload(obj, field) {
41 field = _canonicalFieldName(obj, field, [], field);
42 if (classes.hasMethod(obj, field)) {
43 return classes.bind(obj, field);
44 }
45 // TODO(vsm): Implement NSM robustly. An 'in' check breaks on certain
46 // types. hasOwnProperty doesn't chase the proto chain.
47 // Also, do we want an NSM on regular JS objects?
48 // See: https://github.com/dart-lang/dev_compiler/issues/169
49 let result = obj[field];
50
51 // TODO(vsm): Check this more robustly.
52 if (typeof result == "function" && !hasOwnProperty.call(obj, field)) {
53 // This appears to be a method tearoff. Bind this.
54 return result.bind(obj);
55 }
56 return result;
57 }
58 exports.dload = dload;
59
60 function dput(obj, field, value) {
61 field = _canonicalFieldName(obj, field, [value], field);
62 // TODO(vsm): Implement NSM and type checks.
63 // See: https://github.com/dart-lang/dev_compiler/issues/170
64 obj[field] = value;
65 return value;
66 }
67 exports.dput = dput;
68
69
70 /// Check that a function of a given type can be applied to
71 /// actuals.
72 function checkApply(type, actuals) {
73 if (actuals.length < type.args.length) return false;
74 let index = 0;
75 for(let i = 0; i < type.args.length; ++i) {
76 if (!instanceOfOrNull(actuals[i], type.args[i])) return false;
77 ++index;
78 }
79 if (actuals.length == type.args.length) return true;
80 let extras = actuals.length - type.args.length;
81 if (type.optionals.length > 0) {
82 if (extras > type.optionals.length) return false;
83 for(let i = 0, j=index; i < extras; ++i, ++j) {
84 if (!instanceOfOrNull(actuals[j], type.optionals[i])) return false;
85 }
86 return true;
87 }
88 // TODO(leafp): We can't tell when someone might be calling
89 // something expecting an optional argument with named arguments
90
91 if (extras != 1) return false;
92 // An empty named list means no named arguments
93 if (getOwnPropertyNames(type.named).length == 0) return false;
94 let opts = actuals[index];
95 let names = getOwnPropertyNames(opts);
96 // Type is something other than a map
97 if (names.length == 0) return false;
98 for (var name of names) {
99 if (!(hasOwnProperty.call(type.named, name))) {
100 return false;
101 }
102 if (!instanceOfOrNull(opts[name], type.named[name])) return false;
103 }
104 return true;
105 }
106
107 function throwNoSuchMethod(obj, name, args, opt_func) {
108 if (obj === void 0) obj = opt_func;
109 errors.throwNoSuchMethod(obj, name, args);
110 }
111
112 function checkAndCall(f, ftype, obj, args, name) {
113 if (!(f instanceof Function)) {
114 // We're not a function (and hence not a method either)
115 // Grab the `call` method if it's not a function.
116 if (f != null) {
117 ftype = classes.getMethodType(f, 'call');
118 f = f.call;
119 }
120 if (!(f instanceof Function)) {
121 throwNoSuchMethod(obj, name, args);
122 }
123 }
124 // If f is a function, but not a method (no method type)
125 // then it should have been a function valued field, so
126 // get the type from the function.
127 if (ftype === void 0) {
128 ftype = rtti.read(f);
129 }
130
131 if (!ftype) {
132 // TODO(leafp): Allow JS objects to go through?
133 // This includes the DOM.
134 return f.apply(obj, args);
135 }
136
137 if (checkApply(ftype, args)) {
138 return f.apply(obj, args);
139 }
140
141 // TODO(leafp): throw a type error (rather than NSM)
142 // if the arity matches but the types are wrong.
143 throwNoSuchMethod(obj, name, args, f);
144 }
145
146 function dcall(f/*, ...args*/) {
147 let args = slice.call(arguments, 1);
148 let ftype = rtti.read(f);
149 return checkAndCall(f, ftype, void 0, args, 'call');
150 }
151 exports.dcall = dcall;
152
153 /** Shared code for dsend, dindex, and dsetindex. */
154 function callMethod(obj, name, args, displayName) {
155 let symbol = _canonicalFieldName(obj, name, args, displayName);
156 let f = obj != null ? obj[symbol] : null;
157 let ftype = classes.getMethodType(obj, name);
158 return checkAndCall(f, ftype, obj, args, displayName);
159 }
160
161 function dsend(obj, method/*, ...args*/) {
162 return callMethod(obj, method, slice.call(arguments, 2), method);
163 }
164 exports.dsend = dsend;
165
166 function dindex(obj, index) {
167 return callMethod(obj, 'get', [index], '[]');
168 }
169 exports.dindex = dindex;
170
171 function dsetindex(obj, index, value) {
172 callMethod(obj, 'set', [index, value], '[]=');
173 return value;
174 }
175 exports.dsetindex = dsetindex;
176
177 function _ignoreTypeFailure(actual, type) {
178 // TODO(vsm): Remove this hack ...
179 // This is primarily due to the lack of generic methods,
180 // but we need to triage all the errors.
181 let isSubtype = types.isSubtype;
182 if (isSubtype(type, core.Iterable) && isSubtype(actual, core.Iterable) ||
183 isSubtype(type, async.Future) && isSubtype(actual, async.Future) ||
184 isSubtype(type, core.Map) && isSubtype(actual, core.Map) ||
185 isSubtype(type, core.Function) && isSubtype(actual, core.Function) ||
186 isSubtype(type, async.Stream) && isSubtype(actual, async.Stream) ||
187 isSubtype(type, async.StreamSubscription) &&
188 isSubtype(actual, async.StreamSubscription)) {
189 console.warn('Ignoring cast fail from ' + types.typeName(actual) +
190 ' to ' + types.typeName(type));
191 return true;
192 }
193 return false;
194 }
195
196 function strongInstanceOf(obj, type) {
197 let actual = rtti.realRuntimeType(obj);
198 return types.isSubtype(actual, type) || actual == types.jsobject;
199 }
200 exports.strongInstanceOf = strongInstanceOf;
201
202 function instanceOfOrNull(obj, type) {
203 if ((obj == null) || strongInstanceOf(obj, type)) return true;
204 return false;
205 }
206
207 function instanceOf(obj, type) {
208 if (strongInstanceOf(obj, type)) return true;
209 // TODO(#296): This is perhaps too eager to throw a StrongModeError?
210 // It will throw on <int>[] is List<String>.
211 // TODO(vsm): We can statically detect many cases where this
212 // check is unnecessary.
213 if (types.isGroundType(type)) return false;
214 let actual = rtti.realRuntimeType(obj);
215 dart_utils.throwStrongModeError('Strong mode is check failure: ' +
216 types.typeName(actual) + ' does not soundly subtype ' +
217 types.typeName(type));
218 }
219 exports.instanceOf = instanceOf;
220
221 function cast(obj, type) {
222 // TODO(#296): This is perhaps too eager to throw a StrongModeError?
223 // TODO(vsm): handle non-nullable types
224 if (instanceOfOrNull(obj, type)) return obj;
225 let actual = rtti.realRuntimeType(obj);
226 if (types.isGroundType(type)) errors.throwCastError(actual, type);
227
228 if (_ignoreTypeFailure(actual, type)) return obj;
229
230 dart_utils.throwStrongModeError('Strong mode cast failure from ' +
231 types.typeName(actual) + ' to ' + types.typeName(type));
232 }
233 exports.cast = cast;
234
235 function asInt(obj) {
236 if (Math.floor(obj) != obj) {
237 // Note: null will also be caught by this check
238 errors.throwCastError(rtti.realRuntimeType(obj), core.int);
239 }
240 return obj;
241 }
242 exports.asInt = asInt;
243
244 function arity(f) {
245 // TODO(jmesserly): need to parse optional params.
246 // In ES6, length is the number of required arguments.
247 return { min: f.length, max: f.length };
248 }
249 exports.arity = arity;
250
251 function equals(x, y) {
252 if (x == null || y == null) return x == y;
253 let eq = x['=='];
254 return eq ? eq.call(x, y) : x === y;
255 }
256 exports.equals = equals;
257
258 /** Checks that `x` is not null or undefined. */
259 function notNull(x) {
260 if (x == null) errors.throwNullValueError();
261 return x;
262 }
263 exports.notNull = notNull;
264
265 /**
266 * Creates a dart:collection LinkedHashMap.
267 *
268 * For a map with string keys an object literal can be used, for example
269 * `map({'hi': 1, 'there': 2})`.
270 *
271 * Otherwise an array should be used, for example `map([1, 2, 3, 4])` will
272 * create a map with keys [1, 3] and values [2, 4]. Each key-value pair
273 * should be adjacent entries in the array.
274 *
275 * For a map with no keys the function can be called with no arguments, for
276 * example `map()`.
277 */
278 // TODO(jmesserly): this could be faster
279 function map(values) {
280 let map = collection.LinkedHashMap.new();
281 if (Array.isArray(values)) {
282 for (let i = 0, end = values.length - 1; i < end; i += 2) {
283 let key = values[i];
284 let value = values[i + 1];
285 map.set(key, value);
286 }
287 } else if (typeof values === 'object') {
288 for (let key of getOwnPropertyNames(values)) {
289 map.set(key, values[key]);
290 }
291 }
292 return map;
293 }
294 exports.map = map;
295
296 function assert(condition) {
297 if (!condition) errors.throwAssertionError();
298 }
299 exports.assert = assert;
300
301 let _stack = new WeakMap();
302 function throw_(obj) {
303 if (obj != null && (typeof obj == 'object' || typeof obj == 'function')) {
304 // TODO(jmesserly): couldn't we store the most recent stack in a single
305 // variable? There should only be one active stack trace. That would
306 // allow it to work for things like strings and numbers.
307 _stack.set(obj, new Error());
308 }
309 throw obj;
310 }
311 exports.throw = throw_;
312
313 function getError(exception) {
314 var stack = _stack.get(exception);
315 return stack !== void 0 ? stack : exception;
316 }
317
318 // This is a utility function: it is only intended to be called from dev
319 // tools.
320 function stackPrint(exception) {
321 var error = getError(exception);
322 console.log(error.stack ? error.stack : 'No stack trace for: ' + error);
323 }
324 exports.stackPrint = stackPrint;
325
326 function stackTrace(exception) {
327 var error = getError(exception);
328 return _js_helper.getTraceFromException(error);
329 }
330 exports.stackTrace = stackTrace;
331
332 /**
333 * Implements a sequence of .? operations.
334 *
335 * Will call each successive callback, unless one returns null, which stops
336 * the sequence.
337 */
338 function nullSafe(obj /*, ...callbacks*/) {
339 let callbacks = slice.call(arguments, 1);
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
« no previous file with comments | « lib/runtime/_generators.js ('k') | lib/runtime/_rtti.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698