// Copyright 2020 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.//go:build goexperiment.jsonv2package jsontextimport ()consterrorPrefix = "jsontext: "typeioErrorstruct {actionstring// either "read" or "write"errerror}func ( *ioError) () string {returnerrorPrefix + .action + " error: " + .err.Error()}func ( *ioError) () error {return .err}typenumErrorstruct {accessorstring// either "Int", "Uint", or "Float"valuestring// e.g., "1e1000"errerror// either [strconv.ErrSyntax] or [strconv.ErrRange]}func ( *numError) () string {return"jsontext.Token(" + .value + ")." + .accessor + " error: " + .err.Error()}func ( *numError) () error {return .err}// SyntacticError is a description of an error that occurred when// encoding or decoding JSON according to the grammar.//// The contents of this error as produced by this package may change over time.typeSyntacticErrorstruct {requireKeyedLiteralsnonComparable// ByteOffset indicates that an error occurred at or after this byte offset.ByteOffsetint64// JSONPointer indicates that an error occurred within this JSON value // as indicated using the JSON Pointer notation (see RFC 6901).JSONPointerPointer// Err is the underlying error.Errerror}// wrapSyntacticError wraps an error and annotates it with a precise location// using the provided [encoderState] or [decoderState].// If err is an [ioError] or [io.EOF], then it is not wrapped.//// It takes a relative offset pos that can be resolved into// an absolute offset using state.offsetAt.//// It takes a where that specifies how the JSON pointer is derived.// If the underlying error is a [pointerSuffixError],// then the suffix is appended to the derived pointer.func ( interface { () *jsonopts.Struct ( int) int64 ( []byte, int) []byte}, error, , int) error {if , := .(*ioError); == io.EOF || {return } := .() := .(nil, )if , := .(*pointerSuffixError); { = .appendPointer() = .error }if , := .(*decoderState); && == errMismatchDelim { := "at start of value"iflen(.Tokens.Stack) > 0 && .Tokens.Last.Length() > 0 {switch {case .Tokens.Last.isArray(): = "after array element (expecting ',' or ']')" = []byte(Pointer().Parent()) // problem is with parent arraycase .Tokens.Last.isObject(): = "after object value (expecting ',' or '}')" = []byte(Pointer().Parent()) // problem is with parent object } } = jsonwire.NewInvalidCharacterError(.buf[:], ) }if .().Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) && != io.ErrUnexpectedEOF {// The v1 error offset more consistently reported // the number of bytes read that lead to the error. // This implies that the offset is after the invalid text.if , := .(*jsonwire.InvalidTextError); && != nil { += int64(len(.What)) } else {// This implies a structural error (e.g., parsing a JSON number // when the grammar is expecting a JSON string for the object name). // In such a case, simply increment by one, since the first byte // is usually sufficient to indicate that the incoming token // cannot possibly be correct. ++ } }return &SyntacticError{ByteOffset: , JSONPointer: Pointer(), Err: }}func ( *SyntacticError) () string { := .JSONPointer := .ByteOffset := []byte(errorPrefix)if .Err != nil { = append(, .Err.Error()...)if .Err == ErrDuplicateName { = strconv.AppendQuote(append(, ' '), .LastToken()) = .Parent() = 0// not useful to print offset for duplicate names } } else { = append(, "syntactic error"...) }if != "" { = strconv.AppendQuote(append(, " within "...), jsonwire.TruncatePointer(string(), 100)) }if > 0 { = strconv.AppendInt(append(, " after offset "...), , 10) }returnstring()}func ( *SyntacticError) () error {return .Err}// pointerSuffixError represents a JSON pointer suffix to be appended// to [SyntacticError.JSONPointer]. It is an internal error type// used within this package and does not appear in the public API.//// This type is primarily used to annotate errors in Encoder.WriteValue// and Decoder.ReadValue with precise positions.// At the time WriteValue or ReadValue is called, a JSON pointer to the// upcoming value can be constructed using the Encoder/Decoder state.// However, tracking pointers within values during normal operation// would incur a performance penalty in the error-free case.//// To provide precise error locations without this overhead,// the error is wrapped with object names or array indices// as the call stack is popped when an error occurs.// Since this happens in reverse order, pointerSuffixError holds// the pointer in reverse and is only later reversed when appending to// the pointer prefix.//// For example, if the encoder is at "/alpha/bravo/charlie"// and an error occurs in WriteValue at "/xray/yankee/zulu", then// the final pointer should be "/alpha/bravo/charlie/xray/yankee/zulu".//// As pointerSuffixError is populated during the error return path,// it first contains "/zulu", then "/zulu/yankee",// and finally "/zulu/yankee/xray".// These tokens are reversed and concatenated to "/alpha/bravo/charlie"// to form the full pointer.typepointerSuffixErrorstruct {error// reversePointer is a JSON pointer, but with each token in reverse order.reversePointer []byte}// wrapWithObjectName wraps err with a JSON object name access,// which must be a valid quoted JSON string.func ( error, []byte) error { , := .(*pointerSuffixError)if == nil { = &pointerSuffixError{error: } } := jsonwire.UnquoteMayCopy(, false) .reversePointer = appendEscapePointerName(append(.reversePointer, '/'), )return}// wrapWithArrayIndex wraps err with a JSON array index access.func ( error, int64) error { , := .(*pointerSuffixError)if == nil { = &pointerSuffixError{error: } } .reversePointer = strconv.AppendUint(append(.reversePointer, '/'), uint64(), 10)return}// appendPointer appends the path encoded in e to the end of pointer.func ( *pointerSuffixError) ( []byte) []byte {// Copy each token in reversePointer to the end of pointer in reverse order. // Double reversal means that the appended suffix is now in forward order. , := .reversePointer, forlen() > 0 { := bytes.LastIndexByte(, '/') , = [:], append(, [:]...) }return}
The pages are generated with Goldsv0.8.4. (GOOS=linux GOARCH=amd64)