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