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