package json
import (
)
var ErrUnknownName = errors.New("unknown object member name")
var errAmbiguousName = errors.New("ambiguous object member name")
const errorPrefix = "json: "
func ( error) bool {
, := .(*SemanticError)
return
}
func ( error) bool {
, := .(*jsontext.SyntacticError)
return
}
func ( error, jsonflags.Flags) bool {
return !.Get(jsonflags.ReportErrorsWithLegacySemantics) ||
isSyntacticError() || export.IsIOError()
}
type SemanticError struct {
requireKeyedLiterals
nonComparable
action string
ByteOffset int64
JSONPointer jsontext.Pointer
JSONKind jsontext.Kind
JSONValue jsontext.Value
GoType reflect.Type
Err error
}
type coder interface {
StackPointer() jsontext.Pointer
Options() Options
}
func ( coder, reflect.Type) error {
:= fmt.Errorf("invalid format flag %q", .Options().(*jsonopts.Struct).Format)
switch c := .(type) {
case *jsontext.Encoder:
= newMarshalErrorBefore(, , )
case *jsontext.Decoder:
= newUnmarshalErrorBeforeWithSkipping(, , )
}
return
}
func ( *jsontext.Encoder, reflect.Type, error) error {
return &SemanticError{action: "marshal", GoType: , Err: toUnexpectedEOF(),
ByteOffset: .OutputOffset() + int64(export.Encoder().CountNextDelimWhitespace()),
JSONPointer: jsontext.Pointer(export.Encoder().AppendStackPointer(nil, +1))}
}
func ( *jsontext.Decoder, reflect.Type, error) error {
var jsontext.Kind
if export.Decoder().Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
= .PeekKind()
}
return &SemanticError{action: "unmarshal", GoType: , Err: toUnexpectedEOF(),
ByteOffset: .InputOffset() + int64(export.Decoder().CountNextDelimWhitespace()),
JSONPointer: jsontext.Pointer(export.Decoder().AppendStackPointer(nil, +1)),
JSONKind: }
}
func ( *jsontext.Decoder, reflect.Type, error) error {
= newUnmarshalErrorBefore(, , )
if export.Decoder().Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
if := export.Decoder().SkipValue(); != nil {
return
}
}
return
}
func ( *jsontext.Decoder, reflect.Type, error) error {
:= export.Decoder().PreviousTokenOrValue()
:= .InputOffset() - int64(len())
if export.Decoder().Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
if := jsontext.Value().Kind(); == '[' || == '{' {
++
} else {
+= int64(len())
}
}
return &SemanticError{action: "unmarshal", GoType: , Err: toUnexpectedEOF(),
ByteOffset: ,
JSONPointer: jsontext.Pointer(export.Decoder().AppendStackPointer(nil, -1)),
JSONKind: jsontext.Value().Kind()}
}
func ( *jsontext.Decoder, reflect.Type, error) error {
:= newUnmarshalErrorAfter(, , ).(*SemanticError)
if .JSONKind == '"' || .JSONKind == '0' {
.JSONValue = jsontext.Value(export.Decoder().PreviousTokenOrValue()).Clone()
}
return
}
func ( *jsontext.Decoder, reflect.Type, error) error {
= newUnmarshalErrorAfter(, , )
if export.Decoder().Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
if := export.Decoder().SkipValueRemainder(); != nil {
return
}
}
return
}
func ( coder, reflect.Type, int, int64, error) error {
, := .(*SemanticError)
if == nil {
= &SemanticError{Err: }
}
.Err = toUnexpectedEOF(.Err)
var int
var int64
var interface{ ([]byte, int) []byte }
var int64
switch c := .(type) {
case *jsontext.Encoder:
:= export.Encoder()
.action = cmp.Or(.action, "marshal")
, = .Tokens.DepthLength()
= .OutputOffset() + int64(export.Encoder().CountNextDelimWhitespace())
=
case *jsontext.Decoder:
:= export.Decoder()
.action = cmp.Or(.action, "unmarshal")
, = .Tokens.DepthLength()
:= .PreviousTokenOrValue()
= .InputOffset() - int64(len())
if ( == && == ) || len() == 0 {
= .InputOffset() + int64(export.Decoder().CountNextDelimWhitespace())
}
=
}
.ByteOffset = cmp.Or(.ByteOffset, )
if .JSONPointer == "" {
:= 0
switch {
case == && +0 == :
= +1
case == && +1 == :
= -1
}
.JSONPointer = jsontext.Pointer(.(nil, ))
}
.GoType = cmp.Or(.GoType, )
return
}
func ( error) error {
if , := .(*SemanticError); {
if , := .Err.(*SemanticError); {
.ByteOffset = .ByteOffset + .ByteOffset
.JSONPointer = .JSONPointer + .JSONPointer
* = *
}
}
return
}
func ( error, string) error {
if errors.Is(, errors.ErrUnsupported) {
return errors.New( + " may not return errors.ErrUnsupported")
}
return
}
var errorModalVerb = sync.OnceValue(func() string {
for := range map[string]struct{}{"cannot": {}, "unable to": {}} {
return
}
return ""
})
func ( *SemanticError) () string {
var strings.Builder
.WriteString(errorPrefix)
.WriteString(errorModalVerb())
var string
switch .action {
case "marshal":
.WriteString(" marshal")
= " from"
case "unmarshal":
.WriteString(" unmarshal")
= " into"
default:
.WriteString(" handle")
= " with"
}
switch .JSONKind {
case 'n':
.WriteString(" JSON null")
case 'f', 't':
.WriteString(" JSON boolean")
case '"':
.WriteString(" JSON string")
case '0':
.WriteString(" JSON number")
case '{', '}':
.WriteString(" JSON object")
case '[', ']':
.WriteString(" JSON array")
default:
if .action == "" {
= ""
}
}
if len(.JSONValue) > 0 && len(.JSONValue) < 100 {
.WriteByte(' ')
.Write(.JSONValue)
}
if .GoType != nil {
:= .GoType.String()
if len() > 100 {
= .GoType.Kind().String()
if .GoType.Kind() == reflect.Struct && .GoType.Name() == "" {
for := range .GoType.NumField() {
if := .GoType.Field().PkgPath; != "" {
= [strings.LastIndexByte(, '/')+len("/"):] + ".struct"
break
}
}
}
}
.WriteString()
.WriteString(" Go ")
.WriteString()
}
if .Err == ErrUnknownName || .Err == errAmbiguousName {
.WriteString(": ")
.WriteString(.Err.Error())
.WriteString(" ")
.WriteString(strconv.Quote(.JSONPointer.LastToken()))
if := .JSONPointer.Parent(); != "" {
.WriteString(" within ")
.WriteString(strconv.Quote(jsonwire.TruncatePointer(string(), 100)))
}
return .String()
}
switch , := .Err.(*jsontext.SyntacticError); {
case .JSONPointer != "":
if == nil || !.JSONPointer.Contains(.JSONPointer) {
.WriteString(" within ")
.WriteString(strconv.Quote(jsonwire.TruncatePointer(string(.JSONPointer), 100)))
}
case .ByteOffset > 0:
if == nil || !(.ByteOffset <= .ByteOffset) {
.WriteString(" after offset ")
.WriteString(strconv.FormatInt(.ByteOffset, 10))
}
}
if .Err != nil {
:= .Err.Error()
if isSyntacticError(.Err) {
= strings.TrimPrefix(, "jsontext: ")
}
.WriteString(": ")
.WriteString()
}
return .String()
}
func ( *SemanticError) () error {
return .Err
}
func ( jsontext.Pointer, []byte, int64) error {
if != nil {
, := jsonwire.AppendUnquote(nil, )
= .AppendToken(string())
}
return &jsontext.SyntacticError{
ByteOffset: ,
JSONPointer: ,
Err: jsontext.ErrDuplicateName,
}
}
func ( error) error {
if == io.EOF {
return io.ErrUnexpectedEOF
}
return
}