// 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 ()const errorPrefix = "jsontext: "type ioError struct { action string// either "read" or "write" err error}func ( *ioError) () string {returnerrorPrefix + .action + " error: " + .err.Error()}func ( *ioError) () error {return .err}// SyntacticError is a description of a syntactic 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 after this byte offset. ByteOffset int64// JSONPointer indicates that an error occurred within this JSON value // as indicated using the JSON Pointer notation (see RFC 6901). JSONPointer Pointer// Err is the underlying error. Err error}// 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 specify how the JSON pointer is derived.// If the underlying error is a [pointerSuffixError],// then the suffix is appended to the derived pointer.func wrapSyntacticError( interface { ( 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[:], ) }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.type pointerSuffixError struct {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 wrapWithObjectName( 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 wrapWithArrayIndex( 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.7.7-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.