github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/gc/mkbuiltin.go (about)

     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 "github.com/gagliardetto/golang-go/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  }