-
Notifications
You must be signed in to change notification settings - Fork 168
/
errors.go
181 lines (152 loc) · 5.29 KB
/
errors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package protoparse
import (
"errors"
"fmt"
)
// ErrInvalidSource is a sentinel error that is returned by calls to
// Parser.ParseFiles and Parser.ParseFilesButDoNotLink in the event that syntax
// or link errors are encountered, but the parser's configured ErrorReporter
// always returns nil.
var ErrInvalidSource = errors.New("parse failed: invalid proto source")
// ErrNoSyntax is a sentinel error that may be passed to a warning reporter.
// The error the reporter receives will be wrapped with source position that
// indicates the file that had no syntax statement.
var ErrNoSyntax = errors.New("no syntax specified; defaulting to proto2 syntax")
// ErrLookupImportAndProtoSet is the error returned if both LookupImport and LookupImportProto are set.
var ErrLookupImportAndProtoSet = errors.New("both LookupImport and LookupImportProto set")
// ErrorReporter is responsible for reporting the given error. If the reporter
// returns a non-nil error, parsing/linking will abort with that error. If the
// reporter returns nil, parsing will continue, allowing the parser to try to
// report as many syntax and/or link errors as it can find.
type ErrorReporter func(err ErrorWithPos) error
// WarningReporter is responsible for reporting the given warning. This is used
// for indicating non-error messages to the calling program for things that do
// not cause the parse to fail but are considered bad practice. Though they are
// just warnings, the details are supplied to the reporter via an error type.
type WarningReporter func(ErrorWithPos)
func defaultErrorReporter(err ErrorWithPos) error {
// abort parsing after first error encountered
return err
}
type errorHandler struct {
errReporter ErrorReporter
errsReported int
err error
warnReporter WarningReporter
}
func newErrorHandler(errRep ErrorReporter, warnRep WarningReporter) *errorHandler {
if errRep == nil {
errRep = defaultErrorReporter
}
return &errorHandler{
errReporter: errRep,
warnReporter: warnRep,
}
}
func (h *errorHandler) handleErrorWithPos(pos *SourcePos, format string, args ...interface{}) error {
if h.err != nil {
return h.err
}
h.errsReported++
err := h.errReporter(errorWithPos(pos, format, args...))
h.err = err
return err
}
func (h *errorHandler) handleError(err error) error {
if h.err != nil {
return h.err
}
if ewp, ok := err.(ErrorWithPos); ok {
h.errsReported++
err = h.errReporter(ewp)
}
h.err = err
return err
}
func (h *errorHandler) warnWithPos(pos *SourcePos, err error) {
if h.warnReporter != nil {
h.warnReporter(ErrorWithSourcePos{Pos: pos, Underlying: err})
}
}
func (h *errorHandler) warn(err ErrorWithSourcePos) {
if h.warnReporter != nil {
h.warnReporter(err)
}
}
func (h *errorHandler) getError() error {
if h.errsReported > 0 && h.err == nil {
return ErrInvalidSource
}
return h.err
}
// ErrorWithPos is an error about a proto source file that includes information
// about the location in the file that caused the error.
//
// The value of Error() will contain both the SourcePos and Underlying error.
// The value of Unwrap() will only be the Underlying error.
type ErrorWithPos interface {
error
GetPosition() SourcePos
Unwrap() error
}
// ErrorWithSourcePos is an error about a proto source file that includes
// information about the location in the file that caused the error.
//
// Errors that include source location information *might* be of this type.
// However, calling code that is trying to examine errors with location info
// should instead look for instances of the ErrorWithPos interface, which
// will find other kinds of errors. This type is only exported for backwards
// compatibility.
//
// SourcePos should always be set and never nil.
type ErrorWithSourcePos struct {
Underlying error
Pos *SourcePos
}
// Error implements the error interface
func (e ErrorWithSourcePos) Error() string {
sourcePos := e.GetPosition()
return fmt.Sprintf("%s: %v", sourcePos, e.Underlying)
}
// GetPosition implements the ErrorWithPos interface, supplying a location in
// proto source that caused the error.
func (e ErrorWithSourcePos) GetPosition() SourcePos {
if e.Pos == nil {
return SourcePos{Filename: "<input>"}
}
return *e.Pos
}
// Unwrap implements the ErrorWithPos interface, supplying the underlying
// error. This error will not include location information.
func (e ErrorWithSourcePos) Unwrap() error {
return e.Underlying
}
var _ ErrorWithPos = ErrorWithSourcePos{}
func errorWithPos(pos *SourcePos, format string, args ...interface{}) ErrorWithSourcePos {
return ErrorWithSourcePos{Pos: pos, Underlying: fmt.Errorf(format, args...)}
}
type errorWithFilename struct {
underlying error
filename string
}
func (e errorWithFilename) Error() string {
return fmt.Sprintf("%s: %v", e.filename, e.underlying)
}
func (e errorWithFilename) Unwrap() error {
return e.underlying
}
// ErrorUnusedImport may be passed to a warning reporter when an unused
// import is detected. The error the reporter receives will be wrapped
// with source position that indicates the file and line where the import
// statement appeared.
type ErrorUnusedImport interface {
error
UnusedImport() string
}
type errUnusedImport string
func (e errUnusedImport) Error() string {
return fmt.Sprintf("import %q not used", string(e))
}
func (e errUnusedImport) UnusedImport() string {
return string(e)
}