-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathjson2ast.go
132 lines (113 loc) · 2.38 KB
/
json2ast.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package json2go
import (
"encoding/json"
"go/ast"
"go/token"
"io"
"reflect"
"sort"
"strings"
)
func convertMap(name string, v map[string]interface{}) ([]ast.Decl, error) {
var err error
var fields []*ast.Field
var nestedDecls []ast.Decl
var i int
var vKeys []string
output := make([]ast.Decl, 0)
vKeys = make([]string, len(v))
i = 0
for k, _ := range v {
vKeys[i] = k
i++
}
sort.Strings(vKeys)
for _, key := range vKeys {
var t ast.Expr
valueType := reflect.TypeOf(v[key])
switch valueType.Kind() {
case reflect.Map:
tName := strings.Title(key)
if nestedDecls, err = convertMap(tName, v[key].(map[string]interface{})); err != nil {
return nil, err
}
for _, nestedDecl := range nestedDecls {
output = append(output, nestedDecl)
}
t = &ast.StarExpr{
X: ast.NewIdent(tName),
}
case reflect.Slice:
slice := v[key].([]interface{})
if len(slice) == 0 {
t = &ast.InterfaceType{
Methods: &ast.FieldList{},
}
break
}
sliceType := reflect.TypeOf(slice[0])
switch sliceType.Kind() {
case reflect.Map:
tName := strings.Title(key)
if nestedDecls, err = convertMap(tName, slice[0].(map[string]interface{})); err != nil {
return nil, err
}
for _, nestedDecl := range nestedDecls {
output = append(output, nestedDecl)
}
t = &ast.StarExpr{
X: ast.NewIdent(tName),
}
default:
t = ast.NewIdent(sliceType.String())
}
t = &ast.ArrayType{
Elt: t,
}
default:
t = ast.NewIdent(reflect.TypeOf(v[key]).String())
}
fields = append(fields, &ast.Field{
Names: []*ast.Ident{
&ast.Ident{
Name: key,
NamePos: token.NoPos,
Obj: ast.NewObj(ast.Var, key),
},
},
Type: t,
})
}
output = append(output, &ast.GenDecl{
Tok: token.TYPE,
Specs: []ast.Spec{
&ast.TypeSpec{
Name: ast.NewIdent(name),
Type: &ast.StructType{
Fields: &ast.FieldList{
List: fields,
},
},
},
},
})
return output, err
}
func Json2Ast(jsonReader io.Reader) (*ast.File, error) {
var v map[string]interface{}
var file *ast.File
var err error
dec := json.NewDecoder(jsonReader)
file = &ast.File{
Name: ast.NewIdent("main"),
}
if err := dec.Decode(&v); err != nil {
return nil, err
}
var decls []ast.Decl
if decls, err = convertMap("Top", v); err != nil {
return nil, err
}
file.Decls = decls
return file, nil
}