You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
261 lines
5.7 KiB
Go
261 lines
5.7 KiB
Go
package errors
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"reflect"
|
|
|
|
"github.com/goccy/go-yaml/printer"
|
|
"github.com/goccy/go-yaml/token"
|
|
"golang.org/x/xerrors"
|
|
)
|
|
|
|
const (
|
|
defaultColorize = false
|
|
defaultIncludeSource = true
|
|
)
|
|
|
|
var (
|
|
ErrDecodeRequiredPointerType = xerrors.New("required pointer type value")
|
|
)
|
|
|
|
// Wrapf wrap error for stack trace
|
|
func Wrapf(err error, msg string, args ...interface{}) error {
|
|
return &wrapError{
|
|
baseError: &baseError{},
|
|
err: xerrors.Errorf(msg, args...),
|
|
nextErr: err,
|
|
frame: xerrors.Caller(1),
|
|
}
|
|
}
|
|
|
|
// ErrSyntax create syntax error instance with message and token
|
|
func ErrSyntax(msg string, tk *token.Token) *syntaxError {
|
|
return &syntaxError{
|
|
baseError: &baseError{},
|
|
msg: msg,
|
|
token: tk,
|
|
frame: xerrors.Caller(1),
|
|
}
|
|
}
|
|
|
|
type baseError struct {
|
|
state fmt.State
|
|
verb rune
|
|
}
|
|
|
|
func (e *baseError) Error() string {
|
|
return ""
|
|
}
|
|
|
|
func (e *baseError) chainStateAndVerb(err error) {
|
|
wrapErr, ok := err.(*wrapError)
|
|
if ok {
|
|
wrapErr.state = e.state
|
|
wrapErr.verb = e.verb
|
|
}
|
|
syntaxErr, ok := err.(*syntaxError)
|
|
if ok {
|
|
syntaxErr.state = e.state
|
|
syntaxErr.verb = e.verb
|
|
}
|
|
}
|
|
|
|
type wrapError struct {
|
|
*baseError
|
|
err error
|
|
nextErr error
|
|
frame xerrors.Frame
|
|
}
|
|
|
|
type FormatErrorPrinter struct {
|
|
xerrors.Printer
|
|
Colored bool
|
|
InclSource bool
|
|
}
|
|
|
|
func (e *wrapError) As(target interface{}) bool {
|
|
err := e.nextErr
|
|
for {
|
|
if wrapErr, ok := err.(*wrapError); ok {
|
|
err = wrapErr.nextErr
|
|
continue
|
|
}
|
|
break
|
|
}
|
|
return xerrors.As(err, target)
|
|
}
|
|
|
|
func (e *wrapError) Unwrap() error {
|
|
return e.nextErr
|
|
}
|
|
|
|
func (e *wrapError) PrettyPrint(p xerrors.Printer, colored, inclSource bool) error {
|
|
return e.FormatError(&FormatErrorPrinter{Printer: p, Colored: colored, InclSource: inclSource})
|
|
}
|
|
|
|
func (e *wrapError) FormatError(p xerrors.Printer) error {
|
|
if _, ok := p.(*FormatErrorPrinter); !ok {
|
|
p = &FormatErrorPrinter{
|
|
Printer: p,
|
|
Colored: defaultColorize,
|
|
InclSource: defaultIncludeSource,
|
|
}
|
|
}
|
|
if e.verb == 'v' && e.state.Flag('+') {
|
|
// print stack trace for debugging
|
|
p.Print(e.err, "\n")
|
|
e.frame.Format(p)
|
|
e.chainStateAndVerb(e.nextErr)
|
|
return e.nextErr
|
|
}
|
|
err := e.nextErr
|
|
for {
|
|
if wrapErr, ok := err.(*wrapError); ok {
|
|
err = wrapErr.nextErr
|
|
continue
|
|
}
|
|
break
|
|
}
|
|
e.chainStateAndVerb(err)
|
|
if fmtErr, ok := err.(xerrors.Formatter); ok {
|
|
fmtErr.FormatError(p)
|
|
} else {
|
|
p.Print(err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type wrapState struct {
|
|
org fmt.State
|
|
}
|
|
|
|
func (s *wrapState) Write(b []byte) (n int, err error) {
|
|
return s.org.Write(b)
|
|
}
|
|
|
|
func (s *wrapState) Width() (wid int, ok bool) {
|
|
return s.org.Width()
|
|
}
|
|
|
|
func (s *wrapState) Precision() (prec int, ok bool) {
|
|
return s.org.Precision()
|
|
}
|
|
|
|
func (s *wrapState) Flag(c int) bool {
|
|
// set true to 'printDetail' forced because when p.Detail() is false, xerrors.Printer no output any text
|
|
if c == '#' {
|
|
// ignore '#' keyword because xerrors.FormatError doesn't set true to printDetail.
|
|
// ( see https://github.com/golang/xerrors/blob/master/adaptor.go#L39-L43 )
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (e *wrapError) Format(state fmt.State, verb rune) {
|
|
e.state = state
|
|
e.verb = verb
|
|
xerrors.FormatError(e, &wrapState{org: state}, verb)
|
|
}
|
|
|
|
func (e *wrapError) Error() string {
|
|
var buf bytes.Buffer
|
|
e.PrettyPrint(&Sink{&buf}, defaultColorize, defaultIncludeSource)
|
|
return buf.String()
|
|
}
|
|
|
|
type syntaxError struct {
|
|
*baseError
|
|
msg string
|
|
token *token.Token
|
|
frame xerrors.Frame
|
|
}
|
|
|
|
func (e *syntaxError) PrettyPrint(p xerrors.Printer, colored, inclSource bool) error {
|
|
return e.FormatError(&FormatErrorPrinter{Printer: p, Colored: colored, InclSource: inclSource})
|
|
}
|
|
|
|
func (e *syntaxError) FormatError(p xerrors.Printer) error {
|
|
var pp printer.Printer
|
|
|
|
var colored, inclSource bool
|
|
if fep, ok := p.(*FormatErrorPrinter); ok {
|
|
colored = fep.Colored
|
|
inclSource = fep.InclSource
|
|
}
|
|
|
|
pos := fmt.Sprintf("[%d:%d] ", e.token.Position.Line, e.token.Position.Column)
|
|
msg := pp.PrintErrorMessage(fmt.Sprintf("%s%s", pos, e.msg), colored)
|
|
if inclSource {
|
|
msg += "\n" + pp.PrintErrorToken(e.token, colored)
|
|
}
|
|
p.Print(msg)
|
|
|
|
if e.verb == 'v' && e.state.Flag('+') {
|
|
// %+v
|
|
// print stack trace for debugging
|
|
e.frame.Format(p)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type PrettyPrinter interface {
|
|
PrettyPrint(xerrors.Printer, bool, bool) error
|
|
}
|
|
type Sink struct{ *bytes.Buffer }
|
|
|
|
func (es *Sink) Print(args ...interface{}) {
|
|
fmt.Fprint(es.Buffer, args...)
|
|
}
|
|
|
|
func (es *Sink) Printf(f string, args ...interface{}) {
|
|
fmt.Fprintf(es.Buffer, f, args...)
|
|
}
|
|
|
|
func (es *Sink) Detail() bool {
|
|
return false
|
|
}
|
|
|
|
func (e *syntaxError) Error() string {
|
|
var buf bytes.Buffer
|
|
e.PrettyPrint(&Sink{&buf}, defaultColorize, defaultIncludeSource)
|
|
return buf.String()
|
|
}
|
|
|
|
type TypeError struct {
|
|
DstType reflect.Type
|
|
SrcType reflect.Type
|
|
StructFieldName *string
|
|
Token *token.Token
|
|
}
|
|
|
|
func (e *TypeError) Error() string {
|
|
if e.StructFieldName != nil {
|
|
return fmt.Sprintf("cannot unmarshal %s into Go struct field %s of type %s", e.SrcType, *e.StructFieldName, e.DstType)
|
|
}
|
|
return fmt.Sprintf("cannot unmarshal %s into Go value of type %s", e.SrcType, e.DstType)
|
|
}
|
|
|
|
func (e *TypeError) PrettyPrint(p xerrors.Printer, colored, inclSource bool) error {
|
|
return e.FormatError(&FormatErrorPrinter{Printer: p, Colored: colored, InclSource: inclSource})
|
|
}
|
|
|
|
func (e *TypeError) FormatError(p xerrors.Printer) error {
|
|
var pp printer.Printer
|
|
|
|
var colored, inclSource bool
|
|
if fep, ok := p.(*FormatErrorPrinter); ok {
|
|
colored = fep.Colored
|
|
inclSource = fep.InclSource
|
|
}
|
|
|
|
pos := fmt.Sprintf("[%d:%d] ", e.Token.Position.Line, e.Token.Position.Column)
|
|
msg := pp.PrintErrorMessage(fmt.Sprintf("%s%s", pos, e.Error()), colored)
|
|
if inclSource {
|
|
msg += "\n" + pp.PrintErrorToken(e.Token, colored)
|
|
}
|
|
p.Print(msg)
|
|
|
|
return nil
|
|
}
|