]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/go/internal/modindex/write.go
cmd/go, go/build: parse directives in file headers
[gostls13.git] / src / cmd / go / internal / modindex / write.go
1 // Copyright 2022 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 package modindex
6
7 import (
8         "cmd/go/internal/base"
9         "encoding/binary"
10         "go/token"
11         "sort"
12 )
13
14 const indexVersion = "go index v2" // 11 bytes (plus \n), to align uint32s in index
15
16 // encodeModuleBytes produces the encoded representation of the module index.
17 // encodeModuleBytes may modify the packages slice.
18 func encodeModuleBytes(packages []*rawPackage) []byte {
19         e := newEncoder()
20         e.Bytes([]byte(indexVersion + "\n"))
21         stringTableOffsetPos := e.Pos() // fill this at the end
22         e.Uint32(0)                     // string table offset
23         sort.Slice(packages, func(i, j int) bool {
24                 return packages[i].dir < packages[j].dir
25         })
26         e.Int(len(packages))
27         packagesPos := e.Pos()
28         for _, p := range packages {
29                 e.String(p.dir)
30                 e.Int(0)
31         }
32         for i, p := range packages {
33                 e.IntAt(e.Pos(), packagesPos+8*i+4)
34                 encodePackage(e, p)
35         }
36         e.IntAt(e.Pos(), stringTableOffsetPos)
37         e.Bytes(e.stringTable)
38         e.Bytes([]byte{0xFF}) // end of string table marker
39         return e.b
40 }
41
42 func encodePackageBytes(p *rawPackage) []byte {
43         return encodeModuleBytes([]*rawPackage{p})
44 }
45
46 func encodePackage(e *encoder, p *rawPackage) {
47         e.String(p.error)
48         e.String(p.dir)
49         e.Int(len(p.sourceFiles))      // number of source files
50         sourceFileOffsetPos := e.Pos() // the pos of the start of the source file offsets
51         for range p.sourceFiles {
52                 e.Int(0)
53         }
54         for i, f := range p.sourceFiles {
55                 e.IntAt(e.Pos(), sourceFileOffsetPos+4*i)
56                 encodeFile(e, f)
57         }
58 }
59
60 func encodeFile(e *encoder, f *rawFile) {
61         e.String(f.error)
62         e.String(f.parseError)
63         e.String(f.synopsis)
64         e.String(f.name)
65         e.String(f.pkgName)
66         e.Bool(f.ignoreFile)
67         e.Bool(f.binaryOnly)
68         e.String(f.cgoDirectives)
69         e.String(f.goBuildConstraint)
70
71         e.Int(len(f.plusBuildConstraints))
72         for _, s := range f.plusBuildConstraints {
73                 e.String(s)
74         }
75
76         e.Int(len(f.imports))
77         for _, m := range f.imports {
78                 e.String(m.path)
79                 e.Position(m.position)
80         }
81
82         e.Int(len(f.embeds))
83         for _, embed := range f.embeds {
84                 e.String(embed.pattern)
85                 e.Position(embed.position)
86         }
87
88         e.Int(len(f.directives))
89         for _, d := range f.directives {
90                 e.String(d.Text)
91                 e.Position(d.Pos)
92         }
93 }
94
95 func newEncoder() *encoder {
96         e := &encoder{strings: make(map[string]int)}
97
98         // place the empty string at position 0 in the string table
99         e.stringTable = append(e.stringTable, 0)
100         e.strings[""] = 0
101
102         return e
103 }
104
105 func (e *encoder) Position(position token.Position) {
106         e.String(position.Filename)
107         e.Int(position.Offset)
108         e.Int(position.Line)
109         e.Int(position.Column)
110 }
111
112 type encoder struct {
113         b           []byte
114         stringTable []byte
115         strings     map[string]int
116 }
117
118 func (e *encoder) Pos() int {
119         return len(e.b)
120 }
121
122 func (e *encoder) Bytes(b []byte) {
123         e.b = append(e.b, b...)
124 }
125
126 func (e *encoder) String(s string) {
127         if n, ok := e.strings[s]; ok {
128                 e.Int(n)
129                 return
130         }
131         pos := len(e.stringTable)
132         e.strings[s] = pos
133         e.Int(pos)
134         e.stringTable = binary.AppendUvarint(e.stringTable, uint64(len(s)))
135         e.stringTable = append(e.stringTable, s...)
136 }
137
138 func (e *encoder) Bool(b bool) {
139         if b {
140                 e.Uint32(1)
141         } else {
142                 e.Uint32(0)
143         }
144 }
145
146 func (e *encoder) Uint32(n uint32) {
147         e.b = binary.LittleEndian.AppendUint32(e.b, n)
148 }
149
150 // Int encodes n. Note that all ints are written to the index as uint32s,
151 // and to avoid problems on 32-bit systems we require fitting into a 32-bit int.
152 func (e *encoder) Int(n int) {
153         if n < 0 || int(int32(n)) != n {
154                 base.Fatalf("go: attempting to write an int to the index that overflows int32")
155         }
156         e.Uint32(uint32(n))
157 }
158
159 func (e *encoder) IntAt(n int, at int) {
160         if n < 0 || int(int32(n)) != n {
161                 base.Fatalf("go: attempting to write an int to the index that overflows int32")
162         }
163         binary.LittleEndian.PutUint32(e.b[at:], uint32(n))
164 }