github.com/hoveychen/protoreflect@v1.4.7-0.20221103114119-0b4b3385ec76/desc/protoparse/errors.go (about) 1 package protoparse 2 3 import ( 4 "errors" 5 "fmt" 6 ) 7 8 // ErrInvalidSource is a sentinel error that is returned by calls to 9 // Parser.ParseFiles and Parser.ParseFilesButDoNotLink in the event that syntax 10 // or link errors are encountered, but the parser's configured ErrorReporter 11 // always returns nil. 12 var ErrInvalidSource = errors.New("parse failed: invalid proto source") 13 14 // ErrorReporter is responsible for reporting the given error. If the reporter 15 // returns a non-nil error, parsing/linking will abort with that error. If the 16 // reporter returns nil, parsing will continue, allowing the parser to try to 17 // report as many syntax and/or link errors as it can find. 18 type ErrorReporter func(err ErrorWithPos) error 19 20 func defaultErrorReporter(err ErrorWithPos) error { 21 // abort parsing after first error encountered 22 return err 23 } 24 25 type errorHandler struct { 26 reporter ErrorReporter 27 errsReported bool 28 err error 29 } 30 31 func newErrorHandler(reporter ErrorReporter) *errorHandler { 32 if reporter == nil { 33 reporter = defaultErrorReporter 34 } 35 return &errorHandler{ 36 reporter: reporter, 37 } 38 } 39 40 func (h *errorHandler) handleError(err error) error { 41 if h.err != nil { 42 return h.err 43 } 44 if ewp, ok := err.(ErrorWithPos); ok { 45 h.errsReported = true 46 err = h.reporter(ewp) 47 } 48 h.err = err 49 return err 50 } 51 52 func (h *errorHandler) getError() error { 53 if h.errsReported && h.err == nil { 54 return ErrInvalidSource 55 } 56 return h.err 57 } 58 59 // ErrorWithPos is an error about a proto source file that includes information 60 // about the location in the file that caused the error. 61 type ErrorWithPos interface { 62 error 63 GetPosition() SourcePos 64 } 65 66 // ErrorWithSourcePos is an error about a proto source file that includes 67 // information about the location in the file that caused the error. 68 // 69 // Errors that include source location information *might* be of this type. 70 // However, calling code that is trying to examine errors with location info 71 // should instead look for instances of the ErrorWithPos interface, which 72 // will find other kinds of errors. This type is only exported for backwards 73 // compatibility. 74 type ErrorWithSourcePos struct { 75 Underlying error 76 Pos *SourcePos 77 } 78 79 // Error implements the error interface 80 func (e ErrorWithSourcePos) Error() string { 81 if e.Pos.Line <= 0 || e.Pos.Col <= 0 { 82 return fmt.Sprintf("%s: %v", e.Pos.Filename, e.Underlying) 83 } 84 return fmt.Sprintf("%s:%d:%d: %v", e.Pos.Filename, e.Pos.Line, e.Pos.Col, e.Underlying) 85 } 86 87 // GetPosition implements the ErrorWithPos interface, supplying a location in 88 // proto source that caused the error. 89 func (e ErrorWithSourcePos) GetPosition() SourcePos { 90 return *e.Pos 91 } 92 93 var _ ErrorWithPos = ErrorWithSourcePos{}