github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/internal/jsre/pretty.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2016 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package jsre
    26  
    27  import (
    28  	"fmt"
    29  	"io"
    30  	"sort"
    31  	"strconv"
    32  	"strings"
    33  
    34  	"github.com/fatih/color"
    35  	"github.com/robertkrimen/otto"
    36  )
    37  
    38  const (
    39  	maxPrettyPrintLevel = 3
    40  	indentString        = "  "
    41  )
    42  
    43  var (
    44  	FunctionColor = color.New(color.FgMagenta).SprintfFunc()
    45  	SpecialColor  = color.New(color.Bold).SprintfFunc()
    46  	NumberColor   = color.New(color.FgRed).SprintfFunc()
    47  	StringColor   = color.New(color.FgGreen).SprintfFunc()
    48  	ErrorColor    = color.New(color.FgHiRed).SprintfFunc()
    49  )
    50  
    51  //打印对象时隐藏这些字段。
    52  var boringKeys = map[string]bool{
    53  	"valueOf":              true,
    54  	"toString":             true,
    55  	"toLocaleString":       true,
    56  	"hasOwnProperty":       true,
    57  	"isPrototypeOf":        true,
    58  	"propertyIsEnumerable": true,
    59  	"constructor":          true,
    60  }
    61  
    62  //预打印将值写入标准输出。
    63  func prettyPrint(vm *otto.Otto, value otto.Value, w io.Writer) {
    64  	ppctx{vm: vm, w: w}.printValue(value, 0, false)
    65  }
    66  
    67  //PrettyError将错误写入标准输出。
    68  func prettyError(vm *otto.Otto, err error, w io.Writer) {
    69  	failure := err.Error()
    70  	if ottoErr, ok := err.(*otto.Error); ok {
    71  		failure = ottoErr.String()
    72  	}
    73  	fmt.Fprint(w, ErrorColor("%s", failure))
    74  }
    75  
    76  func (re *JSRE) prettyPrintJS(call otto.FunctionCall) otto.Value {
    77  	for _, v := range call.ArgumentList {
    78  		prettyPrint(call.Otto, v, re.output)
    79  		fmt.Fprintln(re.output)
    80  	}
    81  	return otto.UndefinedValue()
    82  }
    83  
    84  type ppctx struct {
    85  	vm *otto.Otto
    86  	w  io.Writer
    87  }
    88  
    89  func (ctx ppctx) indent(level int) string {
    90  	return strings.Repeat(indentString, level)
    91  }
    92  
    93  func (ctx ppctx) printValue(v otto.Value, level int, inArray bool) {
    94  	switch {
    95  	case v.IsObject():
    96  		ctx.printObject(v.Object(), level, inArray)
    97  	case v.IsNull():
    98  		fmt.Fprint(ctx.w, SpecialColor("null"))
    99  	case v.IsUndefined():
   100  		fmt.Fprint(ctx.w, SpecialColor("undefined"))
   101  	case v.IsString():
   102  		s, _ := v.ToString()
   103  		fmt.Fprint(ctx.w, StringColor("%q", s))
   104  	case v.IsBoolean():
   105  		b, _ := v.ToBoolean()
   106  		fmt.Fprint(ctx.w, SpecialColor("%t", b))
   107  	case v.IsNaN():
   108  		fmt.Fprint(ctx.w, NumberColor("NaN"))
   109  	case v.IsNumber():
   110  		s, _ := v.ToString()
   111  		fmt.Fprint(ctx.w, NumberColor("%s", s))
   112  	default:
   113  		fmt.Fprint(ctx.w, "<unprintable>")
   114  	}
   115  }
   116  
   117  func (ctx ppctx) printObject(obj *otto.Object, level int, inArray bool) {
   118  	switch obj.Class() {
   119  	case "Array", "GoArray":
   120  		lv, _ := obj.Get("length")
   121  		len, _ := lv.ToInteger()
   122  		if len == 0 {
   123  			fmt.Fprintf(ctx.w, "[]")
   124  			return
   125  		}
   126  		if level > maxPrettyPrintLevel {
   127  			fmt.Fprint(ctx.w, "[...]")
   128  			return
   129  		}
   130  		fmt.Fprint(ctx.w, "[")
   131  		for i := int64(0); i < len; i++ {
   132  			el, err := obj.Get(strconv.FormatInt(i, 10))
   133  			if err == nil {
   134  				ctx.printValue(el, level+1, true)
   135  			}
   136  			if i < len-1 {
   137  				fmt.Fprintf(ctx.w, ", ")
   138  			}
   139  		}
   140  		fmt.Fprint(ctx.w, "]")
   141  
   142  	case "Object":
   143  //将bignumber.js中的值打印为常规数字。
   144  		if ctx.isBigNumber(obj) {
   145  			fmt.Fprint(ctx.w, NumberColor("%s", toString(obj)))
   146  			return
   147  		}
   148  //否则,打印所有缩进的字段,但如果太深则停止。
   149  		keys := ctx.fields(obj)
   150  		if len(keys) == 0 {
   151  			fmt.Fprint(ctx.w, "{}")
   152  			return
   153  		}
   154  		if level > maxPrettyPrintLevel {
   155  			fmt.Fprint(ctx.w, "{...}")
   156  			return
   157  		}
   158  		fmt.Fprintln(ctx.w, "{")
   159  		for i, k := range keys {
   160  			v, _ := obj.Get(k)
   161  			fmt.Fprintf(ctx.w, "%s%s: ", ctx.indent(level+1), k)
   162  			ctx.printValue(v, level+1, false)
   163  			if i < len(keys)-1 {
   164  				fmt.Fprintf(ctx.w, ",")
   165  			}
   166  			fmt.Fprintln(ctx.w)
   167  		}
   168  		if inArray {
   169  			level--
   170  		}
   171  		fmt.Fprintf(ctx.w, "%s}", ctx.indent(level))
   172  
   173  	case "Function":
   174  //如果可能,使用ToString()显示参数列表。
   175  		if robj, err := obj.Call("toString"); err != nil {
   176  			fmt.Fprint(ctx.w, FunctionColor("function()"))
   177  		} else {
   178  			desc := strings.Trim(strings.Split(robj.String(), "{")[0], " \t\n")
   179  			desc = strings.Replace(desc, " (", "(", 1)
   180  			fmt.Fprint(ctx.w, FunctionColor("%s", desc))
   181  		}
   182  
   183  	case "RegExp":
   184  		fmt.Fprint(ctx.w, StringColor("%s", toString(obj)))
   185  
   186  	default:
   187  		if v, _ := obj.Get("toString"); v.IsFunction() && level <= maxPrettyPrintLevel {
   188  			s, _ := obj.Call("toString")
   189  			fmt.Fprintf(ctx.w, "<%s %s>", obj.Class(), s.String())
   190  		} else {
   191  			fmt.Fprintf(ctx.w, "<%s>", obj.Class())
   192  		}
   193  	}
   194  }
   195  
   196  func (ctx ppctx) fields(obj *otto.Object) []string {
   197  	var (
   198  		vals, methods []string
   199  		seen          = make(map[string]bool)
   200  	)
   201  	add := func(k string) {
   202  		if seen[k] || boringKeys[k] || strings.HasPrefix(k, "_") {
   203  			return
   204  		}
   205  		seen[k] = true
   206  		if v, _ := obj.Get(k); v.IsFunction() {
   207  			methods = append(methods, k)
   208  		} else {
   209  			vals = append(vals, k)
   210  		}
   211  	}
   212  	iterOwnAndConstructorKeys(ctx.vm, obj, add)
   213  	sort.Strings(vals)
   214  	sort.Strings(methods)
   215  	return append(vals, methods...)
   216  }
   217  
   218  func iterOwnAndConstructorKeys(vm *otto.Otto, obj *otto.Object, f func(string)) {
   219  	seen := make(map[string]bool)
   220  	iterOwnKeys(vm, obj, func(prop string) {
   221  		seen[prop] = true
   222  		f(prop)
   223  	})
   224  	if cp := constructorPrototype(obj); cp != nil {
   225  		iterOwnKeys(vm, cp, func(prop string) {
   226  			if !seen[prop] {
   227  				f(prop)
   228  			}
   229  		})
   230  	}
   231  }
   232  
   233  func iterOwnKeys(vm *otto.Otto, obj *otto.Object, f func(string)) {
   234  	Object, _ := vm.Object("Object")
   235  	rv, _ := Object.Call("getOwnPropertyNames", obj.Value())
   236  	gv, _ := rv.Export()
   237  	switch gv := gv.(type) {
   238  	case []interface{}:
   239  		for _, v := range gv {
   240  			f(v.(string))
   241  		}
   242  	case []string:
   243  		for _, v := range gv {
   244  			f(v)
   245  		}
   246  	default:
   247  		panic(fmt.Errorf("Object.getOwnPropertyNames returned unexpected type %T", gv))
   248  	}
   249  }
   250  
   251  func (ctx ppctx) isBigNumber(v *otto.Object) bool {
   252  //使用自定义构造函数处理数字。
   253  	if v, _ := v.Get("constructor"); v.Object() != nil {
   254  		if strings.HasPrefix(toString(v.Object()), "function BigNumber") {
   255  			return true
   256  		}
   257  	}
   258  //处理默认构造函数。
   259  	BigNumber, _ := ctx.vm.Object("BigNumber.prototype")
   260  	if BigNumber == nil {
   261  		return false
   262  	}
   263  	bv, _ := BigNumber.Call("isPrototypeOf", v)
   264  	b, _ := bv.ToBoolean()
   265  	return b
   266  }
   267  
   268  func toString(obj *otto.Object) string {
   269  	s, _ := obj.Call("toString")
   270  	return s.String()
   271  }
   272  
   273  func constructorPrototype(obj *otto.Object) *otto.Object {
   274  	if v, _ := obj.Get("constructor"); v.Object() != nil {
   275  		if v, _ = v.Object().Get("prototype"); v.Object() != nil {
   276  			return v.Object()
   277  		}
   278  	}
   279  	return nil
   280  }