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
9package main
10
11import (
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
28var stdout = flag.Bool("stdout", false, "write to stdout instead of builtin.go")
29
30func 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
56func 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// typeInterner maps Go type expressions to compiler code that
113// constructs the denoted type. It recognizes and reuses common
114// subtype expressions.
115type typeInterner struct {
116	typs []string
117	hash map[string]int
118}
119
120func (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
134func (i *typeInterner) subtype(t ast.Expr) string {
135	return fmt.Sprintf("typs[%d]", i.intern(t))
136}
137
138func (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
188func (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
210func 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