1
2
3
4
5
6
7
8
9 package main
10
11 import (
12 "bytes"
13 "flag"
14 "fmt"
15 "go/ast"
16 "go/format"
17 "go/parser"
18 "go/token"
19 "io"
20 "log"
21 "os"
22 "path/filepath"
23 "strconv"
24 "strings"
25 )
26
27 var stdout = flag.Bool("stdout", false, "write to stdout instead of builtin.go")
28 var nofmt = flag.Bool("nofmt", false, "skip formatting builtin.go")
29
30 func main() {
31 flag.Parse()
32
33 var b bytes.Buffer
34 fmt.Fprintln(&b, "// Code generated by mkbuiltin.go. DO NOT EDIT.")
35 fmt.Fprintln(&b)
36 fmt.Fprintln(&b, "package typecheck")
37 fmt.Fprintln(&b)
38 fmt.Fprintln(&b, `import (`)
39 fmt.Fprintln(&b, ` "cmd/compile/internal/types"`)
40 fmt.Fprintln(&b, ` "cmd/internal/src"`)
41 fmt.Fprintln(&b, `)`)
42
43 fmt.Fprintln(&b, `
44 // Not inlining this function removes a significant chunk of init code.
45 //go:noinline
46 func newSig(params, results []*types.Field) *types.Type {
47 return types.NewSignature(nil, params, results)
48 }
49
50 func params(tlist ...*types.Type) []*types.Field {
51 flist := make([]*types.Field, len(tlist))
52 for i, typ := range tlist {
53 flist[i] = types.NewField(src.NoXPos, nil, typ)
54 }
55 return flist
56 }
57 `)
58
59 mkbuiltin(&b, "runtime")
60 mkbuiltin(&b, "coverage")
61
62 var err error
63 out := b.Bytes()
64 if !*nofmt {
65 out, err = format.Source(out)
66 if err != nil {
67 log.Fatal(err)
68 }
69 }
70 if *stdout {
71 _, err = os.Stdout.Write(out)
72 } else {
73 err = os.WriteFile("builtin.go", out, 0666)
74 }
75 if err != nil {
76 log.Fatal(err)
77 }
78 }
79
80 func mkbuiltin(w io.Writer, name string) {
81 fset := token.NewFileSet()
82 f, err := parser.ParseFile(fset, filepath.Join("_builtin", name+".go"), nil, 0)
83 if err != nil {
84 log.Fatal(err)
85 }
86
87 var interner typeInterner
88
89 fmt.Fprintf(w, "var %sDecls = [...]struct { name string; tag int; typ int }{\n", name)
90 for _, decl := range f.Decls {
91 switch decl := decl.(type) {
92 case *ast.FuncDecl:
93 if decl.Recv != nil {
94 log.Fatal("methods unsupported")
95 }
96 if decl.Body != nil {
97 log.Fatal("unexpected function body")
98 }
99 fmt.Fprintf(w, "{%q, funcTag, %d},\n", decl.Name.Name, interner.intern(decl.Type))
100 case *ast.GenDecl:
101 if decl.Tok == token.IMPORT {
102 if len(decl.Specs) != 1 || decl.Specs[0].(*ast.ImportSpec).Path.Value != "\"unsafe\"" {
103 log.Fatal("runtime cannot import other package")
104 }
105 continue
106 }
107 if decl.Tok != token.VAR {
108 log.Fatal("unhandled declaration kind", decl.Tok)
109 }
110 for _, spec := range decl.Specs {
111 spec := spec.(*ast.ValueSpec)
112 if len(spec.Values) != 0 {
113 log.Fatal("unexpected values")
114 }
115 typ := interner.intern(spec.Type)
116 for _, name := range spec.Names {
117 fmt.Fprintf(w, "{%q, varTag, %d},\n", name.Name, typ)
118 }
119 }
120 default:
121 log.Fatal("unhandled decl type", decl)
122 }
123 }
124 fmt.Fprintln(w, "}")
125
126 fmt.Fprintln(w)
127 fmt.Fprintf(w, "func %sTypes() []*types.Type {\n", name)
128 fmt.Fprintf(w, "var typs [%d]*types.Type\n", len(interner.typs))
129 for i, typ := range interner.typs {
130 fmt.Fprintf(w, "typs[%d] = %s\n", i, typ)
131 }
132 fmt.Fprintln(w, "return typs[:]")
133 fmt.Fprintln(w, "}")
134 }
135
136
137
138
139 type typeInterner struct {
140 typs []string
141 hash map[string]int
142 }
143
144 func (i *typeInterner) intern(t ast.Expr) int {
145 x := i.mktype(t)
146 v, ok := i.hash[x]
147 if !ok {
148 v = len(i.typs)
149 if i.hash == nil {
150 i.hash = make(map[string]int)
151 }
152 i.hash[x] = v
153 i.typs = append(i.typs, x)
154 }
155 return v
156 }
157
158 func (i *typeInterner) subtype(t ast.Expr) string {
159 return fmt.Sprintf("typs[%d]", i.intern(t))
160 }
161
162 func (i *typeInterner) mktype(t ast.Expr) string {
163 switch t := t.(type) {
164 case *ast.Ident:
165 switch t.Name {
166 case "byte":
167 return "types.ByteType"
168 case "rune":
169 return "types.RuneType"
170 }
171 return fmt.Sprintf("types.Types[types.T%s]", strings.ToUpper(t.Name))
172 case *ast.SelectorExpr:
173 if t.X.(*ast.Ident).Name != "unsafe" || t.Sel.Name != "Pointer" {
174 log.Fatalf("unhandled type: %#v", t)
175 }
176 return "types.Types[types.TUNSAFEPTR]"
177
178 case *ast.ArrayType:
179 if t.Len == nil {
180 return fmt.Sprintf("types.NewSlice(%s)", i.subtype(t.Elt))
181 }
182 return fmt.Sprintf("types.NewArray(%s, %d)", i.subtype(t.Elt), intconst(t.Len))
183 case *ast.ChanType:
184 dir := "types.Cboth"
185 switch t.Dir {
186 case ast.SEND:
187 dir = "types.Csend"
188 case ast.RECV:
189 dir = "types.Crecv"
190 }
191 return fmt.Sprintf("types.NewChan(%s, %s)", i.subtype(t.Value), dir)
192 case *ast.FuncType:
193 return fmt.Sprintf("newSig(%s, %s)", i.fields(t.Params, false), i.fields(t.Results, false))
194 case *ast.InterfaceType:
195 if len(t.Methods.List) != 0 {
196 log.Fatal("non-empty interfaces unsupported")
197 }
198 return "types.Types[types.TINTER]"
199 case *ast.MapType:
200 return fmt.Sprintf("types.NewMap(%s, %s)", i.subtype(t.Key), i.subtype(t.Value))
201 case *ast.StarExpr:
202 return fmt.Sprintf("types.NewPtr(%s)", i.subtype(t.X))
203 case *ast.StructType:
204 return fmt.Sprintf("types.NewStruct(%s)", i.fields(t.Fields, true))
205
206 default:
207 log.Fatalf("unhandled type: %#v", t)
208 panic("unreachable")
209 }
210 }
211
212 func (i *typeInterner) fields(fl *ast.FieldList, keepNames bool) string {
213 if fl == nil || len(fl.List) == 0 {
214 return "nil"
215 }
216
217 var res []string
218 for _, f := range fl.List {
219 typ := i.subtype(f.Type)
220 if len(f.Names) == 0 {
221 res = append(res, typ)
222 } else {
223 for _, name := range f.Names {
224 if keepNames {
225 res = append(res, fmt.Sprintf("types.NewField(src.NoXPos, Lookup(%q), %s)", name.Name, typ))
226 } else {
227 res = append(res, typ)
228 }
229 }
230 }
231 }
232
233 if keepNames {
234 return fmt.Sprintf("[]*types.Field{%s}", strings.Join(res, ", "))
235 }
236 return fmt.Sprintf("params(%s)", strings.Join(res, ", "))
237 }
238
239 func intconst(e ast.Expr) int64 {
240 switch e := e.(type) {
241 case *ast.BasicLit:
242 if e.Kind != token.INT {
243 log.Fatalf("expected INT, got %v", e.Kind)
244 }
245 x, err := strconv.ParseInt(e.Value, 0, 64)
246 if err != nil {
247 log.Fatal(err)
248 }
249 return x
250 default:
251 log.Fatalf("unhandled expr: %#v", e)
252 panic("unreachable")
253 }
254 }
255
View as plain text