/
parameter_type.go
132 lines (122 loc) · 3.12 KB
/
parameter_type.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 dicon
import (
"fmt"
"go/ast"
"go/token"
"log"
"regexp"
"strings"
)
type ParameterType struct {
DeclaredPackageName string
src ast.Expr
}
func NewParameterType(packageName string, expr ast.Expr) *ParameterType {
return &ParameterType{
DeclaredPackageName: packageName,
src: expr,
}
}
func (p *ParameterType) ConvertName(packageName string) string {
return convertName(p.DeclaredPackageName, packageName, p.src)
}
func (p *ParameterType) SimpleName() string {
switch n := p.src.(type) {
case *ast.SelectorExpr:
return n.Sel.Name
case *ast.Ident:
return n.Name
}
panic("unreachable")
}
func convertName(declared, packageName string, expr ast.Expr) string {
switch ex := expr.(type) {
case *ast.Ident:
name := ex.Name
if isPrimitive(name) {
return name
}
selector := relativeSelectorName(declared, packageName, "")
return buildTypeName(selector, name)
case *ast.SelectorExpr:
selector := relativeSelectorName(declared, packageName, fmt.Sprintf("%v", ex.X))
typ := ex.Sel.Name
return buildTypeName(selector, typ)
case *ast.ArrayType:
return "[]" + convertName(declared, packageName, ex.Elt)
case *ast.StarExpr:
return "*" + convertName(declared, packageName, ex.X)
case *ast.MapType:
return fmt.Sprintf("map[%s]%s", convertName(declared, packageName, ex.Key), convertName(declared, packageName, ex.Value))
case *ast.InterfaceType:
return "interface{}"
case *ast.StructType:
return "struct{}"
case *ast.ChanType:
var ch string
if token.Pos(ex.Arrow) == token.NoPos {
ch = "chan "
} else if ex.Dir == ast.SEND {
ch = "chan<- "
} else if ex.Dir == ast.RECV {
ch = "<-chan "
} else {
log.Fatalf("unknown chan type %+v", ex)
}
return ch + convertName(declared, packageName, ex.Value)
case *ast.FuncType:
var args []string
for i, a := range ex.Params.List {
if len(a.Names) == 1 {
args = append(args, fmt.Sprintf("a%d %s", i, convertName(declared, packageName, a.Type)))
} else {
ty := convertName(declared, packageName, a.Type)
for j := range a.Names {
args = append(args, fmt.Sprintf("a%d%d %s", i, j, ty))
}
}
}
var rets []string
for _, r := range ex.Results.List {
rets = append(rets, convertName(declared, packageName, r.Type))
}
arg := "(" + strings.Join(args, ", ") + ")"
var ret string
if len(rets) > 1 {
ret = "(" + strings.Join(rets, ", ") + ")"
} else {
ret = strings.Join(rets, "")
}
return "func" + arg + " " + ret
case *ast.Ellipsis:
return "..." + convertName(declared, packageName, ex.Elt)
default:
log.Fatalf("unsupported type %+v", expr)
}
return ""
}
var reg = regexp.MustCompile("^[a-z].*")
func isPrimitive(in string) bool {
return reg.MatchString(in)
}
func relativeSelectorName(declared, current, selector string) string {
if declared == current {
return selector
}
if selector == current {
return ""
}
if declared != current && selector == "" {
return declared
}
if declared != current && selector != "" {
return selector
}
return ""
}
func buildTypeName(selector, name string) string {
if selector == "" {
return name
}
return selector + "." + name
}