forked from Joker/jade
/
go_ast_wstr.go
121 lines (107 loc) · 2.46 KB
/
go_ast_wstr.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
package main
import (
"bytes"
"fmt"
"go/ast"
"strings"
)
func (a *goAST) collapseWriteString(strInline bool, constName string) {
// ast.Print(a.fset, a.node)
var wrSt = writeStrings{inline: strInline, constName: constName}
ast.Inspect(a.node, func(n ast.Node) bool {
if n != nil {
switch x := n.(type) {
case *ast.CaseClause:
wrSt.push(x.Body)
case *ast.BlockStmt:
wrSt.push(x.List)
// case *ast.CallExpr:
// return false
}
}
return true
})
wrSt.fillConstNode(a.node.Decls)
}
//
type writeStrings struct {
constSlice []struct {
str string
name string
}
constName string
constCount int
inline bool
}
func (ws *writeStrings) push(in []ast.Stmt) {
type wStr struct {
s string
a *ast.CallExpr
z *ast.Stmt
}
List := [][]wStr{}
subList := make([]wStr, 0, 4)
for k, ex := range in {
if es, ok := ex.(*ast.ExprStmt); ok {
if ce, ok := es.X.(*ast.CallExpr); ok {
if fun, ok := ce.Fun.(*ast.SelectorExpr); ok && len(ce.Args) == 1 && fun.Sel.Name == "WriteString" {
if arg, ok := ce.Args[0].(*ast.BasicLit); ok {
subList = append(subList, wStr{s: strings.Trim(arg.Value, "`"), a: ce, z: &in[k]})
continue
}
}
}
}
if len(subList) > 0 {
List = append(List, subList)
subList = make([]wStr, 0, 4)
}
}
if len(subList) > 0 {
List = append(List, subList)
}
//
var st = new(bytes.Buffer)
for _, block := range List {
st.WriteString(block[0].s)
for i := 1; i < len(block); i++ {
st.WriteString(block[i].s)
*block[i].z = new(ast.EmptyStmt) // remove a node
}
if ws.inline {
block[0].a.Args[0].(*ast.BasicLit).Value = "`" + st.String() + "`"
} else {
str := st.String()
if name, ok := dict[str]; ok {
block[0].a.Args = []ast.Expr{&ast.Ident{Name: name}}
} else {
newName := fmt.Sprintf("%s__%d", ws.constName, ws.constCount)
block[0].a.Args = []ast.Expr{&ast.Ident{Name: newName}}
dict[str] = newName
ws.constSlice = append(ws.constSlice, struct {
str string
name string
}{
str,
newName,
})
}
}
st.Reset()
ws.constCount += 1
}
}
func (ws *writeStrings) fillConstNode(decl []ast.Decl) {
if constNode, ok := decl[1].(*ast.GenDecl); ok && !ws.inline {
for _, v := range ws.constSlice {
constNode.Specs = append(constNode.Specs, &ast.ValueSpec{
Names: []*ast.Ident{
{Name: v.name},
},
Values: []ast.Expr{
&ast.BasicLit{Kind: 9, Value: "`" + v.str + "`"}, // 9 => string
},
})
}
}
}