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