github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/internal/decoder/errors.go (about)

     1  /*
     2   * Copyright 2021 ByteDance Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package decoder
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  	"fmt"
    23  	"reflect"
    24  	"strconv"
    25  	"strings"
    26  
    27  	"github.com/goshafaq/sonic/internal/native/types"
    28  	"github.com/goshafaq/sonic/internal/rt"
    29  )
    30  
    31  type SyntaxError struct {
    32  	Pos  int
    33  	Src  string
    34  	Code types.ParsingError
    35  	Msg  string
    36  }
    37  
    38  func (self SyntaxError) Error() string {
    39  	return fmt.Sprintf("%q", self.Description())
    40  }
    41  
    42  func (self SyntaxError) Description() string {
    43  	return "Syntax error " + self.description()
    44  }
    45  
    46  func (self SyntaxError) description() string {
    47  	/* check for empty source */
    48  	if self.Src == "" {
    49  		return fmt.Sprintf("no sources available: %#v", self)
    50  	}
    51  
    52  	p, x, q, y := calcBounds(len(self.Src), self.Pos)
    53  
    54  	/* compose the error description */
    55  	return fmt.Sprintf(
    56  		"at index %d: %s\n\n\t%s\n\t%s^%s\n",
    57  		self.Pos,
    58  		self.Message(),
    59  		self.Src[p:q],
    60  		strings.Repeat(".", x),
    61  		strings.Repeat(".", y),
    62  	)
    63  }
    64  
    65  func calcBounds(size int, pos int) (lbound int, lwidth int, rbound int, rwidth int) {
    66  	if pos >= size || pos < 0 {
    67  		return 0, 0, size, 0
    68  	}
    69  
    70  	i := 16
    71  	lbound = pos - i
    72  	rbound = pos + i
    73  
    74  	/* prevent slicing before the beginning */
    75  	if lbound < 0 {
    76  		lbound, rbound, i = 0, rbound-lbound, i+lbound
    77  	}
    78  
    79  	/* prevent slicing beyond the end */
    80  	if n := size; rbound > n {
    81  		n = rbound - n
    82  		rbound = size
    83  
    84  		/* move the left bound if possible */
    85  		if lbound > n {
    86  			i += n
    87  			lbound -= n
    88  		}
    89  	}
    90  
    91  	/* left and right length */
    92  	lwidth = clamp_zero(i)
    93  	rwidth = clamp_zero(rbound - lbound - i - 1)
    94  
    95  	return
    96  }
    97  
    98  func (self SyntaxError) Message() string {
    99  	if self.Msg == "" {
   100  		return self.Code.Message()
   101  	}
   102  	return self.Msg
   103  }
   104  
   105  func clamp_zero(v int) int {
   106  	if v < 0 {
   107  		return 0
   108  	} else {
   109  		return v
   110  	}
   111  }
   112  
   113  /** JIT Error Helpers **/
   114  
   115  var stackOverflow = &json.UnsupportedValueError{
   116  	Str:   "Value nesting too deep",
   117  	Value: reflect.ValueOf("..."),
   118  }
   119  
   120  func error_wrap(src string, pos int, code types.ParsingError) error {
   121  	return *error_wrap_heap(src, pos, code)
   122  }
   123  
   124  //go:noinline
   125  func error_wrap_heap(src string, pos int, code types.ParsingError) *SyntaxError {
   126  	return &SyntaxError{
   127  		Pos:  pos,
   128  		Src:  src,
   129  		Code: code,
   130  	}
   131  }
   132  
   133  func error_type(vt *rt.GoType) error {
   134  	return &json.UnmarshalTypeError{Type: vt.Pack()}
   135  }
   136  
   137  type MismatchTypeError struct {
   138  	Pos  int
   139  	Src  string
   140  	Type reflect.Type
   141  }
   142  
   143  func swithchJSONType(src string, pos int) string {
   144  	var val string
   145  	switch src[pos] {
   146  	case 'f':
   147  		fallthrough
   148  	case 't':
   149  		val = "bool"
   150  	case '"':
   151  		val = "string"
   152  	case '{':
   153  		val = "object"
   154  	case '[':
   155  		val = "array"
   156  	case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
   157  		val = "number"
   158  	}
   159  	return val
   160  }
   161  
   162  func (self MismatchTypeError) Error() string {
   163  	se := SyntaxError{
   164  		Pos:  self.Pos,
   165  		Src:  self.Src,
   166  		Code: types.ERR_MISMATCH,
   167  	}
   168  	return fmt.Sprintf("Mismatch type %s with value %s %q", self.Type.String(), swithchJSONType(self.Src, self.Pos), se.description())
   169  }
   170  
   171  func (self MismatchTypeError) Description() string {
   172  	se := SyntaxError{
   173  		Pos:  self.Pos,
   174  		Src:  self.Src,
   175  		Code: types.ERR_MISMATCH,
   176  	}
   177  	return fmt.Sprintf("Mismatch type %s with value %s %s", self.Type.String(), swithchJSONType(self.Src, self.Pos), se.description())
   178  }
   179  
   180  func error_mismatch(src string, pos int, vt *rt.GoType) error {
   181  	return &MismatchTypeError{
   182  		Pos:  pos,
   183  		Src:  src,
   184  		Type: vt.Pack(),
   185  	}
   186  }
   187  
   188  func error_field(name string) error {
   189  	return errors.New("json: unknown field " + strconv.Quote(name))
   190  }
   191  
   192  func error_value(value string, vtype reflect.Type) error {
   193  	return &json.UnmarshalTypeError{
   194  		Type:  vtype,
   195  		Value: value,
   196  	}
   197  }