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

Side by Side Diff: test/generated_sdk/lib/_internal/compiler/js_lib/js_rti.dart

Issue 1162723007: remove generated_sdk from checked in code (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 6 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) 2013, 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 /**
6 * This part contains helpers for supporting runtime type information.
7 *
8 * The helper use a mixture of Dart and JavaScript objects. To indicate which is
9 * used where we adopt the scheme of using explicit type annotation for Dart
10 * objects and 'var' or omitted return type for JavaScript objects.
11 *
12 * Since bool, int, and String values are represented by the same JavaScript
13 * primitives, type annotations are used for these types in all cases.
14 *
15 * Several methods use a common JavaScript encoding of runtime type information.
16 * This encoding is referred to as the type representation which is one of
17 * these:
18 * 1) a JavaScript constructor for a class C: the represented type is the raw
19 * type C.
20 * 2) a Dart object: this is the interceptor instance for a native type.
21 * 3) a JavaScript object: this represents a class for which there is no
22 * JavaScript constructor, because it is only used in type arguments or it
23 * is native. The represented type is the raw type of this class.
24 * 4) a JavaScript array: the first entry is of type 1, 2 or 3 and contains the
25 * subtyping flags and the substitution of the type and the rest of the
26 * array are the type arguments.
27 * 5) `null`: the dynamic type.
28 *
29 *
30 * To check subtype relations between generic classes we use a JavaScript
31 * expression that describes the necessary substitution for type arguments.
32 * Such a substitution expresssion can be:
33 * 1) `null`, if no substituted check is necessary, because the
34 * type variables are the same or there are no type variables in the class
35 * that is checked for.
36 * 2) A list expression describing the type arguments to be used in the
37 * subtype check, if the type arguments to be used in the check do not
38 * depend on the type arguments of the object.
39 * 3) A function mapping the type variables of the object to be checked to
40 * a list expression.
41 */
42
43 part of _js_helper;
44
45 Type createRuntimeType(String name) => new TypeImpl(name);
46
47 class TypeImpl implements Type {
48 final String _typeName;
49 String _unmangledName;
50
51 TypeImpl(this._typeName);
52
53 String toString() {
54 if (_unmangledName != null) return _unmangledName;
55 String unmangledName = unmangleAllIdentifiersIfPreservedAnyways(_typeName);
56 return _unmangledName = unmangledName;
57 }
58
59 // TODO(ahe): This is a poor hashCode as it collides with its name.
60 int get hashCode => _typeName.hashCode;
61
62 bool operator ==(other) {
63 return (other is TypeImpl) && _typeName == other._typeName;
64 }
65 }
66
67 /**
68 * Represents a type variable.
69 *
70 * This class holds the information needed when reflecting on generic classes
71 * and their members.
72 */
73 class TypeVariable {
74 final Type owner;
75 final String name;
76 final int bound;
77
78 const TypeVariable(this.owner, this.name, this.bound);
79 }
80
81 getMangledTypeName(TypeImpl type) => type._typeName;
82
83 /**
84 * Sets the runtime type information on [target]. [typeInfo] is a type
85 * representation of type 4 or 5, that is, either a JavaScript array or
86 * `null`.
87 */
88 Object setRuntimeTypeInfo(Object target, var typeInfo) {
89 assert(typeInfo == null || isJsArray(typeInfo));
90 // We have to check for null because factories may return null.
91 if (target != null) JS('var', r'#.$builtinTypeInfo = #', target, typeInfo);
92 return target;
93 }
94
95 /**
96 * Returns the runtime type information of [target]. The returned value is a
97 * list of type representations for the type arguments.
98 */
99 getRuntimeTypeInfo(Object target) {
100 if (target == null) return null;
101 return JS('var', r'#.$builtinTypeInfo', target);
102 }
103
104 /**
105 * Returns the type arguments of [target] as an instance of [substitutionName].
106 */
107 getRuntimeTypeArguments(target, substitutionName) {
108 var substitution =
109 getField(target, '${JS_OPERATOR_AS_PREFIX()}$substitutionName');
110 return substitute(substitution, getRuntimeTypeInfo(target));
111 }
112
113 /**
114 * Returns the [index]th type argument of [target] as an instance of
115 * [substitutionName].
116 */
117 @NoThrows() @NoSideEffects() @NoInline()
118 getRuntimeTypeArgument(Object target, String substitutionName, int index) {
119 var arguments = getRuntimeTypeArguments(target, substitutionName);
120 return arguments == null ? null : getIndex(arguments, index);
121 }
122
123 @NoThrows() @NoSideEffects() @NoInline()
124 getTypeArgumentByIndex(Object target, int index) {
125 var rti = getRuntimeTypeInfo(target);
126 return rti == null ? null : getIndex(rti, index);
127 }
128
129 void copyTypeArguments(Object source, Object target) {
130 JS('var', r'#.$builtinTypeInfo = #.$builtinTypeInfo', target, source);
131 }
132
133 /**
134 * Retrieves the class name from type information stored on the constructor
135 * of [object].
136 */
137 String getClassName(var object) {
138 return JS('String', r'#.constructor.builtin$cls', getInterceptor(object));
139 }
140
141 /**
142 * Creates the string representation for the type representation [runtimeType]
143 * of type 4, the JavaScript array, where the first element represents the class
144 * and the remaining elements represent the type arguments.
145 */
146 String getRuntimeTypeAsString(var runtimeType, {String onTypeVariable(int i)}) {
147 assert(isJsArray(runtimeType));
148 String className = getConstructorName(getIndex(runtimeType, 0));
149 return '$className'
150 '${joinArguments(runtimeType, 1, onTypeVariable: onTypeVariable)}';
151 }
152
153 /**
154 * Retrieves the class name from type information stored on the constructor
155 * [type].
156 */
157 String getConstructorName(var type) => JS('String', r'#.builtin$cls', type);
158
159 /**
160 * Returns a human-readable representation of the type representation [type].
161 */
162 String runtimeTypeToString(var type, {String onTypeVariable(int i)}) {
163 if (type == null) {
164 return 'dynamic';
165 } else if (isJsArray(type)) {
166 // A list representing a type with arguments.
167 return getRuntimeTypeAsString(type, onTypeVariable: onTypeVariable);
168 } else if (isJsFunction(type)) {
169 // A reference to the constructor.
170 return getConstructorName(type);
171 } else if (type is int) {
172 if (onTypeVariable == null) {
173 return type.toString();
174 } else {
175 return onTypeVariable(type);
176 }
177 } else {
178 // TODO(ahe): Handle function types, and be sure to always return a string.
179 return null;
180 }
181 }
182
183 /**
184 * Creates a comma-separated string of human-readable representations of the
185 * type representations in the JavaScript array [types] starting at index
186 * [startIndex].
187 */
188 String joinArguments(var types, int startIndex,
189 {String onTypeVariable(int i)}) {
190 if (types == null) return '';
191 assert(isJsArray(types));
192 bool firstArgument = true;
193 bool allDynamic = true;
194 StringBuffer buffer = new StringBuffer();
195 for (int index = startIndex; index < getLength(types); index++) {
196 if (firstArgument) {
197 firstArgument = false;
198 } else {
199 buffer.write(', ');
200 }
201 var argument = getIndex(types, index);
202 if (argument != null) {
203 allDynamic = false;
204 }
205 buffer.write(runtimeTypeToString(argument, onTypeVariable: onTypeVariable));
206 }
207 return allDynamic ? '' : '<$buffer>';
208 }
209
210 /**
211 * Returns a human-readable representation of the type of [object].
212 *
213 * In minified mode does *not* use unminified identifiers (even when present).
214 */
215 String getRuntimeTypeString(var object) {
216 String className = getClassName(object);
217 if (object == null) return className;
218 var typeInfo = JS('var', r'#.$builtinTypeInfo', object);
219 return "$className${joinArguments(typeInfo, 0)}";
220 }
221
222 Type getRuntimeType(var object) {
223 String type = getRuntimeTypeString(object);
224 return new TypeImpl(type);
225 }
226
227 /**
228 * Applies the [substitution] on the [arguments].
229 *
230 * See the comment in the beginning of this file for a description of the
231 * possible values for [substitution].
232 */
233 substitute(var substitution, var arguments) {
234 assert(substitution == null ||
235 isJsFunction(substitution));
236 assert(arguments == null || isJsArray(arguments));
237 if (isJsFunction(substitution)) {
238 substitution = invoke(substitution, arguments);
239 if (isJsArray(substitution)) {
240 arguments = substitution;
241 } else if (isJsFunction(substitution)) {
242 // TODO(johnniwinther): Check if this is still needed.
243 arguments = invoke(substitution, arguments);
244 }
245 }
246 return arguments;
247 }
248
249 /**
250 * Perform a type check with arguments on the Dart object [object].
251 *
252 * Parameters:
253 * - [isField]: the name of the flag/function to check if the object
254 * is of the correct class.
255 * - [checks]: the (JavaScript) list of type representations for the
256 * arguments to check against.
257 * - [asField]: the name of the function that transforms the type
258 * arguments of [objects] to an instance of the class that we check
259 * against.
260 */
261 bool checkSubtype(Object object, String isField, List checks, String asField) {
262 if (object == null) return false;
263 var arguments = getRuntimeTypeInfo(object);
264 // Interceptor is needed for JSArray and native classes.
265 // TODO(sra): It could be a more specialized interceptor since [object] is not
266 // `null` or a primitive.
267 // TODO(9586): Move type info for static functions onto an interceptor.
268 var interceptor = getInterceptor(object);
269 var isSubclass = getField(interceptor, isField);
270 // When we read the field and it is not there, [isSubclass] will be `null`.
271 if (isSubclass == null) return false;
272 // Should the asField function be passed the receiver?
273 var substitution = getField(interceptor, asField);
274 return checkArguments(substitution, arguments, checks);
275 }
276
277 /// Returns the field's type name.
278 ///
279 /// In minified mode, uses the unminified names if available.
280 String computeTypeName(String isField, List arguments) {
281 // Shorten the field name to the class name and append the textual
282 // representation of the type arguments.
283 int prefixLength = JS_OPERATOR_IS_PREFIX().length;
284 return Primitives.formatType(isField.substring(prefixLength, isField.length),
285 arguments);
286 }
287
288 Object subtypeCast(Object object, String isField, List checks, String asField) {
289 if (object != null && !checkSubtype(object, isField, checks, asField)) {
290 String actualType = Primitives.objectTypeName(object);
291 String typeName = computeTypeName(isField, checks);
292 // TODO(johnniwinther): Move type lookup to [CastErrorImplementation] to
293 // align with [TypeErrorImplementation].
294 throw new CastErrorImplementation(actualType, typeName);
295 }
296 return object;
297 }
298
299 Object assertSubtype(Object object, String isField, List checks,
300 String asField) {
301 if (object != null && !checkSubtype(object, isField, checks, asField)) {
302 String typeName = computeTypeName(isField, checks);
303 throw new TypeErrorImplementation(object, typeName);
304 }
305 return object;
306 }
307
308 /// Checks that the type represented by [subtype] is a subtype of [supertype].
309 /// If not a type error with [message] is thrown.
310 assertIsSubtype(var subtype, var supertype, String message) {
311 if (!isSubtype(subtype, supertype)) {
312 throwTypeError(message);
313 }
314 }
315
316 throwTypeError(message) {
317 throw new TypeErrorImplementation.fromMessage(message);
318 }
319
320 /**
321 * Check that the types in the list [arguments] are subtypes of the types in
322 * list [checks] (at the respective positions), possibly applying [substitution]
323 * to the arguments before the check.
324 *
325 * See the comment in the beginning of this file for a description of the
326 * possible values for [substitution].
327 */
328 bool checkArguments(var substitution, var arguments, var checks) {
329 return areSubtypes(substitute(substitution, arguments), checks);
330 }
331
332 /**
333 * Checks whether the types of [s] are all subtypes of the types of [t].
334 *
335 * [s] and [t] are either `null` or JavaScript arrays of type representations,
336 * A `null` argument is interpreted as the arguments of a raw type, that is a
337 * list of `dynamic`. If [s] and [t] are JavaScript arrays they must be of the
338 * same length.
339 *
340 * See the comment in the beginning of this file for a description of type
341 * representations.
342 */
343 bool areSubtypes(var s, var t) {
344 // `null` means a raw type.
345 if (s == null || t == null) return true;
346
347 assert(isJsArray(s));
348 assert(isJsArray(t));
349 assert(getLength(s) == getLength(t));
350
351 int len = getLength(s);
352 for (int i = 0; i < len; i++) {
353 if (!isSubtype(getIndex(s, i), getIndex(t, i))) {
354 return false;
355 }
356 }
357 return true;
358 }
359
360 /**
361 * Computes the signature by applying the type arguments of [context] as an
362 * instance of [contextName] to the signature function [signature].
363 */
364 computeSignature(var signature, var context, var contextName) {
365 var typeArguments = getRuntimeTypeArguments(context, contextName);
366 return invokeOn(signature, context, typeArguments);
367 }
368
369 /**
370 * Returns `true` if the runtime type representation [type] is a supertype of
371 * [Null].
372 */
373 bool isSupertypeOfNull(var type) {
374 // `null` means `dynamic`.
375 return type == null || getConstructorName(type) == JS_OBJECT_CLASS_NAME()
376 || getConstructorName(type) == JS_NULL_CLASS_NAME();
377 }
378
379 /**
380 * Tests whether the Dart object [o] is a subtype of the runtime type
381 * representation [t].
382 *
383 * See the comment in the beginning of this file for a description of type
384 * representations.
385 */
386 bool checkSubtypeOfRuntimeType(o, t) {
387 if (o == null) return isSupertypeOfNull(t);
388 if (t == null) return true;
389 // Get the runtime type information from the object here, because we may
390 // overwrite o with the interceptor below.
391 var rti = getRuntimeTypeInfo(o);
392 o = getInterceptor(o);
393 var type = JS('', '#.constructor', o);
394 if (rti != null) {
395 // If the type has type variables (that is, `rti != null`), make a copy of
396 // the type arguments and insert [o] in the first position to create a
397 // compound type representation.
398 rti = JS('JSExtendableArray', '#.slice()', rti); // Make a copy.
399 JS('', '#.splice(0, 0, #)', rti, type); // Insert type at position 0.
400 type = rti;
401 } else if (hasField(t, '${JS_FUNCTION_TYPE_TAG()}')) {
402 // Functions are treated specially and have their type information stored
403 // directly in the instance.
404 var signatureName =
405 '${JS_OPERATOR_IS_PREFIX()}_${getField(t, JS_FUNCTION_TYPE_TAG())}';
406 if (hasField(o, signatureName)) return true;
407 var targetSignatureFunction = getField(o, '${JS_SIGNATURE_NAME()}');
408 if (targetSignatureFunction == null) return false;
409 type = invokeOn(targetSignatureFunction, o, null);
410 return isFunctionSubtype(type, t);
411 }
412 return isSubtype(type, t);
413 }
414
415 Object subtypeOfRuntimeTypeCast(Object object, var type) {
416 if (object != null && !checkSubtypeOfRuntimeType(object, type)) {
417 String actualType = Primitives.objectTypeName(object);
418 throw new CastErrorImplementation(actualType, runtimeTypeToString(type));
419 }
420 return object;
421 }
422
423 Object assertSubtypeOfRuntimeType(Object object, var type) {
424 if (object != null && !checkSubtypeOfRuntimeType(object, type)) {
425 throw new TypeErrorImplementation(object, runtimeTypeToString(type));
426 }
427 return object;
428 }
429
430 /**
431 * Extracts the type arguments from a type representation. The result is a
432 * JavaScript array or `null`.
433 */
434 getArguments(var type) {
435 return isJsArray(type) ? JS('var', r'#.slice(1)', type) : null;
436 }
437
438 /**
439 * Checks whether the type represented by the type representation [s] is a
440 * subtype of the type represented by the type representation [t].
441 *
442 * See the comment in the beginning of this file for a description of type
443 * representations.
444 *
445 * The arguments [s] and [t] must be types, usually represented by the
446 * constructor of the class, or an array (for generic types).
447 */
448 bool isSubtype(var s, var t) {
449 // Subtyping is reflexive.
450 if (isIdentical(s, t)) return true;
451 // If either type is dynamic, [s] is a subtype of [t].
452 if (s == null || t == null) return true;
453 if (hasField(t, '${JS_FUNCTION_TYPE_TAG()}')) {
454 return isFunctionSubtype(s, t);
455 }
456 // Check function types against the Function class.
457 if (hasField(s, '${JS_FUNCTION_TYPE_TAG()}')) {
458 return getConstructorName(t) == JS_FUNCTION_CLASS_NAME();
459 }
460
461 // Get the object describing the class and check for the subtyping flag
462 // constructed from the type of [t].
463 var typeOfS = isJsArray(s) ? getIndex(s, 0) : s;
464 var typeOfT = isJsArray(t) ? getIndex(t, 0) : t;
465 // Check for a subtyping flag.
466 var name = runtimeTypeToString(typeOfT);
467 // Get the necessary substitution of the type arguments, if there is one.
468 var substitution;
469 if (isNotIdentical(typeOfT, typeOfS)) {
470 var test = '${JS_OPERATOR_IS_PREFIX()}${name}';
471 var typeOfSPrototype = JS('', '#.prototype', typeOfS);
472 if (hasNoField(typeOfSPrototype, test)) return false;
473 var field = '${JS_OPERATOR_AS_PREFIX()}${runtimeTypeToString(typeOfT)}';
474 substitution = getField(typeOfSPrototype, field);
475 }
476 // The class of [s] is a subclass of the class of [t]. If [s] has no type
477 // arguments and no substitution, it is used as raw type. If [t] has no
478 // type arguments, it used as a raw type. In both cases, [s] is a subtype
479 // of [t].
480 if ((!isJsArray(s) && substitution == null) || !isJsArray(t)) {
481 return true;
482 }
483 // Recursively check the type arguments.
484 return checkArguments(substitution, getArguments(s), getArguments(t));
485 }
486
487 bool isAssignable(var s, var t) {
488 return isSubtype(s, t) || isSubtype(t, s);
489 }
490
491 /**
492 * If [allowShorter] is `true`, [t] is allowed to be shorter than [s].
493 */
494 bool areAssignable(List s, List t, bool allowShorter) {
495 // Both lists are empty and thus equal.
496 if (t ==null && s == null) return true;
497 // [t] is empty (and [s] is not) => only OK if [allowShorter].
498 if (t == null) return allowShorter;
499 // [s] is empty (and [t] is not) => [s] is not longer or equal to [t].
500 if (s == null) return false;
501
502 assert(isJsArray(s));
503 assert(isJsArray(t));
504
505 int sLength = getLength(s);
506 int tLength = getLength(t);
507 if (allowShorter) {
508 if (sLength < tLength) return false;
509 } else {
510 if (sLength != tLength) return false;
511 }
512
513 for (int i = 0; i < tLength; i++) {
514 if (!isAssignable(getIndex(s, i), getIndex(t, i))) {
515 return false;
516 }
517 }
518 return true;
519 }
520
521 bool areAssignableMaps(var s, var t) {
522 if (t == null) return true;
523 if (s == null) return false;
524
525 assert(isJsObject(s));
526 assert(isJsObject(t));
527
528 List names =
529 JSArray.markFixedList(JS('', 'Object.getOwnPropertyNames(#)', t));
530 for (int i = 0; i < names.length; i++) {
531 var name = names[i];
532 if (JS('bool', '!Object.hasOwnProperty.call(#, #)', s, name)) {
533 return false;
534 }
535 var tType = JS('', '#[#]', t, name);
536 var sType = JS('', '#[#]', s, name);
537 if (!isAssignable(tType, sType)) return false;
538 }
539 return true;
540 }
541
542 bool isFunctionSubtype(var s, var t) {
543 assert(hasField(t, '${JS_FUNCTION_TYPE_TAG()}'));
544 if (hasNoField(s, '${JS_FUNCTION_TYPE_TAG()}')) return false;
545 if (hasField(s, '${JS_FUNCTION_TYPE_VOID_RETURN_TAG()}')) {
546 if (hasNoField(t, '${JS_FUNCTION_TYPE_VOID_RETURN_TAG()}') &&
547 hasField(t, '${JS_FUNCTION_TYPE_RETURN_TYPE_TAG()}')) {
548 return false;
549 }
550 } else if (hasNoField(t, '${JS_FUNCTION_TYPE_VOID_RETURN_TAG()}')) {
551 var sReturnType = getField(s, '${JS_FUNCTION_TYPE_RETURN_TYPE_TAG()}');
552 var tReturnType = getField(t, '${JS_FUNCTION_TYPE_RETURN_TYPE_TAG()}');
553 if (!isAssignable(sReturnType, tReturnType)) return false;
554 }
555 var sParameterTypes =
556 getField(s, '${JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG()}');
557 var tParameterTypes =
558 getField(t, '${JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG()}');
559
560 var sOptionalParameterTypes =
561 getField(s, '${JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG()}');
562 var tOptionalParameterTypes =
563 getField(t, '${JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG()}');
564
565 int sParametersLen = sParameterTypes != null ? getLength(sParameterTypes) : 0;
566 int tParametersLen = tParameterTypes != null ? getLength(tParameterTypes) : 0;
567
568 int sOptionalParametersLen =
569 sOptionalParameterTypes != null ? getLength(sOptionalParameterTypes) : 0;
570 int tOptionalParametersLen =
571 tOptionalParameterTypes != null ? getLength(tOptionalParameterTypes) : 0;
572
573 if (sParametersLen > tParametersLen) {
574 // Too many required parameters in [s].
575 return false;
576 }
577 if (sParametersLen + sOptionalParametersLen <
578 tParametersLen + tOptionalParametersLen) {
579 // Too few required and optional parameters in [s].
580 return false;
581 }
582 if (sParametersLen == tParametersLen) {
583 // Simple case: Same number of required parameters.
584 if (!areAssignable(sParameterTypes, tParameterTypes, false)) return false;
585 if (!areAssignable(sOptionalParameterTypes,
586 tOptionalParameterTypes, true)) {
587 return false;
588 }
589 } else {
590 // Complex case: Optional parameters of [s] for required parameters of [t].
591 int pos = 0;
592 // Check all required parameters of [s].
593 for (; pos < sParametersLen; pos++) {
594 if (!isAssignable(getIndex(sParameterTypes, pos),
595 getIndex(tParameterTypes, pos))) {
596 return false;
597 }
598 }
599 int sPos = 0;
600 int tPos = pos;
601 // Check the remaining parameters of [t] with the first optional parameters
602 // of [s].
603 for (; tPos < tParametersLen ; sPos++, tPos++) {
604 if (!isAssignable(getIndex(sOptionalParameterTypes, sPos),
605 getIndex(tParameterTypes, tPos))) {
606 return false;
607 }
608 }
609 tPos = 0;
610 // Check the optional parameters of [t] with the remaining optional
611 // parameters of [s]:
612 for (; tPos < tOptionalParametersLen ; sPos++, tPos++) {
613 if (!isAssignable(getIndex(sOptionalParameterTypes, sPos),
614 getIndex(tOptionalParameterTypes, tPos))) {
615 return false;
616 }
617 }
618 }
619
620 var sNamedParameters =
621 getField(s, '${JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG()}');
622 var tNamedParameters =
623 getField(t, '${JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG()}');
624 return areAssignableMaps(sNamedParameters, tNamedParameters);
625 }
626
627 /**
628 * Calls the JavaScript [function] with the [arguments] with the global scope
629 * as the `this` context.
630 */
631 invoke(var function, var arguments) => invokeOn(function, null, arguments);
632
633 /**
634 * Calls the JavaScript [function] with the [arguments] with [receiver] as the
635 * `this` context.
636 */
637 Object invokeOn(function, receiver, arguments) {
638 assert(isJsFunction(function));
639 assert(arguments == null || isJsArray(arguments));
640 return JS('var', r'#.apply(#, #)', function, receiver, arguments);
641 }
642
643 /// Calls the property [name] on the JavaScript [object].
644 call(var object, String name) => JS('var', r'#[#]()', object, name);
645
646 /// Returns the property [name] of the JavaScript object [object].
647 getField(var object, String name) => JS('var', r'#[#]', object, name);
648
649 /// Returns the property [index] of the JavaScript array [array].
650 getIndex(var array, int index) {
651 assert(isJsArray(array));
652 return JS('var', r'#[#]', array, index);
653 }
654
655 /// Returns the length of the JavaScript array [array].
656 int getLength(var array) {
657 assert(isJsArray(array));
658 return JS('int', r'#.length', array);
659 }
660
661 /// Returns whether [value] is a JavaScript array.
662 bool isJsArray(var value) {
663 return value is JSArray;
664 }
665
666 hasField(var object, var name) => JS('bool', r'# in #', name, object);
667
668 hasNoField(var object, var name) => !hasField(object, name);
669
670 /// Returns `true` if [o] is a JavaScript function.
671 bool isJsFunction(var o) => JS('bool', r'typeof # == "function"', o);
672
673 /// Returns `true` if [o] is a JavaScript object.
674 bool isJsObject(var o) => JS('bool', r"typeof # == 'object'", o);
675
676 /**
677 * Returns `true` if the JavaScript values [s] and [t] are identical. We use
678 * this helper instead of [identical] because `identical` needs to merge
679 * `null` and `undefined` (which we can avoid).
680 */
681 bool isIdentical(var s, var t) => JS('bool', '# === #', s, t);
682
683 /**
684 * Returns `true` if the JavaScript values [s] and [t] are not identical. We use
685 * this helper instead of [identical] because `identical` needs to merge
686 * `null` and `undefined` (which we can avoid).
687 */
688 bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698