1// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// Handle id counters.
29var next_handle_ = 0;
30var next_transient_handle_ = -1;
31
32// Mirror cache.
33var mirror_cache_ = [];
34
35
36/**
37 * Clear the mirror handle cache.
38 */
39function ClearMirrorCache() {
40  next_handle_ = 0;
41  mirror_cache_ = [];
42}
43
44
45/**
46 * Returns the mirror for a specified value or object.
47 *
48 * @param {value or Object} value the value or object to retreive the mirror for
49 * @param {boolean} transient indicate whether this object is transient and
50 *    should not be added to the mirror cache. The default is not transient.
51 * @returns {Mirror} the mirror reflects the passed value or object
52 */
53function MakeMirror(value, opt_transient) {
54  var mirror;
55
56  // Look for non transient mirrors in the mirror cache.
57  if (!opt_transient) {
58    for (id in mirror_cache_) {
59      mirror = mirror_cache_[id];
60      if (mirror.value() === value) {
61        return mirror;
62      }
63      // Special check for NaN as NaN == NaN is false.
64      if (mirror.isNumber() && isNaN(mirror.value()) &&
65          typeof value == 'number' && isNaN(value)) {
66        return mirror;
67      }
68    }
69  }
70
71  if (IS_UNDEFINED(value)) {
72    mirror = new UndefinedMirror();
73  } else if (IS_NULL(value)) {
74    mirror = new NullMirror();
75  } else if (IS_BOOLEAN(value)) {
76    mirror = new BooleanMirror(value);
77  } else if (IS_NUMBER(value)) {
78    mirror = new NumberMirror(value);
79  } else if (IS_STRING(value)) {
80    mirror = new StringMirror(value);
81  } else if (IS_ARRAY(value)) {
82    mirror = new ArrayMirror(value);
83  } else if (IS_DATE(value)) {
84    mirror = new DateMirror(value);
85  } else if (IS_FUNCTION(value)) {
86    mirror = new FunctionMirror(value);
87  } else if (IS_REGEXP(value)) {
88    mirror = new RegExpMirror(value);
89  } else if (IS_ERROR(value)) {
90    mirror = new ErrorMirror(value);
91  } else if (IS_SCRIPT(value)) {
92    mirror = new ScriptMirror(value);
93  } else {
94    mirror = new ObjectMirror(value, OBJECT_TYPE, opt_transient);
95  }
96
97  mirror_cache_[mirror.handle()] = mirror;
98  return mirror;
99}
100
101
102/**
103 * Returns the mirror for a specified mirror handle.
104 *
105 * @param {number} handle the handle to find the mirror for
106 * @returns {Mirror or undefiend} the mirror with the requested handle or
107 *     undefined if no mirror with the requested handle was found
108 */
109function LookupMirror(handle) {
110  return mirror_cache_[handle];
111}
112
113
114/**
115 * Returns the mirror for the undefined value.
116 *
117 * @returns {Mirror} the mirror reflects the undefined value
118 */
119function GetUndefinedMirror() {
120  return MakeMirror(void 0);
121}
122
123
124/**
125 * Inherit the prototype methods from one constructor into another.
126 *
127 * The Function.prototype.inherits from lang.js rewritten as a standalone
128 * function (not on Function.prototype). NOTE: If this file is to be loaded
129 * during bootstrapping this function needs to be revritten using some native
130 * functions as prototype setup using normal JavaScript does not work as
131 * expected during bootstrapping (see mirror.js in r114903).
132 *
133 * @param {function} ctor Constructor function which needs to inherit the
134 *     prototype
135 * @param {function} superCtor Constructor function to inherit prototype from
136 */
137function inherits(ctor, superCtor) {
138  var tempCtor = function(){};
139  tempCtor.prototype = superCtor.prototype;
140  ctor.super_ = superCtor.prototype;
141  ctor.prototype = new tempCtor();
142  ctor.prototype.constructor = ctor;
143}
144
145
146// Type names of the different mirrors.
147var UNDEFINED_TYPE = 'undefined';
148var NULL_TYPE = 'null';
149var BOOLEAN_TYPE = 'boolean';
150var NUMBER_TYPE = 'number';
151var STRING_TYPE = 'string';
152var OBJECT_TYPE = 'object';
153var FUNCTION_TYPE = 'function';
154var REGEXP_TYPE = 'regexp';
155var ERROR_TYPE = 'error';
156var PROPERTY_TYPE = 'property';
157var FRAME_TYPE = 'frame';
158var SCRIPT_TYPE = 'script';
159var CONTEXT_TYPE = 'context';
160var SCOPE_TYPE = 'scope';
161
162// Maximum length when sending strings through the JSON protocol.
163var kMaxProtocolStringLength = 80;
164
165// Different kind of properties.
166var PropertyKind = {};
167PropertyKind.Named   = 1;
168PropertyKind.Indexed = 2;
169
170
171// A copy of the PropertyType enum from global.h
172var PropertyType = {};
173PropertyType.Normal                  = 0;
174PropertyType.Field                   = 1;
175PropertyType.ConstantFunction        = 2;
176PropertyType.Callbacks               = 3;
177PropertyType.Handler                 = 4;
178PropertyType.Interceptor             = 5;
179PropertyType.MapTransition           = 6;
180PropertyType.ExternalArrayTransition = 7;
181PropertyType.ConstantTransition      = 8;
182PropertyType.NullDescriptor          = 9;
183
184
185// Different attributes for a property.
186var PropertyAttribute = {};
187PropertyAttribute.None       = NONE;
188PropertyAttribute.ReadOnly   = READ_ONLY;
189PropertyAttribute.DontEnum   = DONT_ENUM;
190PropertyAttribute.DontDelete = DONT_DELETE;
191
192
193// A copy of the scope types from runtime.cc.
194var ScopeType = { Global: 0,
195                  Local: 1,
196                  With: 2,
197                  Closure: 3,
198                  Catch: 4,
199                  Block: 5 };
200
201
202// Mirror hierarchy:
203//   - Mirror
204//     - ValueMirror
205//       - UndefinedMirror
206//       - NullMirror
207//       - NumberMirror
208//       - StringMirror
209//       - ObjectMirror
210//         - FunctionMirror
211//           - UnresolvedFunctionMirror
212//         - ArrayMirror
213//         - DateMirror
214//         - RegExpMirror
215//         - ErrorMirror
216//     - PropertyMirror
217//     - FrameMirror
218//     - ScriptMirror
219
220
221/**
222 * Base class for all mirror objects.
223 * @param {string} type The type of the mirror
224 * @constructor
225 */
226function Mirror(type) {
227  this.type_ = type;
228}
229
230
231Mirror.prototype.type = function() {
232  return this.type_;
233};
234
235
236/**
237 * Check whether the mirror reflects a value.
238 * @returns {boolean} True if the mirror reflects a value.
239 */
240Mirror.prototype.isValue = function() {
241  return this instanceof ValueMirror;
242};
243
244
245/**
246 * Check whether the mirror reflects the undefined value.
247 * @returns {boolean} True if the mirror reflects the undefined value.
248 */
249Mirror.prototype.isUndefined = function() {
250  return this instanceof UndefinedMirror;
251};
252
253
254/**
255 * Check whether the mirror reflects the null value.
256 * @returns {boolean} True if the mirror reflects the null value
257 */
258Mirror.prototype.isNull = function() {
259  return this instanceof NullMirror;
260};
261
262
263/**
264 * Check whether the mirror reflects a boolean value.
265 * @returns {boolean} True if the mirror reflects a boolean value
266 */
267Mirror.prototype.isBoolean = function() {
268  return this instanceof BooleanMirror;
269};
270
271
272/**
273 * Check whether the mirror reflects a number value.
274 * @returns {boolean} True if the mirror reflects a number value
275 */
276Mirror.prototype.isNumber = function() {
277  return this instanceof NumberMirror;
278};
279
280
281/**
282 * Check whether the mirror reflects a string value.
283 * @returns {boolean} True if the mirror reflects a string value
284 */
285Mirror.prototype.isString = function() {
286  return this instanceof StringMirror;
287};
288
289
290/**
291 * Check whether the mirror reflects an object.
292 * @returns {boolean} True if the mirror reflects an object
293 */
294Mirror.prototype.isObject = function() {
295  return this instanceof ObjectMirror;
296};
297
298
299/**
300 * Check whether the mirror reflects a function.
301 * @returns {boolean} True if the mirror reflects a function
302 */
303Mirror.prototype.isFunction = function() {
304  return this instanceof FunctionMirror;
305};
306
307
308/**
309 * Check whether the mirror reflects an unresolved function.
310 * @returns {boolean} True if the mirror reflects an unresolved function
311 */
312Mirror.prototype.isUnresolvedFunction = function() {
313  return this instanceof UnresolvedFunctionMirror;
314};
315
316
317/**
318 * Check whether the mirror reflects an array.
319 * @returns {boolean} True if the mirror reflects an array
320 */
321Mirror.prototype.isArray = function() {
322  return this instanceof ArrayMirror;
323};
324
325
326/**
327 * Check whether the mirror reflects a date.
328 * @returns {boolean} True if the mirror reflects a date
329 */
330Mirror.prototype.isDate = function() {
331  return this instanceof DateMirror;
332};
333
334
335/**
336 * Check whether the mirror reflects a regular expression.
337 * @returns {boolean} True if the mirror reflects a regular expression
338 */
339Mirror.prototype.isRegExp = function() {
340  return this instanceof RegExpMirror;
341};
342
343
344/**
345 * Check whether the mirror reflects an error.
346 * @returns {boolean} True if the mirror reflects an error
347 */
348Mirror.prototype.isError = function() {
349  return this instanceof ErrorMirror;
350};
351
352
353/**
354 * Check whether the mirror reflects a property.
355 * @returns {boolean} True if the mirror reflects a property
356 */
357Mirror.prototype.isProperty = function() {
358  return this instanceof PropertyMirror;
359};
360
361
362/**
363 * Check whether the mirror reflects a stack frame.
364 * @returns {boolean} True if the mirror reflects a stack frame
365 */
366Mirror.prototype.isFrame = function() {
367  return this instanceof FrameMirror;
368};
369
370
371/**
372 * Check whether the mirror reflects a script.
373 * @returns {boolean} True if the mirror reflects a script
374 */
375Mirror.prototype.isScript = function() {
376  return this instanceof ScriptMirror;
377};
378
379
380/**
381 * Check whether the mirror reflects a context.
382 * @returns {boolean} True if the mirror reflects a context
383 */
384Mirror.prototype.isContext = function() {
385  return this instanceof ContextMirror;
386};
387
388
389/**
390 * Check whether the mirror reflects a scope.
391 * @returns {boolean} True if the mirror reflects a scope
392 */
393Mirror.prototype.isScope = function() {
394  return this instanceof ScopeMirror;
395};
396
397
398/**
399 * Allocate a handle id for this object.
400 */
401Mirror.prototype.allocateHandle_ = function() {
402  this.handle_ = next_handle_++;
403};
404
405
406/**
407 * Allocate a transient handle id for this object. Transient handles are
408 * negative.
409 */
410Mirror.prototype.allocateTransientHandle_ = function() {
411  this.handle_ = next_transient_handle_--;
412};
413
414
415Mirror.prototype.toText = function() {
416  // Simpel to text which is used when on specialization in subclass.
417  return "#<" + this.constructor.name + ">";
418};
419
420
421/**
422 * Base class for all value mirror objects.
423 * @param {string} type The type of the mirror
424 * @param {value} value The value reflected by this mirror
425 * @param {boolean} transient indicate whether this object is transient with a
426 *    transient handle
427 * @constructor
428 * @extends Mirror
429 */
430function ValueMirror(type, value, transient) {
431  %_CallFunction(this, type, Mirror);
432  this.value_ = value;
433  if (!transient) {
434    this.allocateHandle_();
435  } else {
436    this.allocateTransientHandle_();
437  }
438}
439inherits(ValueMirror, Mirror);
440
441
442Mirror.prototype.handle = function() {
443  return this.handle_;
444};
445
446
447/**
448 * Check whether this is a primitive value.
449 * @return {boolean} True if the mirror reflects a primitive value
450 */
451ValueMirror.prototype.isPrimitive = function() {
452  var type = this.type();
453  return type === 'undefined' ||
454         type === 'null' ||
455         type === 'boolean' ||
456         type === 'number' ||
457         type === 'string';
458};
459
460
461/**
462 * Get the actual value reflected by this mirror.
463 * @return {value} The value reflected by this mirror
464 */
465ValueMirror.prototype.value = function() {
466  return this.value_;
467};
468
469
470/**
471 * Mirror object for Undefined.
472 * @constructor
473 * @extends ValueMirror
474 */
475function UndefinedMirror() {
476  %_CallFunction(this, UNDEFINED_TYPE, void 0, ValueMirror);
477}
478inherits(UndefinedMirror, ValueMirror);
479
480
481UndefinedMirror.prototype.toText = function() {
482  return 'undefined';
483};
484
485
486/**
487 * Mirror object for null.
488 * @constructor
489 * @extends ValueMirror
490 */
491function NullMirror() {
492  %_CallFunction(this, NULL_TYPE, null, ValueMirror);
493}
494inherits(NullMirror, ValueMirror);
495
496
497NullMirror.prototype.toText = function() {
498  return 'null';
499};
500
501
502/**
503 * Mirror object for boolean values.
504 * @param {boolean} value The boolean value reflected by this mirror
505 * @constructor
506 * @extends ValueMirror
507 */
508function BooleanMirror(value) {
509  %_CallFunction(this, BOOLEAN_TYPE, value, ValueMirror);
510}
511inherits(BooleanMirror, ValueMirror);
512
513
514BooleanMirror.prototype.toText = function() {
515  return this.value_ ? 'true' : 'false';
516};
517
518
519/**
520 * Mirror object for number values.
521 * @param {number} value The number value reflected by this mirror
522 * @constructor
523 * @extends ValueMirror
524 */
525function NumberMirror(value) {
526  %_CallFunction(this, NUMBER_TYPE, value, ValueMirror);
527}
528inherits(NumberMirror, ValueMirror);
529
530
531NumberMirror.prototype.toText = function() {
532  return %NumberToString(this.value_);
533};
534
535
536/**
537 * Mirror object for string values.
538 * @param {string} value The string value reflected by this mirror
539 * @constructor
540 * @extends ValueMirror
541 */
542function StringMirror(value) {
543  %_CallFunction(this, STRING_TYPE, value, ValueMirror);
544}
545inherits(StringMirror, ValueMirror);
546
547
548StringMirror.prototype.length = function() {
549  return this.value_.length;
550};
551
552StringMirror.prototype.getTruncatedValue = function(maxLength) {
553  if (maxLength != -1 && this.length() > maxLength) {
554    return this.value_.substring(0, maxLength) +
555           '... (length: ' + this.length() + ')';
556  }
557  return this.value_;
558};
559
560StringMirror.prototype.toText = function() {
561  return this.getTruncatedValue(kMaxProtocolStringLength);
562};
563
564
565/**
566 * Mirror object for objects.
567 * @param {object} value The object reflected by this mirror
568 * @param {boolean} transient indicate whether this object is transient with a
569 *    transient handle
570 * @constructor
571 * @extends ValueMirror
572 */
573function ObjectMirror(value, type, transient) {
574  %_CallFunction(this, type || OBJECT_TYPE, value, transient, ValueMirror);
575}
576inherits(ObjectMirror, ValueMirror);
577
578
579ObjectMirror.prototype.className = function() {
580  return %_ClassOf(this.value_);
581};
582
583
584ObjectMirror.prototype.constructorFunction = function() {
585  return MakeMirror(%DebugGetProperty(this.value_, 'constructor'));
586};
587
588
589ObjectMirror.prototype.prototypeObject = function() {
590  return MakeMirror(%DebugGetProperty(this.value_, 'prototype'));
591};
592
593
594ObjectMirror.prototype.protoObject = function() {
595  return MakeMirror(%DebugGetPrototype(this.value_));
596};
597
598
599ObjectMirror.prototype.hasNamedInterceptor = function() {
600  // Get information on interceptors for this object.
601  var x = %GetInterceptorInfo(this.value_);
602  return (x & 2) != 0;
603};
604
605
606ObjectMirror.prototype.hasIndexedInterceptor = function() {
607  // Get information on interceptors for this object.
608  var x = %GetInterceptorInfo(this.value_);
609  return (x & 1) != 0;
610};
611
612
613/**
614 * Return the property names for this object.
615 * @param {number} kind Indicate whether named, indexed or both kinds of
616 *     properties are requested
617 * @param {number} limit Limit the number of names returend to the specified
618       value
619 * @return {Array} Property names for this object
620 */
621ObjectMirror.prototype.propertyNames = function(kind, limit) {
622  // Find kind and limit and allocate array for the result
623  kind = kind || PropertyKind.Named | PropertyKind.Indexed;
624
625  var propertyNames;
626  var elementNames;
627  var total = 0;
628
629  // Find all the named properties.
630  if (kind & PropertyKind.Named) {
631    // Get the local property names.
632    propertyNames = %GetLocalPropertyNames(this.value_);
633    total += propertyNames.length;
634
635    // Get names for named interceptor properties if any.
636    if (this.hasNamedInterceptor() && (kind & PropertyKind.Named)) {
637      var namedInterceptorNames =
638          %GetNamedInterceptorPropertyNames(this.value_);
639      if (namedInterceptorNames) {
640        propertyNames = propertyNames.concat(namedInterceptorNames);
641        total += namedInterceptorNames.length;
642      }
643    }
644  }
645
646  // Find all the indexed properties.
647  if (kind & PropertyKind.Indexed) {
648    // Get the local element names.
649    elementNames = %GetLocalElementNames(this.value_);
650    total += elementNames.length;
651
652    // Get names for indexed interceptor properties.
653    if (this.hasIndexedInterceptor() && (kind & PropertyKind.Indexed)) {
654      var indexedInterceptorNames =
655          %GetIndexedInterceptorElementNames(this.value_);
656      if (indexedInterceptorNames) {
657        elementNames = elementNames.concat(indexedInterceptorNames);
658        total += indexedInterceptorNames.length;
659      }
660    }
661  }
662  limit = Math.min(limit || total, total);
663
664  var names = new Array(limit);
665  var index = 0;
666
667  // Copy names for named properties.
668  if (kind & PropertyKind.Named) {
669    for (var i = 0; index < limit && i < propertyNames.length; i++) {
670      names[index++] = propertyNames[i];
671    }
672  }
673
674  // Copy names for indexed properties.
675  if (kind & PropertyKind.Indexed) {
676    for (var i = 0; index < limit && i < elementNames.length; i++) {
677      names[index++] = elementNames[i];
678    }
679  }
680
681  return names;
682};
683
684
685/**
686 * Return the properties for this object as an array of PropertyMirror objects.
687 * @param {number} kind Indicate whether named, indexed or both kinds of
688 *     properties are requested
689 * @param {number} limit Limit the number of properties returend to the
690       specified value
691 * @return {Array} Property mirrors for this object
692 */
693ObjectMirror.prototype.properties = function(kind, limit) {
694  var names = this.propertyNames(kind, limit);
695  var properties = new Array(names.length);
696  for (var i = 0; i < names.length; i++) {
697    properties[i] = this.property(names[i]);
698  }
699
700  return properties;
701};
702
703
704ObjectMirror.prototype.property = function(name) {
705  var details = %DebugGetPropertyDetails(this.value_, %ToString(name));
706  if (details) {
707    return new PropertyMirror(this, name, details);
708  }
709
710  // Nothing found.
711  return GetUndefinedMirror();
712};
713
714
715
716/**
717 * Try to find a property from its value.
718 * @param {Mirror} value The property value to look for
719 * @return {PropertyMirror} The property with the specified value. If no
720 *     property was found with the specified value UndefinedMirror is returned
721 */
722ObjectMirror.prototype.lookupProperty = function(value) {
723  var properties = this.properties();
724
725  // Look for property value in properties.
726  for (var i = 0; i < properties.length; i++) {
727
728    // Skip properties which are defined through assessors.
729    var property = properties[i];
730    if (property.propertyType() != PropertyType.Callbacks) {
731      if (%_ObjectEquals(property.value_, value.value_)) {
732        return property;
733      }
734    }
735  }
736
737  // Nothing found.
738  return GetUndefinedMirror();
739};
740
741
742/**
743 * Returns objects which has direct references to this object
744 * @param {number} opt_max_objects Optional parameter specifying the maximum
745 *     number of referencing objects to return.
746 * @return {Array} The objects which has direct references to this object.
747 */
748ObjectMirror.prototype.referencedBy = function(opt_max_objects) {
749  // Find all objects with direct references to this object.
750  var result = %DebugReferencedBy(this.value_,
751                                  Mirror.prototype, opt_max_objects || 0);
752
753  // Make mirrors for all the references found.
754  for (var i = 0; i < result.length; i++) {
755    result[i] = MakeMirror(result[i]);
756  }
757
758  return result;
759};
760
761
762ObjectMirror.prototype.toText = function() {
763  var name;
764  var ctor = this.constructorFunction();
765  if (!ctor.isFunction()) {
766    name = this.className();
767  } else {
768    name = ctor.name();
769    if (!name) {
770      name = this.className();
771    }
772  }
773  return '#<' + name + '>';
774};
775
776
777/**
778 * Mirror object for functions.
779 * @param {function} value The function object reflected by this mirror.
780 * @constructor
781 * @extends ObjectMirror
782 */
783function FunctionMirror(value) {
784  %_CallFunction(this, value, FUNCTION_TYPE, ObjectMirror);
785  this.resolved_ = true;
786}
787inherits(FunctionMirror, ObjectMirror);
788
789
790/**
791 * Returns whether the function is resolved.
792 * @return {boolean} True if the function is resolved. Unresolved functions can
793 *     only originate as functions from stack frames
794 */
795FunctionMirror.prototype.resolved = function() {
796  return this.resolved_;
797};
798
799
800/**
801 * Returns the name of the function.
802 * @return {string} Name of the function
803 */
804FunctionMirror.prototype.name = function() {
805  return %FunctionGetName(this.value_);
806};
807
808
809/**
810 * Returns the inferred name of the function.
811 * @return {string} Name of the function
812 */
813FunctionMirror.prototype.inferredName = function() {
814  return %FunctionGetInferredName(this.value_);
815};
816
817
818/**
819 * Returns the source code for the function.
820 * @return {string or undefined} The source code for the function. If the
821 *     function is not resolved undefined will be returned.
822 */
823FunctionMirror.prototype.source = function() {
824  // Return source if function is resolved. Otherwise just fall through to
825  // return undefined.
826  if (this.resolved()) {
827    return builtins.FunctionSourceString(this.value_);
828  }
829};
830
831
832/**
833 * Returns the script object for the function.
834 * @return {ScriptMirror or undefined} Script object for the function or
835 *     undefined if the function has no script
836 */
837FunctionMirror.prototype.script = function() {
838  // Return script if function is resolved. Otherwise just fall through
839  // to return undefined.
840  if (this.resolved()) {
841    var script = %FunctionGetScript(this.value_);
842    if (script) {
843      return MakeMirror(script);
844    }
845  }
846};
847
848
849/**
850 * Returns the script source position for the function. Only makes sense
851 * for functions which has a script defined.
852 * @return {Number or undefined} in-script position for the function
853 */
854FunctionMirror.prototype.sourcePosition_ = function() {
855  // Return script if function is resolved. Otherwise just fall through
856  // to return undefined.
857  if (this.resolved()) {
858    return %FunctionGetScriptSourcePosition(this.value_);
859  }
860};
861
862
863/**
864 * Returns the script source location object for the function. Only makes sense
865 * for functions which has a script defined.
866 * @return {Location or undefined} in-script location for the function begin
867 */
868FunctionMirror.prototype.sourceLocation = function() {
869  if (this.resolved() && this.script()) {
870    return this.script().locationFromPosition(this.sourcePosition_(),
871                                              true);
872  }
873};
874
875
876/**
877 * Returns objects constructed by this function.
878 * @param {number} opt_max_instances Optional parameter specifying the maximum
879 *     number of instances to return.
880 * @return {Array or undefined} The objects constructed by this function.
881 */
882FunctionMirror.prototype.constructedBy = function(opt_max_instances) {
883  if (this.resolved()) {
884    // Find all objects constructed from this function.
885    var result = %DebugConstructedBy(this.value_, opt_max_instances || 0);
886
887    // Make mirrors for all the instances found.
888    for (var i = 0; i < result.length; i++) {
889      result[i] = MakeMirror(result[i]);
890    }
891
892    return result;
893  } else {
894    return [];
895  }
896};
897
898
899FunctionMirror.prototype.toText = function() {
900  return this.source();
901};
902
903
904/**
905 * Mirror object for unresolved functions.
906 * @param {string} value The name for the unresolved function reflected by this
907 *     mirror.
908 * @constructor
909 * @extends ObjectMirror
910 */
911function UnresolvedFunctionMirror(value) {
912  // Construct this using the ValueMirror as an unresolved function is not a
913  // real object but just a string.
914  %_CallFunction(this, FUNCTION_TYPE, value, ValueMirror);
915  this.propertyCount_ = 0;
916  this.elementCount_ = 0;
917  this.resolved_ = false;
918}
919inherits(UnresolvedFunctionMirror, FunctionMirror);
920
921
922UnresolvedFunctionMirror.prototype.className = function() {
923  return 'Function';
924};
925
926
927UnresolvedFunctionMirror.prototype.constructorFunction = function() {
928  return GetUndefinedMirror();
929};
930
931
932UnresolvedFunctionMirror.prototype.prototypeObject = function() {
933  return GetUndefinedMirror();
934};
935
936
937UnresolvedFunctionMirror.prototype.protoObject = function() {
938  return GetUndefinedMirror();
939};
940
941
942UnresolvedFunctionMirror.prototype.name = function() {
943  return this.value_;
944};
945
946
947UnresolvedFunctionMirror.prototype.inferredName = function() {
948  return undefined;
949};
950
951
952UnresolvedFunctionMirror.prototype.propertyNames = function(kind, limit) {
953  return [];
954};
955
956
957/**
958 * Mirror object for arrays.
959 * @param {Array} value The Array object reflected by this mirror
960 * @constructor
961 * @extends ObjectMirror
962 */
963function ArrayMirror(value) {
964  %_CallFunction(this, value, ObjectMirror);
965}
966inherits(ArrayMirror, ObjectMirror);
967
968
969ArrayMirror.prototype.length = function() {
970  return this.value_.length;
971};
972
973
974ArrayMirror.prototype.indexedPropertiesFromRange = function(opt_from_index,
975                                                            opt_to_index) {
976  var from_index = opt_from_index || 0;
977  var to_index = opt_to_index || this.length() - 1;
978  if (from_index > to_index) return new Array();
979  var values = new Array(to_index - from_index + 1);
980  for (var i = from_index; i <= to_index; i++) {
981    var details = %DebugGetPropertyDetails(this.value_, %ToString(i));
982    var value;
983    if (details) {
984      value = new PropertyMirror(this, i, details);
985    } else {
986      value = GetUndefinedMirror();
987    }
988    values[i - from_index] = value;
989  }
990  return values;
991};
992
993
994/**
995 * Mirror object for dates.
996 * @param {Date} value The Date object reflected by this mirror
997 * @constructor
998 * @extends ObjectMirror
999 */
1000function DateMirror(value) {
1001  %_CallFunction(this, value, ObjectMirror);
1002}
1003inherits(DateMirror, ObjectMirror);
1004
1005
1006DateMirror.prototype.toText = function() {
1007  var s = JSON.stringify(this.value_);
1008  return s.substring(1, s.length - 1);  // cut quotes
1009};
1010
1011
1012/**
1013 * Mirror object for regular expressions.
1014 * @param {RegExp} value The RegExp object reflected by this mirror
1015 * @constructor
1016 * @extends ObjectMirror
1017 */
1018function RegExpMirror(value) {
1019  %_CallFunction(this, value, REGEXP_TYPE, ObjectMirror);
1020}
1021inherits(RegExpMirror, ObjectMirror);
1022
1023
1024/**
1025 * Returns the source to the regular expression.
1026 * @return {string or undefined} The source to the regular expression
1027 */
1028RegExpMirror.prototype.source = function() {
1029  return this.value_.source;
1030};
1031
1032
1033/**
1034 * Returns whether this regular expression has the global (g) flag set.
1035 * @return {boolean} Value of the global flag
1036 */
1037RegExpMirror.prototype.global = function() {
1038  return this.value_.global;
1039};
1040
1041
1042/**
1043 * Returns whether this regular expression has the ignore case (i) flag set.
1044 * @return {boolean} Value of the ignore case flag
1045 */
1046RegExpMirror.prototype.ignoreCase = function() {
1047  return this.value_.ignoreCase;
1048};
1049
1050
1051/**
1052 * Returns whether this regular expression has the multiline (m) flag set.
1053 * @return {boolean} Value of the multiline flag
1054 */
1055RegExpMirror.prototype.multiline = function() {
1056  return this.value_.multiline;
1057};
1058
1059
1060RegExpMirror.prototype.toText = function() {
1061  // Simpel to text which is used when on specialization in subclass.
1062  return "/" + this.source() + "/";
1063};
1064
1065
1066/**
1067 * Mirror object for error objects.
1068 * @param {Error} value The error object reflected by this mirror
1069 * @constructor
1070 * @extends ObjectMirror
1071 */
1072function ErrorMirror(value) {
1073  %_CallFunction(this, value, ERROR_TYPE, ObjectMirror);
1074}
1075inherits(ErrorMirror, ObjectMirror);
1076
1077
1078/**
1079 * Returns the message for this eror object.
1080 * @return {string or undefined} The message for this eror object
1081 */
1082ErrorMirror.prototype.message = function() {
1083  return this.value_.message;
1084};
1085
1086
1087ErrorMirror.prototype.toText = function() {
1088  // Use the same text representation as in messages.js.
1089  var text;
1090  try {
1091    str = %_CallFunction(this.value_, builtins.ErrorToString);
1092  } catch (e) {
1093    str = '#<Error>';
1094  }
1095  return str;
1096};
1097
1098
1099/**
1100 * Base mirror object for properties.
1101 * @param {ObjectMirror} mirror The mirror object having this property
1102 * @param {string} name The name of the property
1103 * @param {Array} details Details about the property
1104 * @constructor
1105 * @extends Mirror
1106 */
1107function PropertyMirror(mirror, name, details) {
1108  %_CallFunction(this, PROPERTY_TYPE, Mirror);
1109  this.mirror_ = mirror;
1110  this.name_ = name;
1111  this.value_ = details[0];
1112  this.details_ = details[1];
1113  if (details.length > 2) {
1114    this.exception_ = details[2];
1115    this.getter_ = details[3];
1116    this.setter_ = details[4];
1117  }
1118}
1119inherits(PropertyMirror, Mirror);
1120
1121
1122PropertyMirror.prototype.isReadOnly = function() {
1123  return (this.attributes() & PropertyAttribute.ReadOnly) != 0;
1124};
1125
1126
1127PropertyMirror.prototype.isEnum = function() {
1128  return (this.attributes() & PropertyAttribute.DontEnum) == 0;
1129};
1130
1131
1132PropertyMirror.prototype.canDelete = function() {
1133  return (this.attributes() & PropertyAttribute.DontDelete) == 0;
1134};
1135
1136
1137PropertyMirror.prototype.name = function() {
1138  return this.name_;
1139};
1140
1141
1142PropertyMirror.prototype.isIndexed = function() {
1143  for (var i = 0; i < this.name_.length; i++) {
1144    if (this.name_[i] < '0' || '9' < this.name_[i]) {
1145      return false;
1146    }
1147  }
1148  return true;
1149};
1150
1151
1152PropertyMirror.prototype.value = function() {
1153  return MakeMirror(this.value_, false);
1154};
1155
1156
1157/**
1158 * Returns whether this property value is an exception.
1159 * @return {booolean} True if this property value is an exception
1160 */
1161PropertyMirror.prototype.isException = function() {
1162  return this.exception_ ? true : false;
1163};
1164
1165
1166PropertyMirror.prototype.attributes = function() {
1167  return %DebugPropertyAttributesFromDetails(this.details_);
1168};
1169
1170
1171PropertyMirror.prototype.propertyType = function() {
1172  return %DebugPropertyTypeFromDetails(this.details_);
1173};
1174
1175
1176PropertyMirror.prototype.insertionIndex = function() {
1177  return %DebugPropertyIndexFromDetails(this.details_);
1178};
1179
1180
1181/**
1182 * Returns whether this property has a getter defined through __defineGetter__.
1183 * @return {booolean} True if this property has a getter
1184 */
1185PropertyMirror.prototype.hasGetter = function() {
1186  return this.getter_ ? true : false;
1187};
1188
1189
1190/**
1191 * Returns whether this property has a setter defined through __defineSetter__.
1192 * @return {booolean} True if this property has a setter
1193 */
1194PropertyMirror.prototype.hasSetter = function() {
1195  return this.setter_ ? true : false;
1196};
1197
1198
1199/**
1200 * Returns the getter for this property defined through __defineGetter__.
1201 * @return {Mirror} FunctionMirror reflecting the getter function or
1202 *     UndefinedMirror if there is no getter for this property
1203 */
1204PropertyMirror.prototype.getter = function() {
1205  if (this.hasGetter()) {
1206    return MakeMirror(this.getter_);
1207  } else {
1208    return GetUndefinedMirror();
1209  }
1210};
1211
1212
1213/**
1214 * Returns the setter for this property defined through __defineSetter__.
1215 * @return {Mirror} FunctionMirror reflecting the setter function or
1216 *     UndefinedMirror if there is no setter for this property
1217 */
1218PropertyMirror.prototype.setter = function() {
1219  if (this.hasSetter()) {
1220    return MakeMirror(this.setter_);
1221  } else {
1222    return GetUndefinedMirror();
1223  }
1224};
1225
1226
1227/**
1228 * Returns whether this property is natively implemented by the host or a set
1229 * through JavaScript code.
1230 * @return {boolean} True if the property is
1231 *     UndefinedMirror if there is no setter for this property
1232 */
1233PropertyMirror.prototype.isNative = function() {
1234  return (this.propertyType() == PropertyType.Interceptor) ||
1235         ((this.propertyType() == PropertyType.Callbacks) &&
1236          !this.hasGetter() && !this.hasSetter());
1237};
1238
1239
1240var kFrameDetailsFrameIdIndex = 0;
1241var kFrameDetailsReceiverIndex = 1;
1242var kFrameDetailsFunctionIndex = 2;
1243var kFrameDetailsArgumentCountIndex = 3;
1244var kFrameDetailsLocalCountIndex = 4;
1245var kFrameDetailsSourcePositionIndex = 5;
1246var kFrameDetailsConstructCallIndex = 6;
1247var kFrameDetailsAtReturnIndex = 7;
1248var kFrameDetailsFlagsIndex = 8;
1249var kFrameDetailsFirstDynamicIndex = 9;
1250
1251var kFrameDetailsNameIndex = 0;
1252var kFrameDetailsValueIndex = 1;
1253var kFrameDetailsNameValueSize = 2;
1254
1255var kFrameDetailsFlagDebuggerFrameMask = 1 << 0;
1256var kFrameDetailsFlagOptimizedFrameMask = 1 << 1;
1257var kFrameDetailsFlagInlinedFrameIndexMask = 7 << 2;
1258
1259/**
1260 * Wrapper for the frame details information retreived from the VM. The frame
1261 * details from the VM is an array with the following content. See runtime.cc
1262 * Runtime_GetFrameDetails.
1263 *     0: Id
1264 *     1: Receiver
1265 *     2: Function
1266 *     3: Argument count
1267 *     4: Local count
1268 *     5: Source position
1269 *     6: Construct call
1270 *     7: Is at return
1271 *     8: Flags (debugger frame, optimized frame, inlined frame index)
1272 *     Arguments name, value
1273 *     Locals name, value
1274 *     Return value if any
1275 * @param {number} break_id Current break id
1276 * @param {number} index Frame number
1277 * @constructor
1278 */
1279function FrameDetails(break_id, index) {
1280  this.break_id_ = break_id;
1281  this.details_ = %GetFrameDetails(break_id, index);
1282}
1283
1284
1285FrameDetails.prototype.frameId = function() {
1286  %CheckExecutionState(this.break_id_);
1287  return this.details_[kFrameDetailsFrameIdIndex];
1288};
1289
1290
1291FrameDetails.prototype.receiver = function() {
1292  %CheckExecutionState(this.break_id_);
1293  return this.details_[kFrameDetailsReceiverIndex];
1294};
1295
1296
1297FrameDetails.prototype.func = function() {
1298  %CheckExecutionState(this.break_id_);
1299  return this.details_[kFrameDetailsFunctionIndex];
1300};
1301
1302
1303FrameDetails.prototype.isConstructCall = function() {
1304  %CheckExecutionState(this.break_id_);
1305  return this.details_[kFrameDetailsConstructCallIndex];
1306};
1307
1308
1309FrameDetails.prototype.isAtReturn = function() {
1310  %CheckExecutionState(this.break_id_);
1311  return this.details_[kFrameDetailsAtReturnIndex];
1312};
1313
1314
1315FrameDetails.prototype.isDebuggerFrame = function() {
1316  %CheckExecutionState(this.break_id_);
1317  var f = kFrameDetailsFlagDebuggerFrameMask;
1318  return (this.details_[kFrameDetailsFlagsIndex] & f) == f;
1319};
1320
1321
1322FrameDetails.prototype.isOptimizedFrame = function() {
1323  %CheckExecutionState(this.break_id_);
1324  var f = kFrameDetailsFlagOptimizedFrameMask;
1325  return (this.details_[kFrameDetailsFlagsIndex] & f) == f;
1326};
1327
1328
1329FrameDetails.prototype.isInlinedFrame = function() {
1330  return this.inlinedFrameIndex() > 0;
1331};
1332
1333
1334FrameDetails.prototype.inlinedFrameIndex = function() {
1335  %CheckExecutionState(this.break_id_);
1336  var f = kFrameDetailsFlagInlinedFrameIndexMask;
1337  return (this.details_[kFrameDetailsFlagsIndex] & f) >> 2;
1338};
1339
1340
1341FrameDetails.prototype.argumentCount = function() {
1342  %CheckExecutionState(this.break_id_);
1343  return this.details_[kFrameDetailsArgumentCountIndex];
1344};
1345
1346
1347FrameDetails.prototype.argumentName = function(index) {
1348  %CheckExecutionState(this.break_id_);
1349  if (index >= 0 && index < this.argumentCount()) {
1350    return this.details_[kFrameDetailsFirstDynamicIndex +
1351                         index * kFrameDetailsNameValueSize +
1352                         kFrameDetailsNameIndex];
1353  }
1354};
1355
1356
1357FrameDetails.prototype.argumentValue = function(index) {
1358  %CheckExecutionState(this.break_id_);
1359  if (index >= 0 && index < this.argumentCount()) {
1360    return this.details_[kFrameDetailsFirstDynamicIndex +
1361                         index * kFrameDetailsNameValueSize +
1362                         kFrameDetailsValueIndex];
1363  }
1364};
1365
1366
1367FrameDetails.prototype.localCount = function() {
1368  %CheckExecutionState(this.break_id_);
1369  return this.details_[kFrameDetailsLocalCountIndex];
1370};
1371
1372
1373FrameDetails.prototype.sourcePosition = function() {
1374  %CheckExecutionState(this.break_id_);
1375  return this.details_[kFrameDetailsSourcePositionIndex];
1376};
1377
1378
1379FrameDetails.prototype.localName = function(index) {
1380  %CheckExecutionState(this.break_id_);
1381  if (index >= 0 && index < this.localCount()) {
1382    var locals_offset = kFrameDetailsFirstDynamicIndex +
1383                        this.argumentCount() * kFrameDetailsNameValueSize;
1384    return this.details_[locals_offset +
1385                         index * kFrameDetailsNameValueSize +
1386                         kFrameDetailsNameIndex];
1387  }
1388};
1389
1390
1391FrameDetails.prototype.localValue = function(index) {
1392  %CheckExecutionState(this.break_id_);
1393  if (index >= 0 && index < this.localCount()) {
1394    var locals_offset = kFrameDetailsFirstDynamicIndex +
1395                        this.argumentCount() * kFrameDetailsNameValueSize;
1396    return this.details_[locals_offset +
1397                         index * kFrameDetailsNameValueSize +
1398                         kFrameDetailsValueIndex];
1399  }
1400};
1401
1402
1403FrameDetails.prototype.returnValue = function() {
1404  %CheckExecutionState(this.break_id_);
1405  var return_value_offset =
1406      kFrameDetailsFirstDynamicIndex +
1407      (this.argumentCount() + this.localCount()) * kFrameDetailsNameValueSize;
1408  if (this.details_[kFrameDetailsAtReturnIndex]) {
1409    return this.details_[return_value_offset];
1410  }
1411};
1412
1413
1414FrameDetails.prototype.scopeCount = function() {
1415  return %GetScopeCount(this.break_id_, this.frameId());
1416};
1417
1418
1419/**
1420 * Mirror object for stack frames.
1421 * @param {number} break_id The break id in the VM for which this frame is
1422       valid
1423 * @param {number} index The frame index (top frame is index 0)
1424 * @constructor
1425 * @extends Mirror
1426 */
1427function FrameMirror(break_id, index) {
1428  %_CallFunction(this, FRAME_TYPE, Mirror);
1429  this.break_id_ = break_id;
1430  this.index_ = index;
1431  this.details_ = new FrameDetails(break_id, index);
1432}
1433inherits(FrameMirror, Mirror);
1434
1435
1436FrameMirror.prototype.index = function() {
1437  return this.index_;
1438};
1439
1440
1441FrameMirror.prototype.func = function() {
1442  // Get the function for this frame from the VM.
1443  var f = this.details_.func();
1444
1445  // Create a function mirror. NOTE: MakeMirror cannot be used here as the
1446  // value returned from the VM might be a string if the function for the
1447  // frame is unresolved.
1448  if (IS_FUNCTION(f)) {
1449    return MakeMirror(f);
1450  } else {
1451    return new UnresolvedFunctionMirror(f);
1452  }
1453};
1454
1455
1456FrameMirror.prototype.receiver = function() {
1457  return MakeMirror(this.details_.receiver());
1458};
1459
1460
1461FrameMirror.prototype.isConstructCall = function() {
1462  return this.details_.isConstructCall();
1463};
1464
1465
1466FrameMirror.prototype.isAtReturn = function() {
1467  return this.details_.isAtReturn();
1468};
1469
1470
1471FrameMirror.prototype.isDebuggerFrame = function() {
1472  return this.details_.isDebuggerFrame();
1473};
1474
1475
1476FrameMirror.prototype.isOptimizedFrame = function() {
1477  return this.details_.isOptimizedFrame();
1478};
1479
1480
1481FrameMirror.prototype.isInlinedFrame = function() {
1482  return this.details_.isInlinedFrame();
1483};
1484
1485
1486FrameMirror.prototype.inlinedFrameIndex = function() {
1487  return this.details_.inlinedFrameIndex();
1488};
1489
1490
1491FrameMirror.prototype.argumentCount = function() {
1492  return this.details_.argumentCount();
1493};
1494
1495
1496FrameMirror.prototype.argumentName = function(index) {
1497  return this.details_.argumentName(index);
1498};
1499
1500
1501FrameMirror.prototype.argumentValue = function(index) {
1502  return MakeMirror(this.details_.argumentValue(index));
1503};
1504
1505
1506FrameMirror.prototype.localCount = function() {
1507  return this.details_.localCount();
1508};
1509
1510
1511FrameMirror.prototype.localName = function(index) {
1512  return this.details_.localName(index);
1513};
1514
1515
1516FrameMirror.prototype.localValue = function(index) {
1517  return MakeMirror(this.details_.localValue(index));
1518};
1519
1520
1521FrameMirror.prototype.returnValue = function() {
1522  return MakeMirror(this.details_.returnValue());
1523};
1524
1525
1526FrameMirror.prototype.sourcePosition = function() {
1527  return this.details_.sourcePosition();
1528};
1529
1530
1531FrameMirror.prototype.sourceLocation = function() {
1532  if (this.func().resolved() && this.func().script()) {
1533    return this.func().script().locationFromPosition(this.sourcePosition(),
1534                                                     true);
1535  }
1536};
1537
1538
1539FrameMirror.prototype.sourceLine = function() {
1540  if (this.func().resolved()) {
1541    var location = this.sourceLocation();
1542    if (location) {
1543      return location.line;
1544    }
1545  }
1546};
1547
1548
1549FrameMirror.prototype.sourceColumn = function() {
1550  if (this.func().resolved()) {
1551    var location = this.sourceLocation();
1552    if (location) {
1553      return location.column;
1554    }
1555  }
1556};
1557
1558
1559FrameMirror.prototype.sourceLineText = function() {
1560  if (this.func().resolved()) {
1561    var location = this.sourceLocation();
1562    if (location) {
1563      return location.sourceText();
1564    }
1565  }
1566};
1567
1568
1569FrameMirror.prototype.scopeCount = function() {
1570  return this.details_.scopeCount();
1571};
1572
1573
1574FrameMirror.prototype.scope = function(index) {
1575  return new ScopeMirror(this, index);
1576};
1577
1578
1579FrameMirror.prototype.evaluate = function(source, disable_break,
1580                                          opt_context_object) {
1581  var result = %DebugEvaluate(this.break_id_,
1582                              this.details_.frameId(),
1583                              this.details_.inlinedFrameIndex(),
1584                              source,
1585                              Boolean(disable_break),
1586                              opt_context_object);
1587  return MakeMirror(result);
1588};
1589
1590
1591FrameMirror.prototype.invocationText = function() {
1592  // Format frame invoaction (receiver, function and arguments).
1593  var result = '';
1594  var func = this.func();
1595  var receiver = this.receiver();
1596  if (this.isConstructCall()) {
1597    // For constructor frames display new followed by the function name.
1598    result += 'new ';
1599    result += func.name() ? func.name() : '[anonymous]';
1600  } else if (this.isDebuggerFrame()) {
1601    result += '[debugger]';
1602  } else {
1603    // If the receiver has a className which is 'global' don't display it.
1604    var display_receiver =
1605      !receiver.className || (receiver.className() != 'global');
1606    if (display_receiver) {
1607      result += receiver.toText();
1608    }
1609    // Try to find the function as a property in the receiver. Include the
1610    // prototype chain in the lookup.
1611    var property = GetUndefinedMirror();
1612    if (receiver.isObject()) {
1613      for (var r = receiver;
1614           !r.isNull() && property.isUndefined();
1615           r = r.protoObject()) {
1616        property = r.lookupProperty(func);
1617      }
1618    }
1619    if (!property.isUndefined()) {
1620      // The function invoked was found on the receiver. Use the property name
1621      // for the backtrace.
1622      if (!property.isIndexed()) {
1623        if (display_receiver) {
1624          result += '.';
1625        }
1626        result += property.name();
1627      } else {
1628        result += '[';
1629        result += property.name();
1630        result += ']';
1631      }
1632      // Also known as - if the name in the function doesn't match the name
1633      // under which it was looked up.
1634      if (func.name() && func.name() != property.name()) {
1635        result += '(aka ' + func.name() + ')';
1636      }
1637    } else {
1638      // The function invoked was not found on the receiver. Use the function
1639      // name if available for the backtrace.
1640      if (display_receiver) {
1641        result += '.';
1642      }
1643      result += func.name() ? func.name() : '[anonymous]';
1644    }
1645  }
1646
1647  // Render arguments for normal frames.
1648  if (!this.isDebuggerFrame()) {
1649    result += '(';
1650    for (var i = 0; i < this.argumentCount(); i++) {
1651      if (i != 0) result += ', ';
1652      if (this.argumentName(i)) {
1653        result += this.argumentName(i);
1654        result += '=';
1655      }
1656      result += this.argumentValue(i).toText();
1657    }
1658    result += ')';
1659  }
1660
1661  if (this.isAtReturn()) {
1662    result += ' returning ';
1663    result += this.returnValue().toText();
1664  }
1665
1666  return result;
1667};
1668
1669
1670FrameMirror.prototype.sourceAndPositionText = function() {
1671  // Format source and position.
1672  var result = '';
1673  var func = this.func();
1674  if (func.resolved()) {
1675    if (func.script()) {
1676      if (func.script().name()) {
1677        result += func.script().name();
1678      } else {
1679        result += '[unnamed]';
1680      }
1681      if (!this.isDebuggerFrame()) {
1682        var location = this.sourceLocation();
1683        result += ' line ';
1684        result += !IS_UNDEFINED(location) ? (location.line + 1) : '?';
1685        result += ' column ';
1686        result += !IS_UNDEFINED(location) ? (location.column + 1) : '?';
1687        if (!IS_UNDEFINED(this.sourcePosition())) {
1688          result += ' (position ' + (this.sourcePosition() + 1) + ')';
1689        }
1690      }
1691    } else {
1692      result += '[no source]';
1693    }
1694  } else {
1695    result += '[unresolved]';
1696  }
1697
1698  return result;
1699};
1700
1701
1702FrameMirror.prototype.localsText = function() {
1703  // Format local variables.
1704  var result = '';
1705  var locals_count = this.localCount();
1706  if (locals_count > 0) {
1707    for (var i = 0; i < locals_count; ++i) {
1708      result += '      var ';
1709      result += this.localName(i);
1710      result += ' = ';
1711      result += this.localValue(i).toText();
1712      if (i < locals_count - 1) result += '\n';
1713    }
1714  }
1715
1716  return result;
1717};
1718
1719
1720FrameMirror.prototype.toText = function(opt_locals) {
1721  var result = '';
1722  result += '#' + (this.index() <= 9 ? '0' : '') + this.index();
1723  result += ' ';
1724  result += this.invocationText();
1725  result += ' ';
1726  result += this.sourceAndPositionText();
1727  if (opt_locals) {
1728    result += '\n';
1729    result += this.localsText();
1730  }
1731  return result;
1732};
1733
1734
1735var kScopeDetailsTypeIndex = 0;
1736var kScopeDetailsObjectIndex = 1;
1737
1738function ScopeDetails(frame, index) {
1739  this.break_id_ = frame.break_id_;
1740  this.details_ = %GetScopeDetails(frame.break_id_,
1741                                   frame.details_.frameId(),
1742                                   frame.details_.inlinedFrameIndex(),
1743                                   index);
1744}
1745
1746
1747ScopeDetails.prototype.type = function() {
1748  %CheckExecutionState(this.break_id_);
1749  return this.details_[kScopeDetailsTypeIndex];
1750};
1751
1752
1753ScopeDetails.prototype.object = function() {
1754  %CheckExecutionState(this.break_id_);
1755  return this.details_[kScopeDetailsObjectIndex];
1756};
1757
1758
1759/**
1760 * Mirror object for scope.
1761 * @param {FrameMirror} frame The frame this scope is a part of
1762 * @param {number} index The scope index in the frame
1763 * @constructor
1764 * @extends Mirror
1765 */
1766function ScopeMirror(frame, index) {
1767  %_CallFunction(this, SCOPE_TYPE, Mirror);
1768  this.frame_index_ = frame.index_;
1769  this.scope_index_ = index;
1770  this.details_ = new ScopeDetails(frame, index);
1771}
1772inherits(ScopeMirror, Mirror);
1773
1774
1775ScopeMirror.prototype.frameIndex = function() {
1776  return this.frame_index_;
1777};
1778
1779
1780ScopeMirror.prototype.scopeIndex = function() {
1781  return this.scope_index_;
1782};
1783
1784
1785ScopeMirror.prototype.scopeType = function() {
1786  return this.details_.type();
1787};
1788
1789
1790ScopeMirror.prototype.scopeObject = function() {
1791  // For local and closure scopes create a transient mirror as these objects are
1792  // created on the fly materializing the local or closure scopes and
1793  // therefore will not preserve identity.
1794  var transient = this.scopeType() == ScopeType.Local ||
1795                  this.scopeType() == ScopeType.Closure;
1796  return MakeMirror(this.details_.object(), transient);
1797};
1798
1799
1800/**
1801 * Mirror object for script source.
1802 * @param {Script} script The script object
1803 * @constructor
1804 * @extends Mirror
1805 */
1806function ScriptMirror(script) {
1807  %_CallFunction(this, SCRIPT_TYPE, Mirror);
1808  this.script_ = script;
1809  this.context_ = new ContextMirror(script.context_data);
1810  this.allocateHandle_();
1811}
1812inherits(ScriptMirror, Mirror);
1813
1814
1815ScriptMirror.prototype.value = function() {
1816  return this.script_;
1817};
1818
1819
1820ScriptMirror.prototype.name = function() {
1821  return this.script_.name || this.script_.nameOrSourceURL();
1822};
1823
1824
1825ScriptMirror.prototype.id = function() {
1826  return this.script_.id;
1827};
1828
1829
1830ScriptMirror.prototype.source = function() {
1831  return this.script_.source;
1832};
1833
1834
1835ScriptMirror.prototype.setSource = function(source) {
1836  %DebugSetScriptSource(this.script_, source);
1837};
1838
1839
1840ScriptMirror.prototype.lineOffset = function() {
1841  return this.script_.line_offset;
1842};
1843
1844
1845ScriptMirror.prototype.columnOffset = function() {
1846  return this.script_.column_offset;
1847};
1848
1849
1850ScriptMirror.prototype.data = function() {
1851  return this.script_.data;
1852};
1853
1854
1855ScriptMirror.prototype.scriptType = function() {
1856  return this.script_.type;
1857};
1858
1859
1860ScriptMirror.prototype.compilationType = function() {
1861  return this.script_.compilation_type;
1862};
1863
1864
1865ScriptMirror.prototype.lineCount = function() {
1866  return this.script_.lineCount();
1867};
1868
1869
1870ScriptMirror.prototype.locationFromPosition = function(
1871    position, include_resource_offset) {
1872  return this.script_.locationFromPosition(position, include_resource_offset);
1873};
1874
1875
1876ScriptMirror.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
1877  return this.script_.sourceSlice(opt_from_line, opt_to_line);
1878};
1879
1880
1881ScriptMirror.prototype.context = function() {
1882  return this.context_;
1883};
1884
1885
1886ScriptMirror.prototype.evalFromScript = function() {
1887  return MakeMirror(this.script_.eval_from_script);
1888};
1889
1890
1891ScriptMirror.prototype.evalFromFunctionName = function() {
1892  return MakeMirror(this.script_.eval_from_function_name);
1893};
1894
1895
1896ScriptMirror.prototype.evalFromLocation = function() {
1897  var eval_from_script = this.evalFromScript();
1898  if (!eval_from_script.isUndefined()) {
1899    var position = this.script_.eval_from_script_position;
1900    return eval_from_script.locationFromPosition(position, true);
1901  }
1902};
1903
1904
1905ScriptMirror.prototype.toText = function() {
1906  var result = '';
1907  result += this.name();
1908  result += ' (lines: ';
1909  if (this.lineOffset() > 0) {
1910    result += this.lineOffset();
1911    result += '-';
1912    result += this.lineOffset() + this.lineCount() - 1;
1913  } else {
1914    result += this.lineCount();
1915  }
1916  result += ')';
1917  return result;
1918};
1919
1920
1921/**
1922 * Mirror object for context.
1923 * @param {Object} data The context data
1924 * @constructor
1925 * @extends Mirror
1926 */
1927function ContextMirror(data) {
1928  %_CallFunction(this, CONTEXT_TYPE, Mirror);
1929  this.data_ = data;
1930  this.allocateHandle_();
1931}
1932inherits(ContextMirror, Mirror);
1933
1934
1935ContextMirror.prototype.data = function() {
1936  return this.data_;
1937};
1938
1939
1940/**
1941 * Returns a mirror serializer
1942 *
1943 * @param {boolean} details Set to true to include details
1944 * @param {Object} options Options comtrolling the serialization
1945 *     The following options can be set:
1946 *       includeSource: include ths full source of scripts
1947 * @returns {MirrorSerializer} mirror serializer
1948 */
1949function MakeMirrorSerializer(details, options) {
1950  return new JSONProtocolSerializer(details, options);
1951}
1952
1953
1954/**
1955 * Object for serializing a mirror objects and its direct references.
1956 * @param {boolean} details Indicates whether to include details for the mirror
1957 *     serialized
1958 * @constructor
1959 */
1960function JSONProtocolSerializer(details, options) {
1961  this.details_ = details;
1962  this.options_ = options;
1963  this.mirrors_ = [ ];
1964}
1965
1966
1967/**
1968 * Returns a serialization of an object reference. The referenced object are
1969 * added to the serialization state.
1970 *
1971 * @param {Mirror} mirror The mirror to serialize
1972 * @returns {String} JSON serialization
1973 */
1974JSONProtocolSerializer.prototype.serializeReference = function(mirror) {
1975  return this.serialize_(mirror, true, true);
1976};
1977
1978
1979/**
1980 * Returns a serialization of an object value. The referenced objects are
1981 * added to the serialization state.
1982 *
1983 * @param {Mirror} mirror The mirror to serialize
1984 * @returns {String} JSON serialization
1985 */
1986JSONProtocolSerializer.prototype.serializeValue = function(mirror) {
1987  var json = this.serialize_(mirror, false, true);
1988  return json;
1989};
1990
1991
1992/**
1993 * Returns a serialization of all the objects referenced.
1994 *
1995 * @param {Mirror} mirror The mirror to serialize.
1996 * @returns {Array.<Object>} Array of the referenced objects converted to
1997 *     protcol objects.
1998 */
1999JSONProtocolSerializer.prototype.serializeReferencedObjects = function() {
2000  // Collect the protocol representation of the referenced objects in an array.
2001  var content = [];
2002
2003  // Get the number of referenced objects.
2004  var count = this.mirrors_.length;
2005
2006  for (var i = 0; i < count; i++) {
2007    content.push(this.serialize_(this.mirrors_[i], false, false));
2008  }
2009
2010  return content;
2011};
2012
2013
2014JSONProtocolSerializer.prototype.includeSource_ = function() {
2015  return this.options_ && this.options_.includeSource;
2016};
2017
2018
2019JSONProtocolSerializer.prototype.inlineRefs_ = function() {
2020  return this.options_ && this.options_.inlineRefs;
2021};
2022
2023
2024JSONProtocolSerializer.prototype.maxStringLength_ = function() {
2025  if (IS_UNDEFINED(this.options_) ||
2026      IS_UNDEFINED(this.options_.maxStringLength)) {
2027    return kMaxProtocolStringLength;
2028  }
2029  return this.options_.maxStringLength;
2030};
2031
2032
2033JSONProtocolSerializer.prototype.add_ = function(mirror) {
2034  // If this mirror is already in the list just return.
2035  for (var i = 0; i < this.mirrors_.length; i++) {
2036    if (this.mirrors_[i] === mirror) {
2037      return;
2038    }
2039  }
2040
2041  // Add the mirror to the list of mirrors to be serialized.
2042  this.mirrors_.push(mirror);
2043};
2044
2045
2046/**
2047 * Formats mirror object to protocol reference object with some data that can
2048 * be used to display the value in debugger.
2049 * @param {Mirror} mirror Mirror to serialize.
2050 * @return {Object} Protocol reference object.
2051 */
2052JSONProtocolSerializer.prototype.serializeReferenceWithDisplayData_ =
2053    function(mirror) {
2054  var o = {};
2055  o.ref = mirror.handle();
2056  o.type = mirror.type();
2057  switch (mirror.type()) {
2058    case UNDEFINED_TYPE:
2059    case NULL_TYPE:
2060    case BOOLEAN_TYPE:
2061    case NUMBER_TYPE:
2062      o.value = mirror.value();
2063      break;
2064    case STRING_TYPE:
2065      o.value = mirror.getTruncatedValue(this.maxStringLength_());
2066      break;
2067    case FUNCTION_TYPE:
2068      o.name = mirror.name();
2069      o.inferredName = mirror.inferredName();
2070      if (mirror.script()) {
2071        o.scriptId = mirror.script().id();
2072      }
2073      break;
2074    case ERROR_TYPE:
2075    case REGEXP_TYPE:
2076      o.value = mirror.toText();
2077      break;
2078    case OBJECT_TYPE:
2079      o.className = mirror.className();
2080      break;
2081  }
2082  return o;
2083};
2084
2085
2086JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
2087                                                       details) {
2088  // If serializing a reference to a mirror just return the reference and add
2089  // the mirror to the referenced mirrors.
2090  if (reference &&
2091      (mirror.isValue() || mirror.isScript() || mirror.isContext())) {
2092    if (this.inlineRefs_() && mirror.isValue()) {
2093      return this.serializeReferenceWithDisplayData_(mirror);
2094    } else {
2095      this.add_(mirror);
2096      return {'ref' : mirror.handle()};
2097    }
2098  }
2099
2100  // Collect the JSON property/value pairs.
2101  var content = {};
2102
2103  // Add the mirror handle.
2104  if (mirror.isValue() || mirror.isScript() || mirror.isContext()) {
2105    content.handle = mirror.handle();
2106  }
2107
2108  // Always add the type.
2109  content.type = mirror.type();
2110
2111  switch (mirror.type()) {
2112    case UNDEFINED_TYPE:
2113    case NULL_TYPE:
2114      // Undefined and null are represented just by their type.
2115      break;
2116
2117    case BOOLEAN_TYPE:
2118      // Boolean values are simply represented by their value.
2119      content.value = mirror.value();
2120      break;
2121
2122    case NUMBER_TYPE:
2123      // Number values are simply represented by their value.
2124      content.value = NumberToJSON_(mirror.value());
2125      break;
2126
2127    case STRING_TYPE:
2128      // String values might have their value cropped to keep down size.
2129      if (this.maxStringLength_() != -1 &&
2130          mirror.length() > this.maxStringLength_()) {
2131        var str = mirror.getTruncatedValue(this.maxStringLength_());
2132        content.value = str;
2133        content.fromIndex = 0;
2134        content.toIndex = this.maxStringLength_();
2135      } else {
2136        content.value = mirror.value();
2137      }
2138      content.length = mirror.length();
2139      break;
2140
2141    case OBJECT_TYPE:
2142    case FUNCTION_TYPE:
2143    case ERROR_TYPE:
2144    case REGEXP_TYPE:
2145      // Add object representation.
2146      this.serializeObject_(mirror, content, details);
2147      break;
2148
2149    case PROPERTY_TYPE:
2150      throw new Error('PropertyMirror cannot be serialized independeltly');
2151      break;
2152
2153    case FRAME_TYPE:
2154      // Add object representation.
2155      this.serializeFrame_(mirror, content);
2156      break;
2157
2158    case SCOPE_TYPE:
2159      // Add object representation.
2160      this.serializeScope_(mirror, content);
2161      break;
2162
2163    case SCRIPT_TYPE:
2164      // Script is represented by id, name and source attributes.
2165      if (mirror.name()) {
2166        content.name = mirror.name();
2167      }
2168      content.id = mirror.id();
2169      content.lineOffset = mirror.lineOffset();
2170      content.columnOffset = mirror.columnOffset();
2171      content.lineCount = mirror.lineCount();
2172      if (mirror.data()) {
2173        content.data = mirror.data();
2174      }
2175      if (this.includeSource_()) {
2176        content.source = mirror.source();
2177      } else {
2178        var sourceStart = mirror.source().substring(0, 80);
2179        content.sourceStart = sourceStart;
2180      }
2181      content.sourceLength = mirror.source().length;
2182      content.scriptType = mirror.scriptType();
2183      content.compilationType = mirror.compilationType();
2184      // For compilation type eval emit information on the script from which
2185      // eval was called if a script is present.
2186      if (mirror.compilationType() == 1 &&
2187          mirror.evalFromScript()) {
2188        content.evalFromScript =
2189            this.serializeReference(mirror.evalFromScript());
2190        var evalFromLocation = mirror.evalFromLocation();
2191        if (evalFromLocation) {
2192          content.evalFromLocation = { line: evalFromLocation.line,
2193                                       column: evalFromLocation.column };
2194        }
2195        if (mirror.evalFromFunctionName()) {
2196          content.evalFromFunctionName = mirror.evalFromFunctionName();
2197        }
2198      }
2199      if (mirror.context()) {
2200        content.context = this.serializeReference(mirror.context());
2201      }
2202      break;
2203
2204    case CONTEXT_TYPE:
2205      content.data = mirror.data();
2206      break;
2207  }
2208
2209  // Always add the text representation.
2210  content.text = mirror.toText();
2211
2212  // Create and return the JSON string.
2213  return content;
2214};
2215
2216
2217/**
2218 * Serialize object information to the following JSON format.
2219 *
2220 *   {"className":"<class name>",
2221 *    "constructorFunction":{"ref":<number>},
2222 *    "protoObject":{"ref":<number>},
2223 *    "prototypeObject":{"ref":<number>},
2224 *    "namedInterceptor":<boolean>,
2225 *    "indexedInterceptor":<boolean>,
2226 *    "properties":[<properties>]}
2227 */
2228JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
2229                                                             details) {
2230  // Add general object properties.
2231  content.className = mirror.className();
2232  content.constructorFunction =
2233      this.serializeReference(mirror.constructorFunction());
2234  content.protoObject = this.serializeReference(mirror.protoObject());
2235  content.prototypeObject = this.serializeReference(mirror.prototypeObject());
2236
2237  // Add flags to indicate whether there are interceptors.
2238  if (mirror.hasNamedInterceptor()) {
2239    content.namedInterceptor = true;
2240  }
2241  if (mirror.hasIndexedInterceptor()) {
2242    content.indexedInterceptor = true;
2243  }
2244
2245  // Add function specific properties.
2246  if (mirror.isFunction()) {
2247    // Add function specific properties.
2248    content.name = mirror.name();
2249    if (!IS_UNDEFINED(mirror.inferredName())) {
2250      content.inferredName = mirror.inferredName();
2251    }
2252    content.resolved = mirror.resolved();
2253    if (mirror.resolved()) {
2254      content.source = mirror.source();
2255    }
2256    if (mirror.script()) {
2257      content.script = this.serializeReference(mirror.script());
2258      content.scriptId = mirror.script().id();
2259
2260      serializeLocationFields(mirror.sourceLocation(), content);
2261    }
2262  }
2263
2264  // Add date specific properties.
2265  if (mirror.isDate()) {
2266    // Add date specific properties.
2267    content.value = mirror.value();
2268  }
2269
2270  // Add actual properties - named properties followed by indexed properties.
2271  var propertyNames = mirror.propertyNames(PropertyKind.Named);
2272  var propertyIndexes = mirror.propertyNames(PropertyKind.Indexed);
2273  var p = new Array(propertyNames.length + propertyIndexes.length);
2274  for (var i = 0; i < propertyNames.length; i++) {
2275    var propertyMirror = mirror.property(propertyNames[i]);
2276    p[i] = this.serializeProperty_(propertyMirror);
2277    if (details) {
2278      this.add_(propertyMirror.value());
2279    }
2280  }
2281  for (var i = 0; i < propertyIndexes.length; i++) {
2282    var propertyMirror = mirror.property(propertyIndexes[i]);
2283    p[propertyNames.length + i] = this.serializeProperty_(propertyMirror);
2284    if (details) {
2285      this.add_(propertyMirror.value());
2286    }
2287  }
2288  content.properties = p;
2289};
2290
2291
2292/**
2293 * Serialize location information to the following JSON format:
2294 *
2295 *   "position":"<position>",
2296 *   "line":"<line>",
2297 *   "column":"<column>",
2298 *
2299 * @param {SourceLocation} location The location to serialize, may be undefined.
2300 */
2301function serializeLocationFields (location, content) {
2302  if (!location) {
2303    return;
2304  }
2305  content.position = location.position;
2306  var line = location.line;
2307  if (!IS_UNDEFINED(line)) {
2308    content.line = line;
2309  }
2310  var column = location.column;
2311  if (!IS_UNDEFINED(column)) {
2312    content.column = column;
2313  }
2314}
2315
2316
2317/**
2318 * Serialize property information to the following JSON format for building the
2319 * array of properties.
2320 *
2321 *   {"name":"<property name>",
2322 *    "attributes":<number>,
2323 *    "propertyType":<number>,
2324 *    "ref":<number>}
2325 *
2326 * If the attribute for the property is PropertyAttribute.None it is not added.
2327 * If the propertyType for the property is PropertyType.Normal it is not added.
2328 * Here are a couple of examples.
2329 *
2330 *   {"name":"hello","ref":1}
2331 *   {"name":"length","attributes":7,"propertyType":3,"ref":2}
2332 *
2333 * @param {PropertyMirror} propertyMirror The property to serialize.
2334 * @returns {Object} Protocol object representing the property.
2335 */
2336JSONProtocolSerializer.prototype.serializeProperty_ = function(propertyMirror) {
2337  var result = {};
2338
2339  result.name = propertyMirror.name();
2340  var propertyValue = propertyMirror.value();
2341  if (this.inlineRefs_() && propertyValue.isValue()) {
2342    result.value = this.serializeReferenceWithDisplayData_(propertyValue);
2343  } else {
2344    if (propertyMirror.attributes() != PropertyAttribute.None) {
2345      result.attributes = propertyMirror.attributes();
2346    }
2347    if (propertyMirror.propertyType() != PropertyType.Normal) {
2348      result.propertyType = propertyMirror.propertyType();
2349    }
2350    result.ref = propertyValue.handle();
2351  }
2352  return result;
2353};
2354
2355
2356JSONProtocolSerializer.prototype.serializeFrame_ = function(mirror, content) {
2357  content.index = mirror.index();
2358  content.receiver = this.serializeReference(mirror.receiver());
2359  var func = mirror.func();
2360  content.func = this.serializeReference(func);
2361  if (func.script()) {
2362    content.script = this.serializeReference(func.script());
2363  }
2364  content.constructCall = mirror.isConstructCall();
2365  content.atReturn = mirror.isAtReturn();
2366  if (mirror.isAtReturn()) {
2367    content.returnValue = this.serializeReference(mirror.returnValue());
2368  }
2369  content.debuggerFrame = mirror.isDebuggerFrame();
2370  var x = new Array(mirror.argumentCount());
2371  for (var i = 0; i < mirror.argumentCount(); i++) {
2372    var arg = {};
2373    var argument_name = mirror.argumentName(i);
2374    if (argument_name) {
2375      arg.name = argument_name;
2376    }
2377    arg.value = this.serializeReference(mirror.argumentValue(i));
2378    x[i] = arg;
2379  }
2380  content.arguments = x;
2381  var x = new Array(mirror.localCount());
2382  for (var i = 0; i < mirror.localCount(); i++) {
2383    var local = {};
2384    local.name = mirror.localName(i);
2385    local.value = this.serializeReference(mirror.localValue(i));
2386    x[i] = local;
2387  }
2388  content.locals = x;
2389  serializeLocationFields(mirror.sourceLocation(), content);
2390  var source_line_text = mirror.sourceLineText();
2391  if (!IS_UNDEFINED(source_line_text)) {
2392    content.sourceLineText = source_line_text;
2393  }
2394
2395  content.scopes = [];
2396  for (var i = 0; i < mirror.scopeCount(); i++) {
2397    var scope = mirror.scope(i);
2398    content.scopes.push({
2399      type: scope.scopeType(),
2400      index: i
2401    });
2402  }
2403};
2404
2405
2406JSONProtocolSerializer.prototype.serializeScope_ = function(mirror, content) {
2407  content.index = mirror.scopeIndex();
2408  content.frameIndex = mirror.frameIndex();
2409  content.type = mirror.scopeType();
2410  content.object = this.inlineRefs_() ?
2411                   this.serializeValue(mirror.scopeObject()) :
2412                   this.serializeReference(mirror.scopeObject());
2413};
2414
2415
2416/**
2417 * Convert a number to a protocol value. For all finite numbers the number
2418 * itself is returned. For non finite numbers NaN, Infinite and
2419 * -Infinite the string representation "NaN", "Infinite" or "-Infinite"
2420 * (not including the quotes) is returned.
2421 *
2422 * @param {number} value The number value to convert to a protocol value.
2423 * @returns {number|string} Protocol value.
2424 */
2425function NumberToJSON_(value) {
2426  if (isNaN(value)) {
2427    return 'NaN';
2428  }
2429  if (!NUMBER_IS_FINITE(value)) {
2430    if (value > 0) {
2431      return 'Infinity';
2432    } else {
2433      return '-Infinity';
2434    }
2435  }
2436  return value;
2437}
2438