-
Notifications
You must be signed in to change notification settings - Fork 95
/
Copy pathdump.go
116 lines (110 loc) · 2.57 KB
/
dump.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Copyright 2018 The go-python Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ast
import (
"fmt"
"reflect"
"strings"
"github.com/go-python/gpython/py"
)
func dumpItem(v interface{}) string {
if v == nil {
return "None"
}
switch x := v.(type) {
case py.String:
return fmt.Sprintf("'%s'", string(x))
case py.Bytes:
return fmt.Sprintf("b'%s'", string(x))
case Identifier:
if x == "" {
return "None"
}
return fmt.Sprintf("'%s'", string(x))
case *Keyword:
return dump(x, "keyword")
case *WithItem:
return dump(x, "withitem")
case *Arguments:
if x == nil {
return "None"
}
return dump(x, "arguments")
case *Arg:
if x == nil {
return "None"
}
return dump(x, "arg")
case ModBase:
case StmtBase:
case ExprBase:
case SliceBase:
case Pos:
case *Alias:
return dump(v, "alias")
case Ast:
return Dump(x)
case py.I__str__:
str, err := x.M__str__()
if err != nil {
panic(err)
}
return string(str.(py.String))
case Comprehension:
return dump(v, "comprehension")
}
return fmt.Sprintf("%v", v)
}
// Dump ast as a string with name
func dump(ast interface{}, name string) string {
astValue := reflect.Indirect(reflect.ValueOf(ast))
astType := astValue.Type()
args := make([]string, 0)
for i := 0; i < astType.NumField(); i++ {
fieldType := astType.Field(i)
fieldValue := astValue.Field(i)
fname := strings.ToLower(fieldType.Name)
switch fname {
case "stmtbase", "exprbase", "modbase", "slicebase", "pos":
continue
case "exprtype":
fname = "type"
case "contextexpr":
fname = "context_expr"
case "optionalvars":
fname = "optional_vars"
case "kwdefaults":
fname = "kw_defaults"
case "decoratorlist":
fname = "decorator_list"
}
if fieldValue.Kind() == reflect.Slice && fieldValue.Type().Elem().Kind() != reflect.Uint8 {
strs := make([]string, fieldValue.Len())
for i := 0; i < fieldValue.Len(); i++ {
element := fieldValue.Index(i)
if element.CanInterface() {
v := element.Interface()
strs[i] = dumpItem(v)
}
}
args = append(args, fmt.Sprintf("%s=[%s]", fname, strings.Join(strs, ", ")))
} else if fieldValue.CanInterface() {
v := fieldValue.Interface()
args = append(args, fmt.Sprintf("%s=%s", fname, dumpItem(v)))
}
}
return fmt.Sprintf("%s(%s)", name, strings.Join(args, ", "))
}
// Dump an Ast node as a string
func Dump(ast Ast) string {
if ast == nil {
return "<nil>"
}
name := ast.Type().Name
switch name {
case "ExprStmt":
name = "Expr"
}
return dump(ast, name)
}