2020-04-19 22:54:58 +00:00
|
|
|
package parser
|
|
|
|
|
|
|
|
import "github.com/pkg/errors"
|
|
|
|
|
2020-04-22 05:56:14 +00:00
|
|
|
// ErrorLocation gives a location in source code that caused the error
|
2020-04-19 22:54:58 +00:00
|
|
|
type ErrorLocation struct {
|
2020-04-22 05:56:14 +00:00
|
|
|
Location []Range
|
2020-04-19 22:54:58 +00:00
|
|
|
error
|
|
|
|
}
|
|
|
|
|
2020-04-22 05:56:14 +00:00
|
|
|
// Unwrap unwraps to the next error
|
2020-04-19 22:54:58 +00:00
|
|
|
func (e *ErrorLocation) Unwrap() error {
|
|
|
|
return e.error
|
|
|
|
}
|
|
|
|
|
2020-04-22 05:56:14 +00:00
|
|
|
// Range is a code section between two positions
|
2020-04-19 22:54:58 +00:00
|
|
|
type Range struct {
|
|
|
|
Start Position
|
|
|
|
End Position
|
|
|
|
}
|
|
|
|
|
2020-04-22 05:56:14 +00:00
|
|
|
// Position is a point in source code
|
2020-04-19 22:54:58 +00:00
|
|
|
type Position struct {
|
|
|
|
Line int
|
|
|
|
Character int
|
|
|
|
}
|
|
|
|
|
2020-04-22 05:56:14 +00:00
|
|
|
func withLocation(err error, start, end int) error {
|
|
|
|
return WithLocation(err, toRanges(start, end))
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithLocation extends an error with a source code location
|
|
|
|
func WithLocation(err error, location []Range) error {
|
2020-04-19 22:54:58 +00:00
|
|
|
if err == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2020-04-22 01:28:29 +00:00
|
|
|
var el *ErrorLocation
|
2020-04-20 03:54:38 +00:00
|
|
|
if errors.As(err, &el) {
|
|
|
|
return err
|
|
|
|
}
|
2020-04-22 05:56:14 +00:00
|
|
|
var err1 error = &ErrorLocation{
|
|
|
|
error: err,
|
|
|
|
Location: location,
|
|
|
|
}
|
|
|
|
if !hasLocalStackTrace(err) {
|
|
|
|
err1 = errors.WithStack(err1)
|
|
|
|
}
|
|
|
|
return err1
|
2020-04-19 22:54:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func toRanges(start, end int) (r []Range) {
|
|
|
|
if end <= start {
|
|
|
|
end = start
|
|
|
|
}
|
|
|
|
for i := start; i <= end; i++ {
|
|
|
|
r = append(r, Range{Start: Position{Line: i}, End: Position{Line: i}})
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2020-04-22 05:56:14 +00:00
|
|
|
|
|
|
|
func hasLocalStackTrace(err error) bool {
|
|
|
|
wrapped, ok := err.(interface {
|
|
|
|
Unwrap() error
|
|
|
|
})
|
|
|
|
if ok && hasLocalStackTrace(wrapped.Unwrap()) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
_, ok = err.(interface {
|
|
|
|
StackTrace() errors.StackTrace
|
|
|
|
})
|
|
|
|
return ok
|
|
|
|
}
|