1
2
3
4
5
6
7
8 package main
9
10 import (
11 "bytes"
12 "fmt"
13 "go/format"
14 "go/types"
15 "io/ioutil"
16 "log"
17 "reflect"
18 "sort"
19 "strings"
20
21 "golang.org/x/tools/go/packages"
22 )
23
24 var irPkg *types.Package
25 var buf bytes.Buffer
26
27 func main() {
28 cfg := &packages.Config{
29 Mode: packages.NeedSyntax | packages.NeedTypes,
30 }
31 pkgs, err := packages.Load(cfg, "cmd/compile/internal/ir")
32 if err != nil {
33 log.Fatal(err)
34 }
35 irPkg = pkgs[0].Types
36
37 fmt.Fprintln(&buf, "// Code generated by mknode.go. DO NOT EDIT.")
38 fmt.Fprintln(&buf)
39 fmt.Fprintln(&buf, "package ir")
40 fmt.Fprintln(&buf)
41 fmt.Fprintln(&buf, `import "fmt"`)
42
43 scope := irPkg.Scope()
44 for _, name := range scope.Names() {
45 if strings.HasPrefix(name, "mini") {
46 continue
47 }
48
49 obj, ok := scope.Lookup(name).(*types.TypeName)
50 if !ok {
51 continue
52 }
53 typ := obj.Type().(*types.Named)
54 if !implementsNode(types.NewPointer(typ)) {
55 continue
56 }
57
58 fmt.Fprintf(&buf, "\n")
59 fmt.Fprintf(&buf, "func (n *%s) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }\n", name)
60
61 switch name {
62 case "Name", "Func":
63
64 continue
65 }
66
67 forNodeFields(typ,
68 "func (n *%[1]s) copy() Node { c := *n\n",
69 "",
70 "c.%[1]s = copy%[2]s(c.%[1]s)",
71 "return &c }\n")
72
73 forNodeFields(typ,
74 "func (n *%[1]s) doChildren(do func(Node) bool) bool {\n",
75 "if n.%[1]s != nil && do(n.%[1]s) { return true }",
76 "if do%[2]s(n.%[1]s, do) { return true }",
77 "return false }\n")
78
79 forNodeFields(typ,
80 "func (n *%[1]s) editChildren(edit func(Node) Node) {\n",
81 "if n.%[1]s != nil { n.%[1]s = edit(n.%[1]s).(%[2]s) }",
82 "edit%[2]s(n.%[1]s, edit)",
83 "}\n")
84 }
85
86 makeHelpers()
87
88 out, err := format.Source(buf.Bytes())
89 if err != nil {
90
91 out = buf.Bytes()
92 }
93
94 err = ioutil.WriteFile("node_gen.go", out, 0666)
95 if err != nil {
96 log.Fatal(err)
97 }
98 }
99
100
101
102 var needHelper = map[string]string{}
103
104 func makeHelpers() {
105 var names []string
106 for name := range needHelper {
107 names = append(names, name)
108 }
109 sort.Strings(names)
110
111 for _, name := range names {
112 fmt.Fprintf(&buf, sliceHelperTmpl, name, needHelper[name])
113 }
114 }
115
116 const sliceHelperTmpl = `
117 func copy%[1]s(list []%[2]s) []%[2]s {
118 if list == nil {
119 return nil
120 }
121 c := make([]%[2]s, len(list))
122 copy(c, list)
123 return c
124 }
125 func do%[1]s(list []%[2]s, do func(Node) bool) bool {
126 for _, x := range list {
127 if x != nil && do(x) {
128 return true
129 }
130 }
131 return false
132 }
133 func edit%[1]s(list []%[2]s, edit func(Node) Node) {
134 for i, x := range list {
135 if x != nil {
136 list[i] = edit(x).(%[2]s)
137 }
138 }
139 }
140 `
141
142 func forNodeFields(named *types.Named, prologue, singleTmpl, sliceTmpl, epilogue string) {
143 fmt.Fprintf(&buf, prologue, named.Obj().Name())
144
145 anyField(named.Underlying().(*types.Struct), func(f *types.Var) bool {
146 if f.Embedded() {
147 return false
148 }
149 name, typ := f.Name(), f.Type()
150
151 slice, _ := typ.Underlying().(*types.Slice)
152 if slice != nil {
153 typ = slice.Elem()
154 }
155
156 tmpl, what := singleTmpl, types.TypeString(typ, types.RelativeTo(irPkg))
157 if implementsNode(typ) {
158 if slice != nil {
159 helper := strings.TrimPrefix(what, "*") + "s"
160 needHelper[helper] = what
161 tmpl, what = sliceTmpl, helper
162 }
163 } else if what == "*Field" {
164
165 tmpl = sliceTmpl
166 if slice != nil {
167 what = "Fields"
168 } else {
169 what = "Field"
170 }
171 } else {
172 return false
173 }
174
175 if tmpl == "" {
176 return false
177 }
178
179
180
181 s := fmt.Sprintf(tmpl+"\x00 %[1]s %[2]s", name, what)
182 fmt.Fprintln(&buf, s[:strings.LastIndex(s, "\x00")])
183 return false
184 })
185
186 fmt.Fprintf(&buf, epilogue)
187 }
188
189 func implementsNode(typ types.Type) bool {
190 if _, ok := typ.Underlying().(*types.Interface); ok {
191
192
193 return true
194 }
195
196 if ptr, ok := typ.(*types.Pointer); ok {
197 if str, ok := ptr.Elem().Underlying().(*types.Struct); ok {
198 return anyField(str, func(f *types.Var) bool {
199 return f.Embedded() && f.Name() == "miniNode"
200 })
201 }
202 }
203
204 return false
205 }
206
207 func anyField(typ *types.Struct, pred func(f *types.Var) bool) bool {
208 for i, n := 0, typ.NumFields(); i < n; i++ {
209 if value, ok := reflect.StructTag(typ.Tag(i)).Lookup("mknode"); ok {
210 if value != "-" {
211 panic(fmt.Sprintf("unexpected tag value: %q", value))
212 }
213 continue
214 }
215
216 f := typ.Field(i)
217 if pred(f) {
218 return true
219 }
220 if f.Embedded() {
221 if typ, ok := f.Type().Underlying().(*types.Struct); ok {
222 if anyField(typ, pred) {
223 return true
224 }
225 }
226 }
227 }
228 return false
229 }
230
View as plain text