blob: 07a621411a8f13fdf45a60c37dfbca2cae53d333 [file] [log] [blame]
Scott Baker4a35a702019-11-26 08:17:33 -08001package protoparse
2
3import (
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.
12var 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.
18type ErrorReporter func(err ErrorWithPos) error
19
20func defaultErrorReporter(err ErrorWithPos) error {
21 // abort parsing after first error encountered
22 return err
23}
24
25type errorHandler struct {
26 reporter ErrorReporter
27 errsReported bool
28 err error
29}
30
31func newErrorHandler(reporter ErrorReporter) *errorHandler {
32 if reporter == nil {
33 reporter = defaultErrorReporter
34 }
35 return &errorHandler{
36 reporter: reporter,
37 }
38}
39
40func (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
52func (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//
62// The value of Error() will contain both the SourcePos and Underlying error.
63// The value of Unwrap() will only be the Underlying error.
64type ErrorWithPos interface {
65 error
66 GetPosition() SourcePos
67 Unwrap() error
68}
69
70// ErrorWithSourcePos is an error about a proto source file that includes
71// information about the location in the file that caused the error.
72//
73// Errors that include source location information *might* be of this type.
74// However, calling code that is trying to examine errors with location info
75// should instead look for instances of the ErrorWithPos interface, which
76// will find other kinds of errors. This type is only exported for backwards
77// compatibility.
78type ErrorWithSourcePos struct {
79 Underlying error
80 Pos *SourcePos
81}
82
83// Error implements the error interface
84func (e ErrorWithSourcePos) Error() string {
85 if e.Pos.Line <= 0 || e.Pos.Col <= 0 {
86 return fmt.Sprintf("%s: %v", e.Pos.Filename, e.Underlying)
87 }
88 return fmt.Sprintf("%s:%d:%d: %v", e.Pos.Filename, e.Pos.Line, e.Pos.Col, e.Underlying)
89}
90
91// GetPosition implements the ErrorWithPos interface, supplying a location in
92// proto source that caused the error.
93func (e ErrorWithSourcePos) GetPosition() SourcePos {
94 return *e.Pos
95}
96
97// Unwrap implements the ErrorWithPos interface, supplying the underlying
98// error. This error will not include location information.
99func (e ErrorWithSourcePos) Unwrap() error {
100 return e.Underlying
101}
102
103var _ ErrorWithPos = ErrorWithSourcePos{}