...

Source file src/cmd/compile/internal/typecheck/mkbuiltin.go

Documentation: cmd/compile/internal/typecheck

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

View as plain text