blob: 07a621411a8f13fdf45a60c37dfbca2cae53d333 [file] [log] [blame]
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")
// 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
func defaultErrorReporter(err ErrorWithPos) error {
// abort parsing after first error encountered
return err
}
type errorHandler struct {
reporter ErrorReporter
errsReported bool
err error
}
func newErrorHandler(reporter ErrorReporter) *errorHandler {
if reporter == nil {
reporter = defaultErrorReporter
}
return &errorHandler{
reporter: reporter,
}
}
func (h *errorHandler) handleError(err error) error {
if h.err != nil {
return h.err
}
if ewp, ok := err.(ErrorWithPos); ok {
h.errsReported = true
err = h.reporter(ewp)
}
h.err = err
return err
}
func (h *errorHandler) getError() error {
if h.errsReported && 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.
type ErrorWithSourcePos struct {
Underlying error
Pos *SourcePos
}
// Error implements the error interface
func (e ErrorWithSourcePos) Error() string {
if e.Pos.Line <= 0 || e.Pos.Col <= 0 {
return fmt.Sprintf("%s: %v", e.Pos.Filename, e.Underlying)
}
return fmt.Sprintf("%s:%d:%d: %v", e.Pos.Filename, e.Pos.Line, e.Pos.Col, e.Underlying)
}
// GetPosition implements the ErrorWithPos interface, supplying a location in
// proto source that caused the error.
func (e ErrorWithSourcePos) GetPosition() SourcePos {
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{}