...

Source file src/pkg/cmd/compile/internal/gc/mkbuiltin.go

     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, "// 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	// typeInterner maps Go type expressions to compiler code that
   113	// constructs the denoted type. It recognizes and reuses common
   114	// subtype expressions.
   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