github.com/bytedance/sonic@v1.11.7-0.20240517092252-d2edb31b167b/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/bytedance/sonic/internal/native/types`
    28      `github.com/bytedance/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': fallthrough
   147          case 't': val = "bool"
   148          case '"': val = "string"
   149          case '{': val = "object"
   150          case '[': val = "array"
   151          case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': val = "number"        
   152      }
   153      return val
   154  }
   155  
   156  func (self MismatchTypeError) Error() string {
   157      se := SyntaxError {
   158          Pos  : self.Pos,
   159          Src  : self.Src,
   160          Code : types.ERR_MISMATCH,
   161      }
   162      return fmt.Sprintf("Mismatch type %s with value %s %q", self.Type.String(), swithchJSONType(self.Src, self.Pos), se.description())
   163  }
   164  
   165  func (self MismatchTypeError) Description() string {
   166      se := SyntaxError {
   167          Pos  : self.Pos,
   168          Src  : self.Src,
   169          Code : types.ERR_MISMATCH,
   170      }
   171      return fmt.Sprintf("Mismatch type %s with value %s %s", self.Type.String(), swithchJSONType(self.Src, self.Pos), se.description())
   172  }
   173  
   174  func error_mismatch(src string, pos int, vt *rt.GoType) error {
   175      return &MismatchTypeError {
   176          Pos  : pos,
   177          Src  : src,
   178          Type : vt.Pack(),
   179      }
   180  }
   181  
   182  func error_field(name string) error {
   183      return errors.New("json: unknown field " + strconv.Quote(name))
   184  }
   185  
   186  func error_value(value string, vtype reflect.Type) error {
   187      return &json.UnmarshalTypeError {
   188          Type  : vtype,
   189          Value : value,
   190      }
   191  }