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