/
package.go
145 lines (122 loc) · 2.95 KB
/
package.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
133
134
135
136
137
138
139
140
141
142
143
144
145
package ir2
import (
"fmt"
"go/types"
"strings"
)
// Program that the package belongs to
func (pkg *Package) Program() *Program {
return pkg.prog
}
// funcs
// NewFunc adds a func to the list
func (pkg *Package) NewFunc(name string, sig *types.Signature) *Func {
fn := &Func{
Name: name,
FullName: pkg.genUniqueName(name),
Sig: sig,
}
fn.pkg = pkg
pkg.funcs = append(pkg.funcs, fn)
return fn
}
// Funcs returns a copy of the func list
func (pkg *Package) Funcs() []*Func {
return append([]*Func(nil), pkg.funcs...)
}
// Func finds a func by either Name or FullName
func (pkg *Package) Func(name string) *Func {
for _, fn := range pkg.funcs {
if fn.Name == name || fn.FullName == name {
return fn
}
}
return nil
}
// globals
// NewGlobal adds a global to the list
func (pkg *Package) NewGlobal(name string, typ types.Type) *Global {
glob := &Global{
Name: name,
FullName: pkg.genUniqueName(name),
Type: typ,
}
glob.pkg = pkg
pkg.globals = append(pkg.globals, glob)
return glob
}
// NewStringLiteral creates a global with a string literal value
func (pkg *Package) NewStringLiteral(funcname, str string) *Global {
glob := pkg.prog.strings[str]
if glob != nil {
return glob
}
// move to building a global as the string literal
name := pkg.makeUnique(funcname)
glob = pkg.NewGlobal(name, types.Typ[types.String])
glob.Value = ConstFor(str)
pkg.prog.registerStringLiteral(glob)
return glob
}
// Globals returns a copy of the global list
func (pkg *Package) Globals() []*Global {
return append([]*Global(nil), pkg.globals...)
}
// Global finds the Global by Name or FullName
func (pkg *Package) Global(name string) *Global {
for _, glob := range pkg.globals {
if glob.Name == name || glob.FullName == name {
return glob
}
}
return nil
}
// typedefs
// NewTypeDef adds a typedef to the list
func (pkg *Package) NewTypeDef(name string, typ types.Type) *TypeDef {
td := &TypeDef{
Name: name,
Type: typ,
}
td.pkg = pkg
pkg.typedefs = append(pkg.typedefs, td)
return td
}
// TypeDefs returns a copy of the func list
func (pkg *Package) TypeDefs() []*TypeDef {
return append([]*TypeDef(nil), pkg.typedefs...)
}
// TypeDef finds a func by either Name or FullName
func (pkg *Package) TypeDef(name string) *TypeDef {
for _, td := range pkg.typedefs {
if td.Name == name {
return td
}
}
return nil
}
// utils
func (pkg *Package) makeUnique(name string) string {
for i := 1; ; i++ {
uniq := fmt.Sprintf("%s_%d", name, i)
if pkg.Global(uniq) != nil {
continue
}
if pkg.Func(uniq) != nil {
continue
}
// todo: check types too
return uniq
}
}
func (pkg *Package) genUniqueName(name string) string {
name = strings.ReplaceAll(name, "$", "_")
parts := strings.Split(pkg.Path, "/")
fullName := fmt.Sprintf("%s__%s", pkg.Name, name)
for pkg.prog.takenNames[fullName] {
fullName = parts[len(parts)-1] + "_" + fullName
parts = parts[:len(parts)-1]
}
pkg.prog.claimName(fullName)
return fullName
}