1// +build ignore
2
3// mkstdlib generates the zstdlib.go file, containing the Go standard
4// library API symbols. It's baked into the binary to avoid scanning
5// GOPATH in the common case.
6package main
7
8import (
9 "bufio"
10 "bytes"
11 "fmt"
12 "go/format"
13 "io"
14 "io/ioutil"
15 "log"
16 "os"
17 "path"
18 "path/filepath"
19 "regexp"
20 "runtime"
21 "sort"
22 "strings"
23)
24
25func mustOpen(name string) io.Reader {
26 f, err := os.Open(name)
27 if err != nil {
28 log.Fatal(err)
29 }
30 return f
31}
32
33func api(base string) string {
34 return filepath.Join(runtime.GOROOT(), "api", base)
35}
36
37var sym = regexp.MustCompile(`^pkg (\S+).*?, (?:var|func|type|const) ([A-Z]\w*)`)
38
39func main() {
40 var buf bytes.Buffer
41 outf := func(format string, args ...interface{}) {
42 fmt.Fprintf(&buf, format, args...)
43 }
44 outf("// Code generated by mkstdlib.go. DO NOT EDIT.\n\n")
45 outf("package imports\n")
46 outf("var stdlib = map[string]string{\n")
47 f := io.MultiReader(
48 mustOpen(api("go1.txt")),
49 mustOpen(api("go1.1.txt")),
50 mustOpen(api("go1.2.txt")),
51 mustOpen(api("go1.3.txt")),
52 mustOpen(api("go1.4.txt")),
53 mustOpen(api("go1.5.txt")),
54 mustOpen(api("go1.6.txt")),
55 mustOpen(api("go1.7.txt")),
56 mustOpen(api("go1.8.txt")),
57 mustOpen(api("go1.9.txt")),
58 mustOpen(api("go1.10.txt")),
59 )
60 sc := bufio.NewScanner(f)
61 fullImport := map[string]string{} // "zip.NewReader" => "archive/zip"
62 ambiguous := map[string]bool{}
63 var keys []string
64 for sc.Scan() {
65 l := sc.Text()
66 has := func(v string) bool { return strings.Contains(l, v) }
67 if has("struct, ") || has("interface, ") || has(", method (") {
68 continue
69 }
70 if m := sym.FindStringSubmatch(l); m != nil {
71 full := m[1]
72 key := path.Base(full) + "." + m[2]
73 if exist, ok := fullImport[key]; ok {
74 if exist != full {
75 ambiguous[key] = true
76 }
77 } else {
78 fullImport[key] = full
79 keys = append(keys, key)
80 }
81 }
82 }
83 if err := sc.Err(); err != nil {
84 log.Fatal(err)
85 }
86 sort.Strings(keys)
87 for _, key := range keys {
88 if ambiguous[key] {
89 outf("\t// %q is ambiguous\n", key)
90 } else {
91 outf("\t%q: %q,\n", key, fullImport[key])
92 }
93 }
94 outf("\n")
95 for _, sym := range [...]string{"Alignof", "ArbitraryType", "Offsetof", "Pointer", "Sizeof"} {
96 outf("\t%q: %q,\n", "unsafe."+sym, "unsafe")
97 }
98 outf("}\n")
99 fmtbuf, err := format.Source(buf.Bytes())
100 if err != nil {
101 log.Fatal(err)
102 }
103 err = ioutil.WriteFile("zstdlib.go", fmtbuf, 0666)
104 if err != nil {
105 log.Fatal(err)
106 }
107}