1
2
3
4
5 package base
6
7 import (
8 "fmt"
9 "internal/buildcfg"
10 "internal/types/errors"
11 "os"
12 "runtime/debug"
13 "sort"
14 "strings"
15
16 "cmd/internal/src"
17 )
18
19
20 type errorMsg struct {
21 pos src.XPos
22 msg string
23 code errors.Code
24 }
25
26
27
28 var Pos src.XPos
29
30 var (
31 errorMsgs []errorMsg
32 numErrors int
33 numSyntaxErrors int
34 )
35
36
37 func Errors() int {
38 return numErrors
39 }
40
41
42 func SyntaxErrors() int {
43 return numSyntaxErrors
44 }
45
46
47 func addErrorMsg(pos src.XPos, code errors.Code, format string, args ...interface{}) {
48 msg := fmt.Sprintf(format, args...)
49
50
51 if pos.IsKnown() {
52 msg = fmt.Sprintf("%v: %s", FmtPos(pos), msg)
53 }
54 errorMsgs = append(errorMsgs, errorMsg{
55 pos: pos,
56 msg: msg + "\n",
57 code: code,
58 })
59 }
60
61
62 func FmtPos(pos src.XPos) string {
63 if Ctxt == nil {
64 return "???"
65 }
66 return Ctxt.OutermostPos(pos).Format(Flag.C == 0, Flag.L == 1)
67 }
68
69
70 type byPos []errorMsg
71
72 func (x byPos) Len() int { return len(x) }
73 func (x byPos) Less(i, j int) bool { return x[i].pos.Before(x[j].pos) }
74 func (x byPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
75
76
77
78 func FlushErrors() {
79 if Ctxt != nil && Ctxt.Bso != nil {
80 Ctxt.Bso.Flush()
81 }
82 if len(errorMsgs) == 0 {
83 return
84 }
85 sort.Stable(byPos(errorMsgs))
86 for i, err := range errorMsgs {
87 if i == 0 || err.msg != errorMsgs[i-1].msg {
88 fmt.Print(err.msg)
89 }
90 }
91 errorMsgs = errorMsgs[:0]
92 }
93
94
95
96 var lasterror struct {
97 syntax src.XPos
98 other src.XPos
99 msg string
100 }
101
102
103 func sameline(a, b src.XPos) bool {
104 p := Ctxt.PosTable.Pos(a)
105 q := Ctxt.PosTable.Pos(b)
106 return p.Base() == q.Base() && p.Line() == q.Line()
107 }
108
109
110 func Errorf(format string, args ...interface{}) {
111 ErrorfAt(Pos, 0, format, args...)
112 }
113
114
115 func ErrorfAt(pos src.XPos, code errors.Code, format string, args ...interface{}) {
116 msg := fmt.Sprintf(format, args...)
117
118 if strings.HasPrefix(msg, "syntax error") {
119 numSyntaxErrors++
120
121 if sameline(lasterror.syntax, pos) {
122 return
123 }
124 lasterror.syntax = pos
125 } else {
126
127
128
129
130
131 if sameline(lasterror.other, pos) && lasterror.msg == msg {
132 return
133 }
134 lasterror.other = pos
135 lasterror.msg = msg
136 }
137
138 addErrorMsg(pos, code, "%s", msg)
139 numErrors++
140
141 hcrash()
142 if numErrors >= 10 && Flag.LowerE == 0 {
143 FlushErrors()
144 fmt.Printf("%v: too many errors\n", FmtPos(pos))
145 ErrorExit()
146 }
147 }
148
149
150
151
152 func UpdateErrorDot(line string, name, expr string) {
153 if len(errorMsgs) == 0 {
154 return
155 }
156 e := &errorMsgs[len(errorMsgs)-1]
157 if strings.HasPrefix(e.msg, line) && e.msg == fmt.Sprintf("%v: undefined: %v\n", line, name) {
158 e.msg = fmt.Sprintf("%v: undefined: %v in %v\n", line, name, expr)
159 }
160 }
161
162
163
164
165
166 func Warn(format string, args ...interface{}) {
167 WarnfAt(Pos, format, args...)
168 }
169
170
171
172
173
174 func WarnfAt(pos src.XPos, format string, args ...interface{}) {
175 addErrorMsg(pos, 0, format, args...)
176 if Flag.LowerM != 0 {
177 FlushErrors()
178 }
179 }
180
181
182
183
184
185
186
187
188
189
190
191
192
193 func Fatalf(format string, args ...interface{}) {
194 FatalfAt(Pos, format, args...)
195 }
196
197
198
199
200
201
202
203
204
205
206
207
208
209 func FatalfAt(pos src.XPos, format string, args ...interface{}) {
210 FlushErrors()
211
212 if Debug.Panic != 0 || numErrors == 0 {
213 fmt.Printf("%v: internal compiler error: ", FmtPos(pos))
214 fmt.Printf(format, args...)
215 fmt.Printf("\n")
216
217
218 if Debug.Panic == 0 && strings.HasPrefix(buildcfg.Version, "go") {
219 fmt.Printf("\n")
220 fmt.Printf("Please file a bug report including a short program that triggers the error.\n")
221 fmt.Printf("https://go.dev/issue/new\n")
222 } else {
223
224 fmt.Println()
225 os.Stdout.Write(debug.Stack())
226 fmt.Println()
227 }
228 }
229
230 hcrash()
231 ErrorExit()
232 }
233
234
235 func Assert(b bool) {
236 if !b {
237 Fatalf("assertion failed")
238 }
239 }
240
241
242 func Assertf(b bool, format string, args ...interface{}) {
243 if !b {
244 Fatalf(format, args...)
245 }
246 }
247
248
249 func AssertfAt(b bool, pos src.XPos, format string, args ...interface{}) {
250 if !b {
251 FatalfAt(pos, format, args...)
252 }
253 }
254
255
256 func hcrash() {
257 if Flag.LowerH != 0 {
258 FlushErrors()
259 if Flag.LowerO != "" {
260 os.Remove(Flag.LowerO)
261 }
262 panic("-h")
263 }
264 }
265
266
267
268 func ErrorExit() {
269 FlushErrors()
270 if Flag.LowerO != "" {
271 os.Remove(Flag.LowerO)
272 }
273 os.Exit(2)
274 }
275
276
277 func ExitIfErrors() {
278 if Errors() > 0 {
279 ErrorExit()
280 }
281 }
282
283 var AutogeneratedPos src.XPos
284
View as plain text