2019-10-23 03:21:42 +09:00
|
|
|
package errors
|
|
|
|
|
|
|
|
|
|
import (
|
2019-10-24 11:07:40 +09:00
|
|
|
"bytes"
|
2019-10-23 03:21:42 +09:00
|
|
|
"fmt"
|
|
|
|
|
|
|
|
|
|
"github.com/goccy/go-yaml/printer"
|
|
|
|
|
"github.com/goccy/go-yaml/token"
|
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
|
)
|
|
|
|
|
|
2019-10-24 15:28:41 +09:00
|
|
|
const (
|
|
|
|
|
defaultColorize = false
|
|
|
|
|
defaultIncludeSource = true
|
|
|
|
|
)
|
|
|
|
|
|
2019-10-23 03:21:42 +09:00
|
|
|
var (
|
2019-10-23 16:40:26 +09:00
|
|
|
ErrDecodeRequiredPointerType = xerrors.New("required pointer type value")
|
2019-10-23 03:21:42 +09:00
|
|
|
)
|
|
|
|
|
|
2019-10-23 13:32:30 +09:00
|
|
|
// Wrapf wrap error for stack trace
|
2019-10-23 13:30:22 +09:00
|
|
|
func Wrapf(err error, msg string, args ...interface{}) error {
|
|
|
|
|
return &wrapError{
|
|
|
|
|
baseError: &baseError{},
|
|
|
|
|
err: xerrors.Errorf(msg, args...),
|
|
|
|
|
nextErr: err,
|
|
|
|
|
frame: xerrors.Caller(1),
|
|
|
|
|
}
|
2019-10-23 03:21:42 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-23 13:32:30 +09:00
|
|
|
// ErrSyntax create syntax error instance with message and token
|
2019-10-23 13:30:22 +09:00
|
|
|
func ErrSyntax(msg string, tk *token.Token) *syntaxError {
|
|
|
|
|
return &syntaxError{
|
|
|
|
|
baseError: &baseError{},
|
2019-10-23 16:08:21 +09:00
|
|
|
msg: msg,
|
|
|
|
|
token: tk,
|
2019-10-23 13:30:22 +09:00
|
|
|
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 {
|
2019-10-23 03:21:42 +09:00
|
|
|
wrapErr.state = e.state
|
|
|
|
|
wrapErr.verb = e.verb
|
2019-10-23 13:30:22 +09:00
|
|
|
}
|
|
|
|
|
syntaxErr, ok := err.(*syntaxError)
|
|
|
|
|
if ok {
|
2019-10-23 03:21:42 +09:00
|
|
|
syntaxErr.state = e.state
|
|
|
|
|
syntaxErr.verb = e.verb
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-23 13:30:22 +09:00
|
|
|
type wrapError struct {
|
|
|
|
|
*baseError
|
|
|
|
|
err error
|
|
|
|
|
nextErr error
|
|
|
|
|
frame xerrors.Frame
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 11:07:40 +09:00
|
|
|
type myprinter struct {
|
|
|
|
|
xerrors.Printer
|
|
|
|
|
colored bool
|
|
|
|
|
inclSource bool
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 00:41:05 +09:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-18 23:59:27 +09:00
|
|
|
func (e *wrapError) Unwrap() error {
|
|
|
|
|
return e.nextErr
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 11:07:40 +09:00
|
|
|
func (e *wrapError) PrettyPrint(p xerrors.Printer, colored, inclSource bool) error {
|
|
|
|
|
return e.FormatError(&myprinter{Printer: p, colored: colored, inclSource: inclSource})
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-23 13:30:22 +09:00
|
|
|
func (e *wrapError) FormatError(p xerrors.Printer) error {
|
2019-10-24 15:28:41 +09:00
|
|
|
if _, ok := p.(*myprinter); !ok {
|
|
|
|
|
p = &myprinter{
|
|
|
|
|
Printer: p,
|
|
|
|
|
colored: defaultColorize,
|
|
|
|
|
inclSource: defaultIncludeSource,
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-10-23 13:30:22 +09:00
|
|
|
if e.verb == 'v' && e.state.Flag('+') {
|
2019-10-23 03:21:42 +09:00
|
|
|
// print stack trace for debugging
|
|
|
|
|
p.Print(e.err, "\n")
|
2019-10-23 13:30:22 +09:00
|
|
|
e.frame.Format(p)
|
2019-10-23 03:21:42 +09:00
|
|
|
e.chainStateAndVerb(e.nextErr)
|
|
|
|
|
return e.nextErr
|
|
|
|
|
}
|
|
|
|
|
err := e.nextErr
|
|
|
|
|
for {
|
2019-10-23 13:30:22 +09:00
|
|
|
if wrapErr, ok := err.(*wrapError); ok {
|
2019-10-23 03:21:42 +09:00
|
|
|
err = wrapErr.nextErr
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
2019-10-23 16:40:26 +09:00
|
|
|
e.chainStateAndVerb(err)
|
|
|
|
|
if fmtErr, ok := err.(xerrors.Formatter); ok {
|
|
|
|
|
fmtErr.FormatError(p)
|
2019-10-23 03:21:42 +09:00
|
|
|
} else {
|
2019-10-23 16:40:26 +09:00
|
|
|
p.Print(err)
|
2019-10-23 03:21:42 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-23 13:30:22 +09:00
|
|
|
type wrapState struct {
|
2019-10-23 03:21:42 +09:00
|
|
|
org fmt.State
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-23 13:30:22 +09:00
|
|
|
func (s *wrapState) Write(b []byte) (n int, err error) {
|
2019-10-23 03:21:42 +09:00
|
|
|
return s.org.Write(b)
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-23 13:30:22 +09:00
|
|
|
func (s *wrapState) Width() (wid int, ok bool) {
|
2019-10-23 03:21:42 +09:00
|
|
|
return s.org.Width()
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-23 13:30:22 +09:00
|
|
|
func (s *wrapState) Precision() (prec int, ok bool) {
|
2019-10-23 03:21:42 +09:00
|
|
|
return s.org.Precision()
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-23 13:30:22 +09:00
|
|
|
func (s *wrapState) Flag(c int) bool {
|
|
|
|
|
// set true to 'printDetail' forced because when p.Detail() is false, xerrors.Printer no output any text
|
2019-10-23 03:21:42 +09:00
|
|
|
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
|
|
|
|
|
}
|
2019-10-23 13:30:22 +09:00
|
|
|
return true
|
2019-10-23 03:21:42 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-23 13:30:22 +09:00
|
|
|
func (e *wrapError) Format(state fmt.State, verb rune) {
|
2019-10-23 03:21:42 +09:00
|
|
|
e.state = state
|
|
|
|
|
e.verb = verb
|
2019-10-23 13:30:22 +09:00
|
|
|
xerrors.FormatError(e, &wrapState{org: state}, verb)
|
2019-10-23 03:21:42 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-23 13:30:22 +09:00
|
|
|
func (e *wrapError) Error() string {
|
2019-10-24 15:28:41 +09:00
|
|
|
var buf bytes.Buffer
|
|
|
|
|
e.PrettyPrint(&Sink{&buf}, defaultColorize, defaultIncludeSource)
|
|
|
|
|
return buf.String()
|
2019-10-23 03:21:42 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-23 13:30:22 +09:00
|
|
|
type syntaxError struct {
|
|
|
|
|
*baseError
|
2019-10-23 16:08:21 +09:00
|
|
|
msg string
|
|
|
|
|
token *token.Token
|
2019-10-23 03:21:42 +09:00
|
|
|
frame xerrors.Frame
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 11:07:40 +09:00
|
|
|
func (e *syntaxError) PrettyPrint(p xerrors.Printer, colored, inclSource bool) error {
|
|
|
|
|
return e.FormatError(&myprinter{Printer: p, colored: colored, inclSource: inclSource})
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-23 13:30:22 +09:00
|
|
|
func (e *syntaxError) FormatError(p xerrors.Printer) error {
|
2019-10-24 11:07:40 +09:00
|
|
|
var pp printer.Printer
|
|
|
|
|
|
|
|
|
|
var colored, inclSource bool
|
2019-10-24 15:28:41 +09:00
|
|
|
if mp, ok := p.(*myprinter); ok {
|
2019-10-24 11:07:40 +09:00
|
|
|
colored = mp.colored
|
|
|
|
|
inclSource = mp.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)
|
|
|
|
|
|
2019-10-23 13:30:22 +09:00
|
|
|
if e.verb == 'v' && e.state.Flag('+') {
|
|
|
|
|
// %+v
|
|
|
|
|
// print stack trace for debugging
|
|
|
|
|
e.frame.Format(p)
|
2019-10-23 03:21:42 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 11:07:40 +09:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-23 13:30:22 +09:00
|
|
|
func (e *syntaxError) Error() string {
|
2019-10-24 11:07:40 +09:00
|
|
|
var buf bytes.Buffer
|
2019-10-24 15:28:41 +09:00
|
|
|
e.PrettyPrint(&Sink{&buf}, defaultColorize, defaultIncludeSource)
|
2019-10-24 11:07:40 +09:00
|
|
|
return buf.String()
|
2019-10-23 03:21:42 +09:00
|
|
|
}
|