1// Copyright 2008 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5"use strict";
6
7// A more universal stringify that supports more types than JSON.
8// Used by the d8 shell to output results.
9var stringifyDepthLimit = 4;  // To avoid crashing on cyclic objects
10
11// Hacky solution to circumvent forcing --allow-natives-syntax for d8
12function isProxy(o) { return false };
13function JSProxyGetTarget(proxy) { };
14function JSProxyGetHandler(proxy) { };
15
16try {
17  isProxy = Function(['object'], 'return %_IsJSProxy(object)');
18  JSProxyGetTarget = Function(['proxy'],
19    'return %JSProxyGetTarget(proxy)');
20  JSProxyGetHandler = Function(['proxy'],
21    'return %JSProxyGetHandler(proxy)');
22} catch(e) {};
23
24
25function Stringify(x, depth) {
26  if (depth === undefined)
27    depth = stringifyDepthLimit;
28  else if (depth === 0)
29    return "...";
30  if (isProxy(x)) {
31    return StringifyProxy(x, depth);
32  }
33  switch (typeof x) {
34    case "undefined":
35      return "undefined";
36    case "boolean":
37    case "number":
38    case "function":
39      return x.toString();
40    case "string":
41      return "\"" + x.toString() + "\"";
42    case "symbol":
43      return x.toString();
44    case "object":
45      if (IS_NULL(x)) return "null";
46      if (x.constructor && x.constructor.name === "Array") {
47        var elems = [];
48        for (var i = 0; i < x.length; ++i) {
49          elems.push(
50            {}.hasOwnProperty.call(x, i) ? Stringify(x[i], depth - 1) : "");
51        }
52        return "[" + elems.join(", ") + "]";
53      }
54      try {
55        var string = String(x);
56        if (string && string !== "[object Object]") return string;
57      } catch(e) {}
58      var props = [];
59      var names = Object.getOwnPropertyNames(x);
60      names = names.concat(Object.getOwnPropertySymbols(x));
61      for (var i in names) {
62        var name = names[i];
63        var desc = Object.getOwnPropertyDescriptor(x, name);
64        if (IS_UNDEFINED(desc)) continue;
65        if (IS_SYMBOL(name)) name = "[" + Stringify(name) + "]";
66        if ("value" in desc) {
67          props.push(name + ": " + Stringify(desc.value, depth - 1));
68        }
69        if (desc.get) {
70          var getter = Stringify(desc.get);
71          props.push("get " + name + getter.slice(getter.indexOf('(')));
72        }
73        if (desc.set) {
74          var setter = Stringify(desc.set);
75          props.push("set " + name + setter.slice(setter.indexOf('(')));
76        }
77      }
78      return "{" + props.join(", ") + "}";
79    default:
80      return "[crazy non-standard value]";
81  }
82}
83
84function StringifyProxy(proxy, depth) {
85  var proxy_type = typeof proxy;
86  var info_object = {
87    target: JSProxyGetTarget(proxy),
88    handler: JSProxyGetHandler(proxy)
89  }
90  return '[' + proxy_type + ' Proxy ' + Stringify(info_object, depth-1) + ']';
91}
92