github.com/bytedance/sonic@v1.11.7-0.20240517092252-d2edb31b167b/internal/decoder/assembler_test.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/base64`
    21      `encoding/json`
    22      `reflect`
    23      `testing`
    24      `unsafe`
    25  
    26      `github.com/bytedance/sonic/internal/caching`
    27      `github.com/bytedance/sonic/internal/jit`
    28      `github.com/bytedance/sonic/internal/native/types`
    29      `github.com/bytedance/sonic/internal/rt`
    30      `github.com/stretchr/testify/assert`
    31      `github.com/stretchr/testify/require`
    32  )
    33  
    34  var utextVar []byte
    35  type UtextValue int
    36  
    37  func (UtextValue) UnmarshalText(text []byte) error {
    38      utextVar = text
    39      return nil
    40  }
    41  
    42  var ujsonVar []byte
    43  type UjsonValue int
    44  
    45  func (UjsonValue) UnmarshalJSON(json []byte) error {
    46      ujsonVar = json
    47      return nil
    48  }
    49  
    50  type UtextStruct struct {
    51      V string
    52  }
    53  
    54  func (self *UtextStruct) UnmarshalText(text []byte) error {
    55      self.V = string(text)
    56      return nil
    57  }
    58  
    59  type UjsonStruct struct {
    60      V string
    61  }
    62  
    63  func (self *UjsonStruct) UnmarshalJSON(v []byte) error {
    64      self.V = string(v)
    65      return nil
    66  }
    67  
    68  const (
    69      _OP_dbg_get_sr _Op = 253
    70      _OP_dbg_set_sr _Op = 254
    71      _OP_dbg_break  _Op = 255
    72  )
    73  
    74  func (self *_Assembler) _asm_OP_dbg_get_sr(_ *_Instr) {
    75      self.Emit("MOVQ", _VAR_sr, _AX)
    76      self.Emit("MOVQ", _AX, jit.Ptr(_VP, 0))
    77  }
    78  
    79  func (self *_Assembler) _asm_OP_dbg_set_sr(p *_Instr) {
    80      self.Emit("MOVQ", jit.Imm(p.i64()), _AX)
    81      self.Emit("MOVQ", _AX, _VAR_sr)
    82  }
    83  
    84  func (self *_Assembler) _asm_OP_dbg_break(_ *_Instr) {
    85      self.Byte(0xcc)
    86  }
    87  
    88  func init() {
    89      _OpNames[_OP_dbg_get_sr] = "dbg_get_sr"
    90      _OpNames[_OP_dbg_set_sr] = "dbg_set_sr"
    91      _OpNames[_OP_dbg_break]  = "dbg_break"
    92      _OpFuncTab[_OP_dbg_get_sr] = (*_Assembler)._asm_OP_dbg_get_sr
    93      _OpFuncTab[_OP_dbg_set_sr] = (*_Assembler)._asm_OP_dbg_set_sr
    94      _OpFuncTab[_OP_dbg_break]  = (*_Assembler)._asm_OP_dbg_break
    95  }
    96  
    97  type testOps struct {
    98      key string
    99      ins _Program
   100      src string
   101      pos int
   102      opt uint64
   103      vfn func(i int, v interface{})
   104      exp interface{}
   105      err error
   106      val interface{}
   107  }
   108  
   109  func testOpCode(t *testing.T, ops *testOps) {
   110      p := ops.ins
   111      k := new(_Stack)
   112      a := newAssembler(p)
   113      f := a.Load()
   114      i, e := f(ops.src, ops.pos, rt.UnpackEface(ops.val).Value, k, ops.opt, "", nil)
   115      if ops.err != nil {
   116          assert.EqualError(t, e, ops.err.Error())
   117      } else {
   118          assert.NoError(t, e)
   119          if ops.vfn != nil {
   120              if ops.val == nil {
   121                  ops.vfn(i, nil)
   122              } else {
   123                  ops.vfn(i, reflect.Indirect(reflect.ValueOf(ops.val)).Interface())
   124              }
   125          } else {
   126              if ops.val == nil {
   127                  assert.Nil(t, ops.exp)
   128              } else {
   129                  assert.Equal(t, ops.exp, reflect.Indirect(reflect.ValueOf(ops.val)).Interface())
   130              }
   131          }
   132      }
   133  }
   134  
   135  func TestAssembler_OpCode(t *testing.T) {
   136      tests := []testOps{
   137      {
   138          key: "_OP_any/stdlib",
   139          ins: []_Instr{newInsOp(_OP_any)},
   140          src: `{"a": [1, 2, 3]}`,
   141          exp: map[string]interface{}{"a": []interface{}{1.0, 2.0, 3.0}},
   142          val: new(interface{}),
   143      }, 
   144      {
   145          key: "_OP_any/use_int64",
   146          ins: []_Instr{newInsOp(_OP_any)},
   147          src: `{"a": [1, 2, 3]}`,
   148          opt: 1 << _F_use_int64,
   149          exp: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}},
   150          val: new(interface{}),
   151      }, 
   152      {
   153          key: "_OP_any/use_number",
   154          ins: []_Instr{newInsOp(_OP_any)},
   155          src: `{"a": [1, 2, 3]}`,
   156          opt: 1 << _F_use_number,
   157          exp: map[string]interface{}{"a": []interface{}{json.Number("1"), json.Number("2"), json.Number("3")}},
   158          val: new(interface{}),
   159      }, 
   160      {
   161          key: "_OP_str/plain",
   162          ins: []_Instr{newInsOp(_OP_str)},
   163          src: `hello, world"`,
   164          exp: "hello, world",
   165          val: new(string),
   166      }, {
   167          key: "_OP_str/unquote",
   168          ins: []_Instr{newInsOp(_OP_str)},
   169          src: `hello, world \\ \" \/ \b \f \n \r \t \u666f 测试中文 \ud83d\ude00"`,
   170          exp: "hello, world \\ \" / \b \f \n \r \t 景 测试中文 😀",
   171          val: new(string),
   172      }, {
   173          key: "_OP_str/unquote_unirep",
   174          ins: []_Instr{newInsOp(_OP_str)},
   175          src: `hello\ud800world"`,
   176          exp: "hello\ufffdworld",
   177          val: new(string),
   178      }, {
   179          key: "_OP_str/error_eof",
   180          ins: []_Instr{newInsOp(_OP_str)},
   181          src: `12345`,
   182          err: SyntaxError{Src: `12345`, Pos: 5, Code: types.ERR_EOF},
   183          val: new(string),
   184      }, {
   185          key: "_OP_str/error_invalid_escape",
   186          ins: []_Instr{newInsOp(_OP_str)},
   187          src: `12\g345"`,
   188          err: SyntaxError{Src: `12\g345"`, Pos: 3, Code: types.ERR_INVALID_ESCAPE},
   189          val: new(string),
   190      }, {
   191          key: "_OP_str/error_invalid_unicode",
   192          ins: []_Instr{newInsOp(_OP_str)},
   193          src: `hello\ud800world"`,
   194          opt: 1 << _F_disable_urc,
   195          err: SyntaxError{Src: `hello\ud800world"`, Pos: 7, Code: types.ERR_INVALID_UNICODE},
   196          val: new(string),
   197      }, {
   198          key: "_OP_str/error_invalid_char",
   199          ins: []_Instr{newInsOp(_OP_str)},
   200          src: `12\u1ggg345"`,
   201          err: SyntaxError{Src: `12\u1ggg345"`, Pos: 5, Code: types.ERR_INVALID_CHAR},
   202          val: new(string),
   203      }, {
   204          key: "_OP_bin",
   205          ins: []_Instr{newInsOp(_OP_bin)},
   206          src: `aGVsbG8sIHdvcmxk"`,
   207          exp: []byte("hello, world"),
   208          val: new([]byte),
   209      }, {
   210          key: "_OP_bin/error_eof",
   211          ins: []_Instr{newInsOp(_OP_bin)},
   212          src: `aGVsbG8sIHdvcmxk`,
   213          err: SyntaxError{Src: `aGVsbG8sIHdvcmxk`, Pos: 16, Code: types.ERR_EOF},
   214          val: new([]byte),
   215      }, {
   216          key: "_OP_bin/error_corrupt_input",
   217          ins: []_Instr{newInsOp(_OP_bin)},
   218          src: `aGVsbG8!sIHdvcmxk"`,
   219          err: base64.CorruptInputError(7),
   220          val: new([]byte),
   221      }, {
   222          key: "_OP_bool/true",
   223          ins: []_Instr{newInsOp(_OP_bool)},
   224          src: "true",
   225          exp: true,
   226          val: new(bool),
   227      }, 
   228      {
   229          key: "_OP_bool/skip",
   230          ins: []_Instr{newInsOp(_OP_bool)},
   231          src: `"true"`,
   232          exp: nil,
   233          val: new(bool),
   234          err: &MismatchTypeError{Src: `"true"`, Pos: 0, Type: reflect.TypeOf(true)},
   235      }, 
   236      {
   237          key: "_OP_bool/false",
   238          ins: []_Instr{newInsOp(_OP_bool)},
   239          src: "false",
   240          exp: false,
   241          val: new(bool),
   242      }, {
   243          key: "_OP_bool/false_pos",
   244          ins: []_Instr{newInsOp(_OP_bool)},
   245          src: "false",
   246          vfn: func(i int, v interface{}) { require.False(t, v.(bool)); assert.Equal(t, 5, i) },
   247          val: new(bool),
   248      }, {
   249          key: "_OP_bool/error_eof_1",
   250          ins: []_Instr{newInsOp(_OP_bool)},
   251          src: "tru",
   252          err: SyntaxError{Src: `tru`, Pos: 3, Code: types.ERR_EOF},
   253          val: new(bool),
   254      }, {
   255          key: "_OP_bool/error_eof_2",
   256          ins: []_Instr{newInsOp(_OP_bool)},
   257          src: "fals",
   258          err: SyntaxError{Src: `fals`, Pos: 4, Code: types.ERR_EOF},
   259          val: new(bool),
   260      }, {
   261          key: "_OP_bool/error_invalid_char_1",
   262          ins: []_Instr{newInsOp(_OP_bool)},
   263          src: "falxe",
   264          err: SyntaxError{Src: `falxe`, Pos: 3, Code: types.ERR_INVALID_CHAR},
   265          val: new(bool),
   266      }, {
   267          key: "_OP_bool/error_invalid_char_2",
   268          ins: []_Instr{newInsOp(_OP_bool)},
   269          src: "falsx",
   270          err: SyntaxError{Src: `falsx`, Pos: 4, Code: types.ERR_INVALID_CHAR},
   271          val: new(bool),
   272      },
   273      {
   274          key: "_OP_num/positive",
   275          ins: []_Instr{newInsOp(_OP_num)},
   276          src: "1.234e5",
   277          exp: json.Number("1.234e5"),
   278          val: new(json.Number),
   279      }, {
   280          key: "_OP_num/negative",
   281          ins: []_Instr{newInsOp(_OP_num)},
   282          src: "-1.234e5",
   283          exp: json.Number("-1.234e5"),
   284          val: new(json.Number),
   285      }, {
   286          key: "_OP_num/error_eof",
   287          ins: []_Instr{newInsOp(_OP_num)},
   288          src: "-",
   289          err: SyntaxError{Src: `-`, Pos: 1, Code: types.ERR_INVALID_CHAR},
   290          val: new(json.Number),
   291      }, {
   292          key: "_OP_num/error_invalid_char",
   293          ins: []_Instr{newInsOp(_OP_num)},
   294          src: "xxx",
   295          err: SyntaxError{Src: `xxx`, Pos: 1, Code: types.ERR_INVALID_CHAR},
   296          val: new(json.Number),
   297      }, {
   298          key: "_OP_i8",
   299          ins: []_Instr{newInsOp(_OP_i8)},
   300          src: "123",
   301          exp: int8(123),
   302          val: new(int8),
   303      }, {
   304          key: "_OP_i8/error_overflow",
   305          ins: []_Instr{newInsOp(_OP_i8)},
   306          src: "1234",
   307          err: error_value("1234", reflect.TypeOf(int8(0))),
   308          val: new(int8),
   309      }, 
   310      {
   311          key: "_OP_i8/error_wrong_type",
   312          ins: []_Instr{newInsOp(_OP_i8)},
   313          src: "12.34",
   314          err: &MismatchTypeError{Src: `12.34`, Pos: 0, Type: int8Type},
   315          val: new(int8),
   316      }, {
   317          key: "_OP_u8",
   318          ins: []_Instr{newInsOp(_OP_u8)},
   319          src: "234",
   320          exp: uint8(234),
   321          val: new(uint8),
   322      }, {
   323          key: "_OP_u8/error_overflow",
   324          ins: []_Instr{newInsOp(_OP_u8)},
   325          src: "1234",
   326          err: error_value("1234", reflect.TypeOf(uint8(0))),
   327          val: new(uint8),
   328      }, {
   329          key: "_OP_u8/error_underflow",
   330          ins: []_Instr{newInsOp(_OP_u8)},
   331          src: "-123",
   332          err: &MismatchTypeError{Src: `-123`, Pos: 0, Type: uint8Type},
   333          val: new(uint8),
   334      }, {
   335          key: "_OP_u8/error_wrong_type",
   336          ins: []_Instr{newInsOp(_OP_u8)},
   337          src: "12.34",
   338          err: &MismatchTypeError{Src: `12.34`, Pos: 0, Type: uint8Type},
   339          val: new(uint8),
   340      }, {
   341          key: "_OP_f32",
   342          ins: []_Instr{newInsOp(_OP_f32)},
   343          src: "1.25e20",
   344          exp: float32(1.25e20),
   345          val: new(float32),
   346      }, {
   347          key: "_OP_f32/overflow",
   348          ins: []_Instr{newInsOp(_OP_f32)},
   349          src: "1.25e50",
   350          err: error_value("1.25e50", reflect.TypeOf(float32(0))),
   351          val: new(float32),
   352      }, {
   353          key: "_OP_f32/underflow",
   354          ins: []_Instr{newInsOp(_OP_f32)},
   355          src: "-1.25e50",
   356          err: error_value("-1.25e50", reflect.TypeOf(float32(0))),
   357          val: new(float32),
   358      }, {
   359          key: "_OP_f64",
   360          ins: []_Instr{newInsOp(_OP_f64)},
   361          src: "1.25e123",
   362          exp: 1.25e123,
   363          val: new(float64),
   364      }, {
   365          key: "_OP_unquote/plain",
   366          ins: []_Instr{newInsOp(_OP_unquote)},
   367          src: `\"hello, world\""`,
   368          exp: "hello, world",
   369          val: new(string),
   370      }, {
   371          key: "_OP_unquote/unquote",
   372          ins: []_Instr{newInsOp(_OP_unquote)},
   373          src: `\"hello, world \\\\ \\\" \\/ \\b \\f \\n \\r \\t \\u666f 测试中文 \\ud83d\\ude00\""`,
   374          exp: "hello, world \\ \" / \b \f \n \r \t 景 测试中文 😀",
   375          val: new(string),
   376      }, {
   377          key: "_OP_unquote/error_invalid_end",
   378          ins: []_Instr{newInsOp(_OP_unquote)},
   379          src: `\"te\\\"st"`,
   380          err: SyntaxError{Src: `\"te\\\"st"`, Pos: 8, Code: types.ERR_INVALID_CHAR},
   381          val: new(string),
   382      }, {
   383          key: "_OP_nil_1",
   384          ins: []_Instr{newInsOp(_OP_nil_1)},
   385          src: "",
   386          exp: 0,
   387          val: (func() *int { v := new(int); *v = 123; return v })(),
   388      }, {
   389          key: "_OP_nil_2",
   390          ins: []_Instr{newInsOp(_OP_nil_2)},
   391          src: "",
   392          exp: error(nil),
   393          val: (func() *error { v := new(error); *v = types.ERR_EOF; return v })(),
   394      }, {
   395          key: "_OP_nil_3",
   396          ins: []_Instr{newInsOp(_OP_nil_3)},
   397          src: "",
   398          exp: []byte(nil),
   399          val: &[]byte{1, 2, 3},
   400      }, {
   401          key: "_OP_deref",
   402          ins: []_Instr{newInsVt(_OP_deref, reflect.TypeOf(0))},
   403          src: "",
   404          vfn: func(_ int, v interface{}) { require.NotNil(t, v); assert.NotNil(t, v.(*int)) },
   405          val: new(*int),
   406      }, {
   407          key: "_OP_map_init",
   408          ins: []_Instr{newInsOp(_OP_map_init)},
   409          src: "",
   410          vfn: func(_ int, v interface{}) { require.NotNil(t, v); assert.NotNil(t, v.(map[string]int)) },
   411          val: new(map[string]int),
   412      }, {
   413          key: "_OP_map_key_i8",
   414          ins: []_Instr{newInsVt(_OP_map_key_i8, reflect.TypeOf(map[int8]int{}))},
   415          src: `123"`,
   416          exp: map[int8]int{123: 0},
   417          val: map[int8]int{},
   418      }, {
   419          key: "_OP_map_key_i32",
   420          ins: []_Instr{newInsVt(_OP_map_key_i32, reflect.TypeOf(map[int32]int{}))},
   421          src: `123456789"`,
   422          exp: map[int32]int{123456789: 0},
   423          val: map[int32]int{},
   424      }, {
   425          key: "_OP_map_key_i64",
   426          ins: []_Instr{newInsVt(_OP_map_key_i64, reflect.TypeOf(map[int64]int{}))},
   427          src: `123456789123456789"`,
   428          exp: map[int64]int{123456789123456789: 0},
   429          val: map[int64]int{},
   430      }, {
   431          key: "_OP_map_key_u8",
   432          ins: []_Instr{newInsVt(_OP_map_key_u8, reflect.TypeOf(map[uint8]int{}))},
   433          src: `123"`,
   434          exp: map[uint8]int{123: 0},
   435          val: map[uint8]int{},
   436      }, {
   437          key: "_OP_map_key_u32",
   438          ins: []_Instr{newInsVt(_OP_map_key_u32, reflect.TypeOf(map[uint32]int{}))},
   439          src: `123456789"`,
   440          exp: map[uint32]int{123456789: 0},
   441          val: map[uint32]int{},
   442      }, {
   443          key: "_OP_map_key_u64",
   444          ins: []_Instr{newInsVt(_OP_map_key_u64, reflect.TypeOf(map[uint64]int{}))},
   445          src: `123456789123456789"`,
   446          exp: map[uint64]int{123456789123456789: 0},
   447          val: map[uint64]int{},
   448      }, {
   449          key: "_OP_map_key_f32",
   450          ins: []_Instr{newInsVt(_OP_map_key_f32, reflect.TypeOf(map[float32]int{}))},
   451          src: `1.25"`,
   452          exp: map[float32]int{1.25: 0},
   453          val: map[float32]int{},
   454      }, {
   455          key: "_OP_map_key_f64",
   456          ins: []_Instr{newInsVt(_OP_map_key_f64, reflect.TypeOf(map[float64]int{}))},
   457          src: `1.25"`,
   458          exp: map[float64]int{1.25: 0},
   459          val: map[float64]int{},
   460      }, {
   461          key: "_OP_map_key_str/plain",
   462          ins: []_Instr{newInsVt(_OP_map_key_str, reflect.TypeOf(map[string]int{}))},
   463          src: `foo"`,
   464          exp: map[string]int{"foo": 0},
   465          val: map[string]int{},
   466      }, {
   467          key: "_OP_map_key_str/unquote",
   468          ins: []_Instr{newInsVt(_OP_map_key_str, reflect.TypeOf(map[string]int{}))},
   469          src: `foo\nbar"`,
   470          exp: map[string]int{"foo\nbar": 0},
   471          val: map[string]int{},
   472      }, 
   473      {
   474          key: "_OP_map_key_utext/value",
   475          ins: []_Instr{newInsVt(_OP_map_key_utext, reflect.TypeOf(map[UtextValue]int{}))},
   476          src: `foo"`,
   477          vfn: func(_ int, v interface{}) {
   478              m := v.(map[UtextValue]int)
   479              assert.Equal(t, 1, len(m))
   480              for k := range m {
   481                  assert.Equal(t, UtextValue(0), k)
   482              }
   483              assert.Equal(t, []byte("foo"), utextVar)
   484          },
   485          val: map[UtextValue]int{},
   486      }, 
   487      {
   488          key: "_OP_map_key_utext/pointer",
   489          ins: []_Instr{newInsVt(_OP_map_key_utext, reflect.TypeOf(map[*UtextStruct]int{}))},
   490          src: `foo"`,
   491          vfn: func(_ int, v interface{}) {
   492              m := v.(map[*UtextStruct]int)
   493              assert.Equal(t, 1, len(m))
   494              for k := range m {
   495                  assert.Equal(t, "foo", k.V)
   496              }
   497          },
   498          val: map[*UtextStruct]int{},
   499      }, 
   500      {
   501          key: "_OP_map_key_utext_p",
   502          ins: []_Instr{newInsVt(_OP_map_key_utext_p, reflect.TypeOf(map[UtextStruct]int{}))},
   503          src: `foo"`,
   504          exp: map[UtextStruct]int{UtextStruct{V: "foo"}: 0},
   505          val: map[UtextStruct]int{},
   506      }, 
   507      {
   508          key: "_OP_array_skip",
   509          ins: []_Instr{newInsOp(_OP_array_skip)},
   510          src: `[1,2.0,true,false,null,"asdf",{"qwer":[1,2,3,4]}]`,
   511          pos: 1,
   512          vfn: func(i int, _ interface{}) { assert.Equal(t, 49, i) },
   513          val: nil,
   514      },{
   515          key: "_OP_slice_init",
   516          ins: []_Instr{newInsVt(_OP_slice_init, reflect.TypeOf(0))},
   517          src: "",
   518          vfn: func(_ int, v interface{}) {
   519              require.NotNil(t, v)
   520              assert.Equal(t, 0, len(v.([]int)))
   521              assert.Equal(t, _MinSlice, cap(v.([]int)))
   522          },
   523          val: new([]int),
   524      }, {
   525          key: "_OP_slice_append",
   526          ins: []_Instr{newInsVt(_OP_slice_append, reflect.TypeOf(0)), newInsOp(_OP_nil_1)},
   527          src: "",
   528          exp: []int{123, 0},
   529          val: &[]int{123},
   530      }, {
   531          key: "_OP_object_skip",
   532          ins: []_Instr{newInsOp(_OP_object_skip)},
   533          src: `{"zxcv":[1,2.0],"asdf":[true,false,null,"asdf",{"qwer":345}]}`,
   534          pos: 1,
   535          vfn: func(i int, _ interface{}) { assert.Equal(t, 61, i) },
   536          val: nil,
   537      }, {
   538          key: "_OP_object_next",
   539          ins: []_Instr{newInsOp(_OP_object_next)},
   540          src: `{"asdf":[1,2.0,true,false,null,"asdf",{"qwer":345}]}`,
   541          vfn: func(i int, _ interface{}) { assert.Equal(t, 52, i) },
   542          val: nil,
   543      }, {
   544          key: "_OP_struct_field",
   545          ins: []_Instr{
   546              newInsVf(_OP_struct_field, (func() *caching.FieldMap {
   547                  ret := caching.CreateFieldMap(2)
   548                  ret.Set("bab", 1)
   549                  ret.Set("bac", 2)
   550                  ret.Set("bad", 3)
   551                  return ret
   552              })()),
   553              newInsOp(_OP_dbg_get_sr),
   554          },
   555          src: `bac"`,
   556          exp: 2,
   557          val: new(int),
   558      }, {
   559          key: "_OP_struct_field/case_insensitive",
   560          ins: []_Instr{
   561              newInsVf(_OP_struct_field, (func() *caching.FieldMap {
   562                  ret := caching.CreateFieldMap(2)
   563                  ret.Set("Bac", 2)
   564                  ret.Set("BAC", 1)
   565                  ret.Set("baC", 3)
   566                  return ret
   567              })()),
   568              newInsOp(_OP_dbg_get_sr),
   569          },
   570          src: `bac"`,
   571          exp: 1,
   572          val: new(int),
   573      }, {
   574          key: "_OP_struct_field/not_found",
   575          ins: []_Instr{
   576              newInsVf(_OP_struct_field, (func() *caching.FieldMap {
   577                  ret := caching.CreateFieldMap(2)
   578                  ret.Set("bab", 1)
   579                  ret.Set("bac", 2)
   580                  ret.Set("bad", 3)
   581                  return ret
   582              })()),
   583              newInsOp(_OP_dbg_get_sr),
   584          },
   585          src: `bae"`,
   586          exp: -1,
   587          val: new(int),
   588      }, {
   589          key: "_OP_unmarshal/value",
   590          ins: []_Instr{newInsVt(_OP_unmarshal, reflect.TypeOf(UjsonValue(0)))},
   591          src: `{"asdf":[1,2.0,true,false,null,"asdf",{"qwer":345}]}`,
   592          vfn: func(_ int, v interface{}) {
   593              assert.Equal(t, []byte(`{"asdf":[1,2.0,true,false,null,"asdf",{"qwer":345}]}`), ujsonVar)
   594          },
   595          val: new(UjsonValue),
   596      }, {
   597          key: "_OP_unmarshal/pointer",
   598          ins: []_Instr{newInsVt(_OP_unmarshal, reflect.TypeOf(new(UjsonStruct)))},
   599          src: `{"asdf":[1,2.0,true,false,null,"asdf",{"qwer":345}]}`,
   600          exp: &UjsonStruct{V: `{"asdf":[1,2.0,true,false,null,"asdf",{"qwer":345}]}`},
   601          val: new(*UjsonStruct),
   602      }, {
   603          key: "_OP_unmarshal_p",
   604          ins: []_Instr{newInsVt(_OP_unmarshal_p, reflect.TypeOf(new(UjsonStruct)))},
   605          src: `{"asdf":[1,2.0,true,false,null,"asdf",{"qwer":345}]}`,
   606          exp: UjsonStruct{V: `{"asdf":[1,2.0,true,false,null,"asdf",{"qwer":345}]}`},
   607          val: new(UjsonStruct),
   608      }, {
   609          key: "_OP_unmarshal_text/value",
   610          ins: []_Instr{newInsVt(_OP_unmarshal_text, reflect.TypeOf(UtextValue(0)))},
   611          src: `hello\n\r\tworld"`,
   612          vfn: func(_ int, v interface{}) {
   613              assert.Equal(t, []byte("hello\n\r\tworld"), utextVar)
   614          },
   615          val: new(UtextValue),
   616      }, {
   617          key: "_OP_unmarshal_text/pointer",
   618          ins: []_Instr{newInsVt(_OP_unmarshal_text, reflect.TypeOf(new(UtextStruct)))},
   619          src: `hello\n\r\tworld"`,
   620          exp: &UtextStruct{V: "hello\n\r\tworld"},
   621          val: new(*UtextStruct),
   622      }, {
   623          key: "_OP_unmarshal_text_p",
   624          ins: []_Instr{newInsVt(_OP_unmarshal_text_p, reflect.TypeOf(new(UtextStruct)))},
   625          src: `hello\n\r\tworld"`,
   626          exp: UtextStruct{V: "hello\n\r\tworld"},
   627          val: new(UtextStruct),
   628      }, {
   629          key: "_OP_lspace",
   630          ins: []_Instr{newInsOp(_OP_lspace)},
   631          src: " \t\r\na",
   632          vfn: func(i int, _ interface{}) { assert.Equal(t, 4, i) },
   633          val: nil,
   634      }, {
   635          key: "_OP_lspace/error",
   636          ins: []_Instr{newInsOp(_OP_lspace)},
   637          src: "",
   638          err: SyntaxError{Src: ``, Pos: 0, Code: types.ERR_EOF},
   639          val: nil,
   640      }, {
   641          key: "_OP_match_char/correct",
   642          ins: []_Instr{newInsVb(_OP_match_char, 'a')},
   643          src: "a",
   644          exp: nil,
   645          val: nil,
   646      }, {
   647          key: "_OP_match_char/error",
   648          ins: []_Instr{newInsVb(_OP_match_char, 'b')},
   649          src: "a",
   650          err: SyntaxError{Src: `a`, Pos: 0, Code: types.ERR_INVALID_CHAR},
   651          val: nil,
   652      }, {
   653          key: "_OP_switch",
   654          ins: []_Instr{
   655              newInsVi(_OP_dbg_set_sr, 1),
   656              newInsVs(_OP_switch, []int{4, 6, 8}),
   657              newInsOp(_OP_i8),
   658              newInsVi(_OP_goto, 9),
   659              newInsOp(_OP_i16),
   660              newInsVi(_OP_goto, 9),
   661              newInsOp(_OP_i32),
   662              newInsVi(_OP_goto, 9),
   663              newInsOp(_OP_u8),
   664          },
   665          src: "-1234567",
   666          exp: int32(-1234567),
   667          val: new(int32),
   668      },
   669      }
   670      for _, tv := range tests {
   671          t.Run(tv.key, func(t *testing.T) {
   672              println(tv.key)
   673              testOpCode(t, &tv)
   674          })
   675      }
   676  }
   677  
   678  type JsonStruct struct {
   679      A int
   680      B string
   681      C map[string]int
   682      D []int
   683  }
   684  
   685  func TestAssembler_DecodeStruct(t *testing.T) {
   686      var v JsonStruct
   687      s := `{"A": 123, "B": "asdf", "C": {"qwer": 4567}, "D": [1, 2, 3, 4, 5]}`
   688      p, err := newCompiler().compile(reflect.TypeOf(v))
   689      require.NoError(t, err)
   690      k := new(_Stack)
   691      a := newAssembler(p)
   692      f := a.Load()
   693      pos, err := f(s, 0, unsafe.Pointer(&v), k, 0, "", nil)
   694      require.NoError(t, err)
   695      assert.Equal(t, len(s), pos)
   696      assert.Equal(t, JsonStruct{
   697          A: 123,
   698          B: "asdf",
   699          C: map[string]int{"qwer": 4567},
   700          D: []int{1, 2, 3, 4, 5},
   701      }, v)
   702  }
   703  
   704  func TestAssembler_PrologueAndEpilogue(t *testing.T) {
   705      a := newAssembler(nil)
   706      _, e := a.Load()("", 0, nil, nil, 0, "", nil)
   707      assert.Nil(t, e)
   708  }
   709  
   710  type Tx struct {
   711      x int
   712  }
   713  
   714  func TestAssembler_DecodeStruct_SinglePrivateField(t *testing.T) {
   715      var v Tx
   716      s := `{"x": 1}`
   717      p, err := newCompiler().compile(reflect.TypeOf(v))
   718      require.NoError(t, err)
   719      k := new(_Stack)
   720      a := newAssembler(p)
   721      f := a.Load()
   722      pos, err := f(s, 0, unsafe.Pointer(&v), k, 0, "", nil)
   723      require.NoError(t, err)
   724      assert.Equal(t, len(s), pos)
   725      assert.Equal(t, Tx{}, v)
   726  }
   727  
   728  func TestAssembler_DecodeByteSlice_Bin(t *testing.T) {
   729      var v []byte
   730      s := `"aGVsbG8sIHdvcmxk"`
   731      p, err := newCompiler().compile(reflect.TypeOf(v))
   732      require.NoError(t, err)
   733      k := new(_Stack)
   734      a := newAssembler(p)
   735      f := a.Load()
   736      pos, err := f(s, 0, unsafe.Pointer(&v), k, 0, "", nil)
   737      require.NoError(t, err)
   738      assert.Equal(t, len(s), pos)
   739      assert.Equal(t, []byte("hello, world"), v)
   740  }
   741  
   742  func TestAssembler_DecodeByteSlice_List(t *testing.T) {
   743      var v []byte
   744      s := `[104, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100]`
   745      p, err := newCompiler().compile(reflect.TypeOf(v))
   746      require.NoError(t, err)
   747      k := new(_Stack)
   748      a := newAssembler(p)
   749      f := a.Load()
   750      pos, err := f(s, 0, unsafe.Pointer(&v), k, 0, "", nil)
   751      require.NoError(t, err)
   752      assert.Equal(t, len(s), pos)
   753      assert.Equal(t, []byte("hello, world"), v)
   754  }