github.com/night-codes/go-json@v0.9.15/internal/encoder/code.go (about)

     1  package encoder
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"unsafe"
     7  
     8  	"github.com/night-codes/go-json/internal/runtime"
     9  )
    10  
    11  type Code interface {
    12  	Kind() CodeKind
    13  	ToOpcode(*compileContext) Opcodes
    14  	Filter(*FieldQuery) Code
    15  }
    16  
    17  type AnonymousCode interface {
    18  	ToAnonymousOpcode(*compileContext) Opcodes
    19  }
    20  
    21  type Opcodes []*Opcode
    22  
    23  func (o Opcodes) First() *Opcode {
    24  	if len(o) == 0 {
    25  		return nil
    26  	}
    27  	return o[0]
    28  }
    29  
    30  func (o Opcodes) Last() *Opcode {
    31  	if len(o) == 0 {
    32  		return nil
    33  	}
    34  	return o[len(o)-1]
    35  }
    36  
    37  func (o Opcodes) Add(codes ...*Opcode) Opcodes {
    38  	return append(o, codes...)
    39  }
    40  
    41  type CodeKind int
    42  
    43  const (
    44  	CodeKindInterface CodeKind = iota
    45  	CodeKindPtr
    46  	CodeKindInt
    47  	CodeKindUint
    48  	CodeKindFloat
    49  	CodeKindString
    50  	CodeKindBool
    51  	CodeKindStruct
    52  	CodeKindMap
    53  	CodeKindSlice
    54  	CodeKindArray
    55  	CodeKindBytes
    56  	CodeKindMarshalJSON
    57  	CodeKindMarshalText
    58  	CodeKindRecursive
    59  )
    60  
    61  type IntCode struct {
    62  	typ      *runtime.Type
    63  	bitSize  uint8
    64  	isString bool
    65  	isPtr    bool
    66  }
    67  
    68  func (c *IntCode) Kind() CodeKind {
    69  	return CodeKindInt
    70  }
    71  
    72  func (c *IntCode) ToOpcode(ctx *compileContext) Opcodes {
    73  	var code *Opcode
    74  	switch {
    75  	case c.isPtr:
    76  		code = newOpCode(ctx, c.typ, OpIntPtr)
    77  	case c.isString:
    78  		code = newOpCode(ctx, c.typ, OpIntString)
    79  	default:
    80  		code = newOpCode(ctx, c.typ, OpInt)
    81  	}
    82  	code.NumBitSize = c.bitSize
    83  	ctx.incIndex()
    84  	return Opcodes{code}
    85  }
    86  
    87  func (c *IntCode) Filter(_ *FieldQuery) Code {
    88  	return c
    89  }
    90  
    91  type UintCode struct {
    92  	typ      *runtime.Type
    93  	bitSize  uint8
    94  	isString bool
    95  	isPtr    bool
    96  }
    97  
    98  func (c *UintCode) Kind() CodeKind {
    99  	return CodeKindUint
   100  }
   101  
   102  func (c *UintCode) ToOpcode(ctx *compileContext) Opcodes {
   103  	var code *Opcode
   104  	switch {
   105  	case c.isPtr:
   106  		code = newOpCode(ctx, c.typ, OpUintPtr)
   107  	case c.isString:
   108  		code = newOpCode(ctx, c.typ, OpUintString)
   109  	default:
   110  		code = newOpCode(ctx, c.typ, OpUint)
   111  	}
   112  	code.NumBitSize = c.bitSize
   113  	ctx.incIndex()
   114  	return Opcodes{code}
   115  }
   116  
   117  func (c *UintCode) Filter(_ *FieldQuery) Code {
   118  	return c
   119  }
   120  
   121  type FloatCode struct {
   122  	typ     *runtime.Type
   123  	bitSize uint8
   124  	isPtr   bool
   125  }
   126  
   127  func (c *FloatCode) Kind() CodeKind {
   128  	return CodeKindFloat
   129  }
   130  
   131  func (c *FloatCode) ToOpcode(ctx *compileContext) Opcodes {
   132  	var code *Opcode
   133  	switch {
   134  	case c.isPtr:
   135  		switch c.bitSize {
   136  		case 32:
   137  			code = newOpCode(ctx, c.typ, OpFloat32Ptr)
   138  		default:
   139  			code = newOpCode(ctx, c.typ, OpFloat64Ptr)
   140  		}
   141  	default:
   142  		switch c.bitSize {
   143  		case 32:
   144  			code = newOpCode(ctx, c.typ, OpFloat32)
   145  		default:
   146  			code = newOpCode(ctx, c.typ, OpFloat64)
   147  		}
   148  	}
   149  	ctx.incIndex()
   150  	return Opcodes{code}
   151  }
   152  
   153  func (c *FloatCode) Filter(_ *FieldQuery) Code {
   154  	return c
   155  }
   156  
   157  type StringCode struct {
   158  	typ   *runtime.Type
   159  	isPtr bool
   160  }
   161  
   162  func (c *StringCode) Kind() CodeKind {
   163  	return CodeKindString
   164  }
   165  
   166  func (c *StringCode) ToOpcode(ctx *compileContext) Opcodes {
   167  	isJSONNumberType := c.typ == runtime.Type2RType(jsonNumberType)
   168  	var code *Opcode
   169  	if c.isPtr {
   170  		if isJSONNumberType {
   171  			code = newOpCode(ctx, c.typ, OpNumberPtr)
   172  		} else {
   173  			code = newOpCode(ctx, c.typ, OpStringPtr)
   174  		}
   175  	} else {
   176  		if isJSONNumberType {
   177  			code = newOpCode(ctx, c.typ, OpNumber)
   178  		} else {
   179  			code = newOpCode(ctx, c.typ, OpString)
   180  		}
   181  	}
   182  	ctx.incIndex()
   183  	return Opcodes{code}
   184  }
   185  
   186  func (c *StringCode) Filter(_ *FieldQuery) Code {
   187  	return c
   188  }
   189  
   190  type BoolCode struct {
   191  	typ   *runtime.Type
   192  	isPtr bool
   193  }
   194  
   195  func (c *BoolCode) Kind() CodeKind {
   196  	return CodeKindBool
   197  }
   198  
   199  func (c *BoolCode) ToOpcode(ctx *compileContext) Opcodes {
   200  	var code *Opcode
   201  	switch {
   202  	case c.isPtr:
   203  		code = newOpCode(ctx, c.typ, OpBoolPtr)
   204  	default:
   205  		code = newOpCode(ctx, c.typ, OpBool)
   206  	}
   207  	ctx.incIndex()
   208  	return Opcodes{code}
   209  }
   210  
   211  func (c *BoolCode) Filter(_ *FieldQuery) Code {
   212  	return c
   213  }
   214  
   215  type BytesCode struct {
   216  	typ   *runtime.Type
   217  	isPtr bool
   218  }
   219  
   220  func (c *BytesCode) Kind() CodeKind {
   221  	return CodeKindBytes
   222  }
   223  
   224  func (c *BytesCode) ToOpcode(ctx *compileContext) Opcodes {
   225  	var code *Opcode
   226  	switch {
   227  	case c.isPtr:
   228  		code = newOpCode(ctx, c.typ, OpBytesPtr)
   229  	default:
   230  		code = newOpCode(ctx, c.typ, OpBytes)
   231  	}
   232  	ctx.incIndex()
   233  	return Opcodes{code}
   234  }
   235  
   236  func (c *BytesCode) Filter(_ *FieldQuery) Code {
   237  	return c
   238  }
   239  
   240  type SliceCode struct {
   241  	typ   *runtime.Type
   242  	value Code
   243  }
   244  
   245  func (c *SliceCode) Kind() CodeKind {
   246  	return CodeKindSlice
   247  }
   248  
   249  func (c *SliceCode) ToOpcode(ctx *compileContext) Opcodes {
   250  	// header => opcode => elem => end
   251  	//             ^        |
   252  	//             |________|
   253  	size := c.typ.Elem().Size()
   254  	header := newSliceHeaderCode(ctx, c.typ)
   255  	ctx.incIndex()
   256  
   257  	ctx.incIndent()
   258  	codes := c.value.ToOpcode(ctx)
   259  	ctx.decIndent()
   260  
   261  	codes.First().Flags |= IndirectFlags
   262  	elemCode := newSliceElemCode(ctx, c.typ.Elem(), header, size)
   263  	ctx.incIndex()
   264  	end := newOpCode(ctx, c.typ, OpSliceEnd)
   265  	ctx.incIndex()
   266  	header.End = end
   267  	header.Next = codes.First()
   268  	codes.Last().Next = elemCode
   269  	elemCode.Next = codes.First()
   270  	elemCode.End = end
   271  	return Opcodes{header}.Add(codes...).Add(elemCode).Add(end)
   272  }
   273  
   274  func (c *SliceCode) Filter(_ *FieldQuery) Code {
   275  	return c
   276  }
   277  
   278  type ArrayCode struct {
   279  	typ   *runtime.Type
   280  	value Code
   281  }
   282  
   283  func (c *ArrayCode) Kind() CodeKind {
   284  	return CodeKindArray
   285  }
   286  
   287  func (c *ArrayCode) ToOpcode(ctx *compileContext) Opcodes {
   288  	// header => opcode => elem => end
   289  	//             ^        |
   290  	//             |________|
   291  	elem := c.typ.Elem()
   292  	alen := c.typ.Len()
   293  	size := elem.Size()
   294  
   295  	header := newArrayHeaderCode(ctx, c.typ, alen)
   296  	ctx.incIndex()
   297  
   298  	ctx.incIndent()
   299  	codes := c.value.ToOpcode(ctx)
   300  	ctx.decIndent()
   301  
   302  	codes.First().Flags |= IndirectFlags
   303  
   304  	elemCode := newArrayElemCode(ctx, elem, header, alen, size)
   305  	ctx.incIndex()
   306  
   307  	end := newOpCode(ctx, c.typ, OpArrayEnd)
   308  	ctx.incIndex()
   309  
   310  	header.End = end
   311  	header.Next = codes.First()
   312  	codes.Last().Next = elemCode
   313  	elemCode.Next = codes.First()
   314  	elemCode.End = end
   315  
   316  	return Opcodes{header}.Add(codes...).Add(elemCode).Add(end)
   317  }
   318  
   319  func (c *ArrayCode) Filter(_ *FieldQuery) Code {
   320  	return c
   321  }
   322  
   323  type MapCode struct {
   324  	typ   *runtime.Type
   325  	key   Code
   326  	value Code
   327  }
   328  
   329  func (c *MapCode) Kind() CodeKind {
   330  	return CodeKindMap
   331  }
   332  
   333  func (c *MapCode) ToOpcode(ctx *compileContext) Opcodes {
   334  	// header => code => value => code => key => code => value => code => end
   335  	//                                     ^                       |
   336  	//                                     |_______________________|
   337  	header := newMapHeaderCode(ctx, c.typ)
   338  	ctx.incIndex()
   339  
   340  	keyCodes := c.key.ToOpcode(ctx)
   341  
   342  	value := newMapValueCode(ctx, c.typ.Elem(), header)
   343  	ctx.incIndex()
   344  
   345  	ctx.incIndent()
   346  	valueCodes := c.value.ToOpcode(ctx)
   347  	ctx.decIndent()
   348  
   349  	valueCodes.First().Flags |= IndirectFlags
   350  
   351  	key := newMapKeyCode(ctx, c.typ.Key(), header)
   352  	ctx.incIndex()
   353  
   354  	end := newMapEndCode(ctx, c.typ, header)
   355  	ctx.incIndex()
   356  
   357  	header.Next = keyCodes.First()
   358  	keyCodes.Last().Next = value
   359  	value.Next = valueCodes.First()
   360  	valueCodes.Last().Next = key
   361  	key.Next = keyCodes.First()
   362  
   363  	header.End = end
   364  	key.End = end
   365  	value.End = end
   366  	return Opcodes{header}.Add(keyCodes...).Add(value).Add(valueCodes...).Add(key).Add(end)
   367  }
   368  
   369  func (c *MapCode) Filter(_ *FieldQuery) Code {
   370  	return c
   371  }
   372  
   373  type StructCode struct {
   374  	typ                       *runtime.Type
   375  	fields                    []*StructFieldCode
   376  	isPtr                     bool
   377  	disableIndirectConversion bool
   378  	isIndirect                bool
   379  	isRecursive               bool
   380  }
   381  
   382  func (c *StructCode) Kind() CodeKind {
   383  	return CodeKindStruct
   384  }
   385  
   386  func (c *StructCode) lastFieldCode(field *StructFieldCode, firstField *Opcode) *Opcode {
   387  	if isEmbeddedStruct(field) {
   388  		return c.lastAnonymousFieldCode(firstField)
   389  	}
   390  	lastField := firstField
   391  	for lastField.NextField != nil {
   392  		lastField = lastField.NextField
   393  	}
   394  	return lastField
   395  }
   396  
   397  func (c *StructCode) lastAnonymousFieldCode(firstField *Opcode) *Opcode {
   398  	// firstField is special StructHead operation for anonymous structure.
   399  	// So, StructHead's next operation is truly struct head operation.
   400  	lastField := firstField.Next
   401  	for lastField.NextField != nil {
   402  		lastField = lastField.NextField
   403  	}
   404  	return lastField
   405  }
   406  
   407  func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes {
   408  	// header => code => structField => code => end
   409  	//                        ^          |
   410  	//                        |__________|
   411  	if c.isRecursive {
   412  		recursive := newRecursiveCode(ctx, c.typ, &CompiledCode{})
   413  		recursive.Type = c.typ
   414  		ctx.incIndex()
   415  		*ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive)
   416  		return Opcodes{recursive}
   417  	}
   418  	codes := Opcodes{}
   419  	var prevField *Opcode
   420  	ctx.incIndent()
   421  	for idx, field := range c.fields {
   422  		isFirstField := idx == 0
   423  		isEndField := idx == len(c.fields)-1
   424  		fieldCodes := field.ToOpcode(ctx, isFirstField, isEndField)
   425  		for _, code := range fieldCodes {
   426  			if c.isIndirect {
   427  				code.Flags |= IndirectFlags
   428  			}
   429  		}
   430  		firstField := fieldCodes.First()
   431  		if len(codes) > 0 {
   432  			codes.Last().Next = firstField
   433  			firstField.Idx = codes.First().Idx
   434  		}
   435  		if prevField != nil {
   436  			prevField.NextField = firstField
   437  		}
   438  		if isEndField {
   439  			endField := fieldCodes.Last()
   440  			if isEmbeddedStruct(field) {
   441  				firstField.End = endField
   442  				lastField := c.lastAnonymousFieldCode(firstField)
   443  				lastField.NextField = endField
   444  			}
   445  			if len(codes) > 0 {
   446  				codes.First().End = endField
   447  			} else {
   448  				firstField.End = endField
   449  			}
   450  			codes = codes.Add(fieldCodes...)
   451  			break
   452  		}
   453  		prevField = c.lastFieldCode(field, firstField)
   454  		codes = codes.Add(fieldCodes...)
   455  	}
   456  	if len(codes) == 0 {
   457  		head := &Opcode{
   458  			Op:         OpStructHead,
   459  			Idx:        opcodeOffset(ctx.ptrIndex),
   460  			Type:       c.typ,
   461  			DisplayIdx: ctx.opcodeIndex,
   462  			Indent:     ctx.indent,
   463  		}
   464  		ctx.incOpcodeIndex()
   465  		end := &Opcode{
   466  			Op:         OpStructEnd,
   467  			Idx:        opcodeOffset(ctx.ptrIndex),
   468  			DisplayIdx: ctx.opcodeIndex,
   469  			Indent:     ctx.indent,
   470  		}
   471  		head.NextField = end
   472  		head.Next = end
   473  		head.End = end
   474  		codes = codes.Add(head, end)
   475  		ctx.incIndex()
   476  	}
   477  	ctx.decIndent()
   478  	ctx.structTypeToCodes[uintptr(unsafe.Pointer(c.typ))] = codes
   479  	return codes
   480  }
   481  
   482  func (c *StructCode) ToAnonymousOpcode(ctx *compileContext) Opcodes {
   483  	// header => code => structField => code => end
   484  	//                        ^          |
   485  	//                        |__________|
   486  	if c.isRecursive {
   487  		recursive := newRecursiveCode(ctx, c.typ, &CompiledCode{})
   488  		recursive.Type = c.typ
   489  		ctx.incIndex()
   490  		*ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive)
   491  		return Opcodes{recursive}
   492  	}
   493  	codes := Opcodes{}
   494  	var prevField *Opcode
   495  	for idx, field := range c.fields {
   496  		isFirstField := idx == 0
   497  		isEndField := idx == len(c.fields)-1
   498  		fieldCodes := field.ToAnonymousOpcode(ctx, isFirstField, isEndField)
   499  		for _, code := range fieldCodes {
   500  			if c.isIndirect {
   501  				code.Flags |= IndirectFlags
   502  			}
   503  		}
   504  		firstField := fieldCodes.First()
   505  		if len(codes) > 0 {
   506  			codes.Last().Next = firstField
   507  			firstField.Idx = codes.First().Idx
   508  		}
   509  		if prevField != nil {
   510  			prevField.NextField = firstField
   511  		}
   512  		if isEndField {
   513  			lastField := fieldCodes.Last()
   514  			if len(codes) > 0 {
   515  				codes.First().End = lastField
   516  			} else {
   517  				firstField.End = lastField
   518  			}
   519  		}
   520  		prevField = firstField
   521  		codes = codes.Add(fieldCodes...)
   522  	}
   523  	return codes
   524  }
   525  
   526  func (c *StructCode) removeFieldsByTags(tags runtime.StructTags) {
   527  	fields := make([]*StructFieldCode, 0, len(c.fields))
   528  	for _, field := range c.fields {
   529  		if field.isAnonymous {
   530  			structCode := field.getAnonymousStruct()
   531  			if structCode != nil && !structCode.isRecursive {
   532  				structCode.removeFieldsByTags(tags)
   533  				if len(structCode.fields) > 0 {
   534  					fields = append(fields, field)
   535  				}
   536  				continue
   537  			}
   538  		}
   539  		if tags.ExistsKey(field.key) {
   540  			continue
   541  		}
   542  		fields = append(fields, field)
   543  	}
   544  	c.fields = fields
   545  }
   546  
   547  func (c *StructCode) enableIndirect() {
   548  	if c.isIndirect {
   549  		return
   550  	}
   551  	c.isIndirect = true
   552  	if len(c.fields) == 0 {
   553  		return
   554  	}
   555  	structCode := c.fields[0].getStruct()
   556  	if structCode == nil {
   557  		return
   558  	}
   559  	structCode.enableIndirect()
   560  }
   561  
   562  func (c *StructCode) Filter(query *FieldQuery) Code {
   563  	fieldMap := map[string]*FieldQuery{}
   564  	for _, field := range query.Fields {
   565  		fieldMap[field.Name] = field
   566  	}
   567  	fields := make([]*StructFieldCode, 0, len(c.fields))
   568  	for _, field := range c.fields {
   569  		query, exists := fieldMap[field.key]
   570  		if !exists {
   571  			continue
   572  		}
   573  		fieldCode := &StructFieldCode{
   574  			typ:                field.typ,
   575  			key:                field.key,
   576  			tag:                field.tag,
   577  			value:              field.value,
   578  			offset:             field.offset,
   579  			isAnonymous:        field.isAnonymous,
   580  			isTaggedKey:        field.isTaggedKey,
   581  			isNilableType:      field.isNilableType,
   582  			isNilCheck:         field.isNilCheck,
   583  			isAddrForMarshaler: field.isAddrForMarshaler,
   584  			isNextOpPtrType:    field.isNextOpPtrType,
   585  		}
   586  		if len(query.Fields) > 0 {
   587  			fieldCode.value = fieldCode.value.Filter(query)
   588  		}
   589  		fields = append(fields, fieldCode)
   590  	}
   591  	return &StructCode{
   592  		typ:                       c.typ,
   593  		fields:                    fields,
   594  		isPtr:                     c.isPtr,
   595  		disableIndirectConversion: c.disableIndirectConversion,
   596  		isIndirect:                c.isIndirect,
   597  		isRecursive:               c.isRecursive,
   598  	}
   599  }
   600  
   601  type StructFieldCode struct {
   602  	typ                *runtime.Type
   603  	key                string
   604  	tag                *runtime.StructTag
   605  	value              Code
   606  	offset             uintptr
   607  	isAnonymous        bool
   608  	isTaggedKey        bool
   609  	isNilableType      bool
   610  	isNilCheck         bool
   611  	isAddrForMarshaler bool
   612  	isNextOpPtrType    bool
   613  	isMarshalerContext bool
   614  }
   615  
   616  func (c *StructFieldCode) getStruct() *StructCode {
   617  	value := c.value
   618  	ptr, ok := value.(*PtrCode)
   619  	if ok {
   620  		value = ptr.value
   621  	}
   622  	structCode, ok := value.(*StructCode)
   623  	if ok {
   624  		return structCode
   625  	}
   626  	return nil
   627  }
   628  
   629  func (c *StructFieldCode) getAnonymousStruct() *StructCode {
   630  	if !c.isAnonymous {
   631  		return nil
   632  	}
   633  	return c.getStruct()
   634  }
   635  
   636  func optimizeStructHeader(code *Opcode, tag *runtime.StructTag) OpType {
   637  	headType := code.ToHeaderType(tag.IsString)
   638  	if tag.IsOmitEmpty {
   639  		headType = headType.HeadToOmitEmptyHead()
   640  	}
   641  	return headType
   642  }
   643  
   644  func optimizeStructField(code *Opcode, tag *runtime.StructTag) OpType {
   645  	fieldType := code.ToFieldType(tag.IsString)
   646  	if tag.IsOmitEmpty {
   647  		fieldType = fieldType.FieldToOmitEmptyField()
   648  	}
   649  	return fieldType
   650  }
   651  
   652  func (c *StructFieldCode) headerOpcodes(ctx *compileContext, field *Opcode, valueCodes Opcodes) Opcodes {
   653  	value := valueCodes.First()
   654  	op := optimizeStructHeader(value, c.tag)
   655  	field.Op = op
   656  	if value.Flags&MarshalerContextFlags != 0 {
   657  		field.Flags |= MarshalerContextFlags
   658  	}
   659  	field.NumBitSize = value.NumBitSize
   660  	field.PtrNum = value.PtrNum
   661  	field.FieldQuery = value.FieldQuery
   662  	fieldCodes := Opcodes{field}
   663  	if op.IsMultipleOpHead() {
   664  		field.Next = value
   665  		fieldCodes = fieldCodes.Add(valueCodes...)
   666  	} else {
   667  		ctx.decIndex()
   668  	}
   669  	return fieldCodes
   670  }
   671  
   672  func (c *StructFieldCode) fieldOpcodes(ctx *compileContext, field *Opcode, valueCodes Opcodes) Opcodes {
   673  	value := valueCodes.First()
   674  	op := optimizeStructField(value, c.tag)
   675  	field.Op = op
   676  	if value.Flags&MarshalerContextFlags != 0 {
   677  		field.Flags |= MarshalerContextFlags
   678  	}
   679  	field.NumBitSize = value.NumBitSize
   680  	field.PtrNum = value.PtrNum
   681  	field.FieldQuery = value.FieldQuery
   682  
   683  	fieldCodes := Opcodes{field}
   684  	if op.IsMultipleOpField() {
   685  		field.Next = value
   686  		fieldCodes = fieldCodes.Add(valueCodes...)
   687  	} else {
   688  		ctx.decIndex()
   689  	}
   690  	return fieldCodes
   691  }
   692  
   693  func (c *StructFieldCode) addStructEndCode(ctx *compileContext, codes Opcodes) Opcodes {
   694  	end := &Opcode{
   695  		Op:         OpStructEnd,
   696  		Idx:        opcodeOffset(ctx.ptrIndex),
   697  		DisplayIdx: ctx.opcodeIndex,
   698  		Indent:     ctx.indent,
   699  	}
   700  	codes.Last().Next = end
   701  	codes.First().NextField = end
   702  	codes = codes.Add(end)
   703  	ctx.incOpcodeIndex()
   704  	return codes
   705  }
   706  
   707  func (c *StructFieldCode) structKey(ctx *compileContext) string {
   708  	if ctx.escapeKey {
   709  		rctx := &RuntimeContext{Option: &Option{Flag: HTMLEscapeOption}}
   710  		return fmt.Sprintf(`%s:`, string(AppendString(rctx, []byte{}, c.key)))
   711  	}
   712  	return fmt.Sprintf(`"%s":`, c.key)
   713  }
   714  
   715  func (c *StructFieldCode) flags() OpFlags {
   716  	var flags OpFlags
   717  	if c.isTaggedKey {
   718  		flags |= IsTaggedKeyFlags
   719  	}
   720  	if c.isNilableType {
   721  		flags |= IsNilableTypeFlags
   722  	}
   723  	if c.isNilCheck {
   724  		flags |= NilCheckFlags
   725  	}
   726  	if c.isAddrForMarshaler {
   727  		flags |= AddrForMarshalerFlags
   728  	}
   729  	if c.isNextOpPtrType {
   730  		flags |= IsNextOpPtrTypeFlags
   731  	}
   732  	if c.isAnonymous {
   733  		flags |= AnonymousKeyFlags
   734  	}
   735  	if c.isMarshalerContext {
   736  		flags |= MarshalerContextFlags
   737  	}
   738  	return flags
   739  }
   740  
   741  func (c *StructFieldCode) toValueOpcodes(ctx *compileContext) Opcodes {
   742  	if c.isAnonymous {
   743  		anonymCode, ok := c.value.(AnonymousCode)
   744  		if ok {
   745  			return anonymCode.ToAnonymousOpcode(ctx)
   746  		}
   747  	}
   748  	return c.value.ToOpcode(ctx)
   749  }
   750  
   751  func (c *StructFieldCode) ToOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes {
   752  	field := &Opcode{
   753  		Idx:        opcodeOffset(ctx.ptrIndex),
   754  		Flags:      c.flags(),
   755  		Key:        c.structKey(ctx),
   756  		Offset:     uint32(c.offset),
   757  		Type:       c.typ,
   758  		DisplayIdx: ctx.opcodeIndex,
   759  		Indent:     ctx.indent,
   760  		DisplayKey: c.key,
   761  	}
   762  	ctx.incIndex()
   763  	valueCodes := c.toValueOpcodes(ctx)
   764  	if isFirstField {
   765  		codes := c.headerOpcodes(ctx, field, valueCodes)
   766  		if isEndField {
   767  			codes = c.addStructEndCode(ctx, codes)
   768  		}
   769  		return codes
   770  	}
   771  	codes := c.fieldOpcodes(ctx, field, valueCodes)
   772  	if isEndField {
   773  		if isEnableStructEndOptimization(c.value) {
   774  			field.Op = field.Op.FieldToEnd()
   775  		} else {
   776  			codes = c.addStructEndCode(ctx, codes)
   777  		}
   778  	}
   779  	return codes
   780  }
   781  
   782  func (c *StructFieldCode) ToAnonymousOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes {
   783  	field := &Opcode{
   784  		Idx:        opcodeOffset(ctx.ptrIndex),
   785  		Flags:      c.flags() | AnonymousHeadFlags,
   786  		Key:        c.structKey(ctx),
   787  		Offset:     uint32(c.offset),
   788  		Type:       c.typ,
   789  		DisplayIdx: ctx.opcodeIndex,
   790  		Indent:     ctx.indent,
   791  		DisplayKey: c.key,
   792  	}
   793  	ctx.incIndex()
   794  	valueCodes := c.toValueOpcodes(ctx)
   795  	if isFirstField {
   796  		return c.headerOpcodes(ctx, field, valueCodes)
   797  	}
   798  	return c.fieldOpcodes(ctx, field, valueCodes)
   799  }
   800  
   801  func isEnableStructEndOptimization(value Code) bool {
   802  	switch value.Kind() {
   803  	case CodeKindInt,
   804  		CodeKindUint,
   805  		CodeKindFloat,
   806  		CodeKindString,
   807  		CodeKindBool,
   808  		CodeKindBytes:
   809  		return true
   810  	case CodeKindPtr:
   811  		return isEnableStructEndOptimization(value.(*PtrCode).value)
   812  	default:
   813  		return false
   814  	}
   815  }
   816  
   817  type InterfaceCode struct {
   818  	typ        *runtime.Type
   819  	fieldQuery *FieldQuery
   820  	isPtr      bool
   821  }
   822  
   823  func (c *InterfaceCode) Kind() CodeKind {
   824  	return CodeKindInterface
   825  }
   826  
   827  func (c *InterfaceCode) ToOpcode(ctx *compileContext) Opcodes {
   828  	var code *Opcode
   829  	switch {
   830  	case c.isPtr:
   831  		code = newOpCode(ctx, c.typ, OpInterfacePtr)
   832  	default:
   833  		code = newOpCode(ctx, c.typ, OpInterface)
   834  	}
   835  	code.FieldQuery = c.fieldQuery
   836  	if c.typ.NumMethod() > 0 {
   837  		code.Flags |= NonEmptyInterfaceFlags
   838  	}
   839  	ctx.incIndex()
   840  	return Opcodes{code}
   841  }
   842  
   843  func (c *InterfaceCode) Filter(query *FieldQuery) Code {
   844  	return &InterfaceCode{
   845  		typ:        c.typ,
   846  		fieldQuery: query,
   847  		isPtr:      c.isPtr,
   848  	}
   849  }
   850  
   851  type MarshalJSONCode struct {
   852  	typ                *runtime.Type
   853  	fieldQuery         *FieldQuery
   854  	isAddrForMarshaler bool
   855  	isNilableType      bool
   856  	isMarshalerContext bool
   857  }
   858  
   859  func (c *MarshalJSONCode) Kind() CodeKind {
   860  	return CodeKindMarshalJSON
   861  }
   862  
   863  func (c *MarshalJSONCode) ToOpcode(ctx *compileContext) Opcodes {
   864  	code := newOpCode(ctx, c.typ, OpMarshalJSON)
   865  	code.FieldQuery = c.fieldQuery
   866  	if c.isAddrForMarshaler {
   867  		code.Flags |= AddrForMarshalerFlags
   868  	}
   869  	if c.isMarshalerContext {
   870  		code.Flags |= MarshalerContextFlags
   871  	}
   872  	if c.isNilableType {
   873  		code.Flags |= IsNilableTypeFlags
   874  	} else {
   875  		code.Flags &= ^IsNilableTypeFlags
   876  	}
   877  	ctx.incIndex()
   878  	return Opcodes{code}
   879  }
   880  
   881  func (c *MarshalJSONCode) Filter(query *FieldQuery) Code {
   882  	return &MarshalJSONCode{
   883  		typ:                c.typ,
   884  		fieldQuery:         query,
   885  		isAddrForMarshaler: c.isAddrForMarshaler,
   886  		isNilableType:      c.isNilableType,
   887  		isMarshalerContext: c.isMarshalerContext,
   888  	}
   889  }
   890  
   891  type MarshalTextCode struct {
   892  	typ                *runtime.Type
   893  	fieldQuery         *FieldQuery
   894  	isAddrForMarshaler bool
   895  	isNilableType      bool
   896  }
   897  
   898  func (c *MarshalTextCode) Kind() CodeKind {
   899  	return CodeKindMarshalText
   900  }
   901  
   902  func (c *MarshalTextCode) ToOpcode(ctx *compileContext) Opcodes {
   903  	code := newOpCode(ctx, c.typ, OpMarshalText)
   904  	code.FieldQuery = c.fieldQuery
   905  	if c.isAddrForMarshaler {
   906  		code.Flags |= AddrForMarshalerFlags
   907  	}
   908  	if c.isNilableType {
   909  		code.Flags |= IsNilableTypeFlags
   910  	} else {
   911  		code.Flags &= ^IsNilableTypeFlags
   912  	}
   913  	ctx.incIndex()
   914  	return Opcodes{code}
   915  }
   916  
   917  func (c *MarshalTextCode) Filter(query *FieldQuery) Code {
   918  	return &MarshalTextCode{
   919  		typ:                c.typ,
   920  		fieldQuery:         query,
   921  		isAddrForMarshaler: c.isAddrForMarshaler,
   922  		isNilableType:      c.isNilableType,
   923  	}
   924  }
   925  
   926  type PtrCode struct {
   927  	typ    *runtime.Type
   928  	value  Code
   929  	ptrNum uint8
   930  }
   931  
   932  func (c *PtrCode) Kind() CodeKind {
   933  	return CodeKindPtr
   934  }
   935  
   936  func (c *PtrCode) ToOpcode(ctx *compileContext) Opcodes {
   937  	codes := c.value.ToOpcode(ctx)
   938  	codes.First().Op = convertPtrOp(codes.First())
   939  	codes.First().PtrNum = c.ptrNum
   940  	return codes
   941  }
   942  
   943  func (c *PtrCode) ToAnonymousOpcode(ctx *compileContext) Opcodes {
   944  	var codes Opcodes
   945  	anonymCode, ok := c.value.(AnonymousCode)
   946  	if ok {
   947  		codes = anonymCode.ToAnonymousOpcode(ctx)
   948  	} else {
   949  		codes = c.value.ToOpcode(ctx)
   950  	}
   951  	codes.First().Op = convertPtrOp(codes.First())
   952  	codes.First().PtrNum = c.ptrNum
   953  	return codes
   954  }
   955  
   956  func (c *PtrCode) Filter(query *FieldQuery) Code {
   957  	return &PtrCode{
   958  		typ:    c.typ,
   959  		value:  c.value.Filter(query),
   960  		ptrNum: c.ptrNum,
   961  	}
   962  }
   963  
   964  func convertPtrOp(code *Opcode) OpType {
   965  	ptrHeadOp := code.Op.HeadToPtrHead()
   966  	if code.Op != ptrHeadOp {
   967  		if code.PtrNum > 0 {
   968  			// ptr field and ptr head
   969  			code.PtrNum--
   970  		}
   971  		return ptrHeadOp
   972  	}
   973  	switch code.Op {
   974  	case OpInt:
   975  		return OpIntPtr
   976  	case OpUint:
   977  		return OpUintPtr
   978  	case OpFloat32:
   979  		return OpFloat32Ptr
   980  	case OpFloat64:
   981  		return OpFloat64Ptr
   982  	case OpString:
   983  		return OpStringPtr
   984  	case OpBool:
   985  		return OpBoolPtr
   986  	case OpBytes:
   987  		return OpBytesPtr
   988  	case OpNumber:
   989  		return OpNumberPtr
   990  	case OpArray:
   991  		return OpArrayPtr
   992  	case OpSlice:
   993  		return OpSlicePtr
   994  	case OpMap:
   995  		return OpMapPtr
   996  	case OpMarshalJSON:
   997  		return OpMarshalJSONPtr
   998  	case OpMarshalText:
   999  		return OpMarshalTextPtr
  1000  	case OpInterface:
  1001  		return OpInterfacePtr
  1002  	case OpRecursive:
  1003  		return OpRecursivePtr
  1004  	}
  1005  	return code.Op
  1006  }
  1007  
  1008  func isEmbeddedStruct(field *StructFieldCode) bool {
  1009  	if !field.isAnonymous {
  1010  		return false
  1011  	}
  1012  	t := field.typ
  1013  	if t.Kind() == reflect.Ptr {
  1014  		t = t.Elem()
  1015  	}
  1016  	return t.Kind() == reflect.Struct
  1017  }