Home | History | Annotate | Download | only in gc
      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