1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build ignore 6 7 // Generate builtin.go from builtin/runtime.go. 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, "// AUTO-GENERATED by mkbuiltin.go; DO NOT EDIT") 35 fmt.Fprintln(&b) 36 fmt.Fprintln(&b, "package gc") 37 38 mkbuiltin(&b, "runtime") 39 40 out, err := format.Source(b.Bytes()) 41 if err != nil { 42 log.Fatal(err) 43 } 44 if *stdout { 45 _, err = os.Stdout.Write(out) 46 } else { 47 err = ioutil.WriteFile("builtin.go", out, 0666) 48 } 49 if err != nil { 50 log.Fatal(err) 51 } 52 } 53 54 func mkbuiltin(w io.Writer, name string) { 55 fset := token.NewFileSet() 56 f, err := parser.ParseFile(fset, filepath.Join("builtin", name+".go"), nil, 0) 57 if err != nil { 58 log.Fatal(err) 59 } 60 61 var interner typeInterner 62 63 fmt.Fprintf(w, "var %sDecls = [...]struct { name string; tag int; typ int }{\n", name) 64 for _, decl := range f.Decls { 65 switch decl := decl.(type) { 66 case *ast.FuncDecl: 67 if decl.Recv != nil { 68 log.Fatal("methods unsupported") 69 } 70 if decl.Body != nil { 71 log.Fatal("unexpected function body") 72 } 73 fmt.Fprintf(w, "{%q, funcTag, %d},\n", decl.Name.Name, interner.intern(decl.Type)) 74 case *ast.GenDecl: 75 if decl.Tok != token.VAR { 76 log.Fatal("unhandled declaration kind", decl.Tok) 77 } 78 for _, spec := range decl.Specs { 79 spec := spec.(*ast.ValueSpec) 80 if len(spec.Values) != 0 { 81 log.Fatal("unexpected values") 82 } 83 typ := interner.intern(spec.Type) 84 for _, name := range spec.Names { 85 fmt.Fprintf(w, "{%q, varTag, %d},\n", name.Name, typ) 86 } 87 } 88 default: 89 log.Fatal("unhandled decl type", decl) 90 } 91 } 92 fmt.Fprintln(w, "}") 93 94 fmt.Fprintln(w) 95 fmt.Fprintf(w, "func %sTypes() []*Type {\n", name) 96 fmt.Fprintf(w, "var typs [%d]*Type\n", len(interner.typs)) 97 for i, typ := range interner.typs { 98 fmt.Fprintf(w, "typs[%d] = %s\n", i, typ) 99 } 100 fmt.Fprintln(w, "return typs[:]") 101 fmt.Fprintln(w, "}") 102 } 103 104 // typeInterner maps Go type expressions to compiler code that 105 // constructs the denoted type. It recognizes and reuses common 106 // subtype expressions. 107 type typeInterner struct { 108 typs []string 109 hash map[string]int 110 } 111 112 func (i *typeInterner) intern(t ast.Expr) int { 113 x := i.mktype(t) 114 v, ok := i.hash[x] 115 if !ok { 116 v = len(i.typs) 117 if i.hash == nil { 118 i.hash = make(map[string]int) 119 } 120 i.hash[x] = v 121 i.typs = append(i.typs, x) 122 } 123 return v 124 } 125 126 func (i *typeInterner) subtype(t ast.Expr) string { 127 return fmt.Sprintf("typs[%d]", i.intern(t)) 128 } 129 130 func (i *typeInterner) mktype(t ast.Expr) string { 131 switch t := t.(type) { 132 case *ast.Ident: 133 switch t.Name { 134 case "byte": 135 return "bytetype" 136 case "rune": 137 return "runetype" 138 } 139 return fmt.Sprintf("Types[T%s]", strings.ToUpper(t.Name)) 140 141 case *ast.ArrayType: 142 if t.Len == nil { 143 return fmt.Sprintf("typSlice(%s)", i.subtype(t.Elt)) 144 } 145 return fmt.Sprintf("typArray(%s, %d)", i.subtype(t.Elt), intconst(t.Len)) 146 case *ast.ChanType: 147 dir := "Cboth" 148 switch t.Dir { 149 case ast.SEND: 150 dir = "Csend" 151 case ast.RECV: 152 dir = "Crecv" 153 } 154 return fmt.Sprintf("typChan(%s, %s)", i.subtype(t.Value), dir) 155 case *ast.FuncType: 156 return fmt.Sprintf("functype(nil, %s, %s)", i.fields(t.Params, false), i.fields(t.Results, false)) 157 case *ast.InterfaceType: 158 if len(t.Methods.List) != 0 { 159 log.Fatal("non-empty interfaces unsupported") 160 } 161 return "Types[TINTER]" 162 case *ast.MapType: 163 return fmt.Sprintf("typMap(%s, %s)", i.subtype(t.Key), i.subtype(t.Value)) 164 case *ast.StarExpr: 165 return fmt.Sprintf("typPtr(%s)", i.subtype(t.X)) 166 case *ast.StructType: 167 return fmt.Sprintf("tostruct(%s)", i.fields(t.Fields, true)) 168 169 default: 170 log.Fatalf("unhandled type: %#v", t) 171 panic("unreachable") 172 } 173 } 174 175 func (i *typeInterner) fields(fl *ast.FieldList, keepNames bool) string { 176 if fl == nil || len(fl.List) == 0 { 177 return "nil" 178 } 179 var res []string 180 for _, f := range fl.List { 181 typ := i.subtype(f.Type) 182 if len(f.Names) == 0 { 183 res = append(res, fmt.Sprintf("anonfield(%s)", typ)) 184 } else { 185 for _, name := range f.Names { 186 if keepNames { 187 res = append(res, fmt.Sprintf("namedfield(%q, %s)", name.Name, typ)) 188 } else { 189 res = append(res, fmt.Sprintf("anonfield(%s)", typ)) 190 } 191 } 192 } 193 } 194 return fmt.Sprintf("[]*Node{%s}", strings.Join(res, ", ")) 195 } 196 197 func intconst(e ast.Expr) int64 { 198 switch e := e.(type) { 199 case *ast.BasicLit: 200 if e.Kind != token.INT { 201 log.Fatalf("expected INT, got %v", e.Kind) 202 } 203 x, err := strconv.ParseInt(e.Value, 0, 64) 204 if err != nil { 205 log.Fatal(err) 206 } 207 return x 208 default: 209 log.Fatalf("unhandled expr: %#v", e) 210 panic("unreachable") 211 } 212 } 213