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 }