github.com/grbit/go-json@v0.11.0/internal/encoder/code.go (about)

     1  package encoder
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"unsafe"
     7  
     8  	"github.com/grbit/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  	for firstField.Op == OpStructHead || firstField.Op == OpStructField {
   401  		firstField = firstField.Next
   402  	}
   403  	lastField := firstField
   404  	for lastField.NextField != nil {
   405  		lastField = lastField.NextField
   406  	}
   407  	return lastField
   408  }
   409  
   410  func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes {
   411  	// header => code => structField => code => end
   412  	//                        ^          |
   413  	//                        |__________|
   414  	if c.isRecursive {
   415  		recursive := newRecursiveCode(ctx, c.typ, &CompiledCode{})
   416  		recursive.Type = c.typ
   417  		ctx.incIndex()
   418  		*ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive)
   419  		return Opcodes{recursive}
   420  	}
   421  	codes := Opcodes{}
   422  	var prevField *Opcode
   423  	ctx.incIndent()
   424  	for idx, field := range c.fields {
   425  		isFirstField := idx == 0
   426  		isEndField := idx == len(c.fields)-1
   427  		fieldCodes := field.ToOpcode(ctx, isFirstField, isEndField)
   428  		for _, code := range fieldCodes {
   429  			if c.isIndirect {
   430  				code.Flags |= IndirectFlags
   431  			}
   432  		}
   433  		firstField := fieldCodes.First()
   434  		if len(codes) > 0 {
   435  			codes.Last().Next = firstField
   436  			firstField.Idx = codes.First().Idx
   437  		}
   438  		if prevField != nil {
   439  			prevField.NextField = firstField
   440  		}
   441  		if isEndField {
   442  			endField := fieldCodes.Last()
   443  			if len(codes) > 0 {
   444  				codes.First().End = endField
   445  			} else {
   446  				firstField.End = endField
   447  			}
   448  			codes = codes.Add(fieldCodes...)
   449  			break
   450  		}
   451  		prevField = c.lastFieldCode(field, firstField)
   452  		codes = codes.Add(fieldCodes...)
   453  	}
   454  	if len(codes) == 0 {
   455  		head := &Opcode{
   456  			Op:         OpStructHead,
   457  			Idx:        opcodeOffset(ctx.ptrIndex),
   458  			Type:       c.typ,
   459  			DisplayIdx: ctx.opcodeIndex,
   460  			Indent:     ctx.indent,
   461  		}
   462  		ctx.incOpcodeIndex()
   463  		end := &Opcode{
   464  			Op:         OpStructEnd,
   465  			Idx:        opcodeOffset(ctx.ptrIndex),
   466  			DisplayIdx: ctx.opcodeIndex,
   467  			Indent:     ctx.indent,
   468  		}
   469  		head.NextField = end
   470  		head.Next = end
   471  		head.End = end
   472  		codes = codes.Add(head, end)
   473  		ctx.incIndex()
   474  	}
   475  	ctx.decIndent()
   476  	ctx.structTypeToCodes[uintptr(unsafe.Pointer(c.typ))] = codes
   477  	return codes
   478  }
   479  
   480  func (c *StructCode) ToAnonymousOpcode(ctx *compileContext) Opcodes {
   481  	// header => code => structField => code => end
   482  	//                        ^          |
   483  	//                        |__________|
   484  	if c.isRecursive {
   485  		recursive := newRecursiveCode(ctx, c.typ, &CompiledCode{})
   486  		recursive.Type = c.typ
   487  		ctx.incIndex()
   488  		*ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive)
   489  		return Opcodes{recursive}
   490  	}
   491  	codes := Opcodes{}
   492  	var prevField *Opcode
   493  	for idx, field := range c.fields {
   494  		isFirstField := idx == 0
   495  		isEndField := idx == len(c.fields)-1
   496  		fieldCodes := field.ToAnonymousOpcode(ctx, isFirstField, isEndField)
   497  		for _, code := range fieldCodes {
   498  			if c.isIndirect {
   499  				code.Flags |= IndirectFlags
   500  			}
   501  		}
   502  		firstField := fieldCodes.First()
   503  		if len(codes) > 0 {
   504  			codes.Last().Next = firstField
   505  			firstField.Idx = codes.First().Idx
   506  		}
   507  		if prevField != nil {
   508  			prevField.NextField = firstField
   509  		}
   510  		if isEndField {
   511  			lastField := fieldCodes.Last()
   512  			if len(codes) > 0 {
   513  				codes.First().End = lastField
   514  			} else {
   515  				firstField.End = lastField
   516  			}
   517  		}
   518  		prevField = firstField
   519  		codes = codes.Add(fieldCodes...)
   520  	}
   521  	return codes
   522  }
   523  
   524  func (c *StructCode) removeFieldsByTags(tags runtime.StructTags) {
   525  	fields := make([]*StructFieldCode, 0, len(c.fields))
   526  	for _, field := range c.fields {
   527  		if field.isAnonymous {
   528  			structCode := field.getAnonymousStruct()
   529  			if structCode != nil && !structCode.isRecursive {
   530  				structCode.removeFieldsByTags(tags)
   531  				if len(structCode.fields) > 0 {
   532  					fields = append(fields, field)
   533  				}
   534  				continue
   535  			}
   536  		}
   537  		if tags.ExistsKey(field.key) {
   538  			continue
   539  		}
   540  		fields = append(fields, field)
   541  	}
   542  	c.fields = fields
   543  }
   544  
   545  func (c *StructCode) enableIndirect() {
   546  	if c.isIndirect {
   547  		return
   548  	}
   549  	c.isIndirect = true
   550  	if len(c.fields) == 0 {
   551  		return
   552  	}
   553  	structCode := c.fields[0].getStruct()
   554  	if structCode == nil {
   555  		return
   556  	}
   557  	structCode.enableIndirect()
   558  }
   559  
   560  func (c *StructCode) Filter(query *FieldQuery) Code {
   561  	fieldMap := map[string]*FieldQuery{}
   562  	for _, field := range query.Fields {
   563  		fieldMap[field.Name] = field
   564  	}
   565  	fields := make([]*StructFieldCode, 0, len(c.fields))
   566  	for _, field := range c.fields {
   567  		query, exists := fieldMap[field.key]
   568  		if !exists {
   569  			continue
   570  		}
   571  		fieldCode := &StructFieldCode{
   572  			typ:                field.typ,
   573  			key:                field.key,
   574  			tag:                field.tag,
   575  			value:              field.value,
   576  			offset:             field.offset,
   577  			isAnonymous:        field.isAnonymous,
   578  			isTaggedKey:        field.isTaggedKey,
   579  			isNilableType:      field.isNilableType,
   580  			isNilCheck:         field.isNilCheck,
   581  			isAddrForMarshaler: field.isAddrForMarshaler,
   582  			isNextOpPtrType:    field.isNextOpPtrType,
   583  		}
   584  		if len(query.Fields) > 0 {
   585  			fieldCode.value = fieldCode.value.Filter(query)
   586  		}
   587  		fields = append(fields, fieldCode)
   588  	}
   589  	return &StructCode{
   590  		typ:                       c.typ,
   591  		fields:                    fields,
   592  		isPtr:                     c.isPtr,
   593  		disableIndirectConversion: c.disableIndirectConversion,
   594  		isIndirect:                c.isIndirect,
   595  		isRecursive:               c.isRecursive,
   596  	}
   597  }
   598  
   599  type StructFieldCode struct {
   600  	typ                *runtime.Type
   601  	key                string
   602  	tag                *runtime.StructTag
   603  	value              Code
   604  	offset             uintptr
   605  	isAnonymous        bool
   606  	isTaggedKey        bool
   607  	isNilableType      bool
   608  	isNilCheck         bool
   609  	isAddrForMarshaler bool
   610  	isNextOpPtrType    bool
   611  	isMarshalerContext bool
   612  }
   613  
   614  func (c *StructFieldCode) getStruct() *StructCode {
   615  	value := c.value
   616  	ptr, ok := value.(*PtrCode)
   617  	if ok {
   618  		value = ptr.value
   619  	}
   620  	structCode, ok := value.(*StructCode)
   621  	if ok {
   622  		return structCode
   623  	}
   624  	return nil
   625  }
   626  
   627  func (c *StructFieldCode) getAnonymousStruct() *StructCode {
   628  	if !c.isAnonymous {
   629  		return nil
   630  	}
   631  	return c.getStruct()
   632  }
   633  
   634  func optimizeStructHeader(code *Opcode, tag *runtime.StructTag) OpType {
   635  	headType := code.ToHeaderType(tag.IsString)
   636  	if tag.IsOmitEmpty {
   637  		headType = headType.HeadToOmitEmptyHead()
   638  	}
   639  	return headType
   640  }
   641  
   642  func optimizeStructField(code *Opcode, tag *runtime.StructTag) OpType {
   643  	fieldType := code.ToFieldType(tag.IsString)
   644  	if tag.IsOmitEmpty {
   645  		fieldType = fieldType.FieldToOmitEmptyField()
   646  	}
   647  	return fieldType
   648  }
   649  
   650  func (c *StructFieldCode) headerOpcodes(ctx *compileContext, field *Opcode, valueCodes Opcodes) Opcodes {
   651  	value := valueCodes.First()
   652  	op := optimizeStructHeader(value, c.tag)
   653  	field.Op = op
   654  	if value.Flags&MarshalerContextFlags != 0 {
   655  		field.Flags |= MarshalerContextFlags
   656  	}
   657  	field.NumBitSize = value.NumBitSize
   658  	field.PtrNum = value.PtrNum
   659  	field.FieldQuery = value.FieldQuery
   660  	fieldCodes := Opcodes{field}
   661  	if op.IsMultipleOpHead() {
   662  		field.Next = value
   663  		fieldCodes = fieldCodes.Add(valueCodes...)
   664  	} else {
   665  		ctx.decIndex()
   666  	}
   667  	return fieldCodes
   668  }
   669  
   670  func (c *StructFieldCode) fieldOpcodes(ctx *compileContext, field *Opcode, valueCodes Opcodes) Opcodes {
   671  	value := valueCodes.First()
   672  	op := optimizeStructField(value, c.tag)
   673  	field.Op = op
   674  	if value.Flags&MarshalerContextFlags != 0 {
   675  		field.Flags |= MarshalerContextFlags
   676  	}
   677  	field.NumBitSize = value.NumBitSize
   678  	field.PtrNum = value.PtrNum
   679  	field.FieldQuery = value.FieldQuery
   680  
   681  	fieldCodes := Opcodes{field}
   682  	if op.IsMultipleOpField() {
   683  		field.Next = value
   684  		fieldCodes = fieldCodes.Add(valueCodes...)
   685  	} else {
   686  		ctx.decIndex()
   687  	}
   688  	return fieldCodes
   689  }
   690  
   691  func (c *StructFieldCode) addStructEndCode(ctx *compileContext, codes Opcodes) Opcodes {
   692  	end := &Opcode{
   693  		Op:         OpStructEnd,
   694  		Idx:        opcodeOffset(ctx.ptrIndex),
   695  		DisplayIdx: ctx.opcodeIndex,
   696  		Indent:     ctx.indent,
   697  	}
   698  	codes.Last().Next = end
   699  	code := codes.First()
   700  	for code.Op == OpStructField || code.Op == OpStructHead {
   701  		code = code.Next
   702  	}
   703  	for code.NextField != nil {
   704  		code = code.NextField
   705  	}
   706  	code.NextField = end
   707  
   708  	codes = codes.Add(end)
   709  	ctx.incOpcodeIndex()
   710  	return codes
   711  }
   712  
   713  func (c *StructFieldCode) structKey(ctx *compileContext) string {
   714  	if ctx.escapeKey {
   715  		rctx := &RuntimeContext{Option: &Option{Flag: HTMLEscapeOption}}
   716  		return fmt.Sprintf(`%s:`, string(AppendString(rctx, []byte{}, c.key)))
   717  	}
   718  	return fmt.Sprintf(`"%s":`, c.key)
   719  }
   720  
   721  func (c *StructFieldCode) flags() OpFlags {
   722  	var flags OpFlags
   723  	if c.isTaggedKey {
   724  		flags |= IsTaggedKeyFlags
   725  	}
   726  	if c.isNilableType {
   727  		flags |= IsNilableTypeFlags
   728  	}
   729  	if c.isNilCheck {
   730  		flags |= NilCheckFlags
   731  	}
   732  	if c.isAddrForMarshaler {
   733  		flags |= AddrForMarshalerFlags
   734  	}
   735  	if c.isNextOpPtrType {
   736  		flags |= IsNextOpPtrTypeFlags
   737  	}
   738  	if c.isAnonymous {
   739  		flags |= AnonymousKeyFlags
   740  	}
   741  	if c.isMarshalerContext {
   742  		flags |= MarshalerContextFlags
   743  	}
   744  	return flags
   745  }
   746  
   747  func (c *StructFieldCode) toValueOpcodes(ctx *compileContext) Opcodes {
   748  	if c.isAnonymous {
   749  		anonymCode, ok := c.value.(AnonymousCode)
   750  		if ok {
   751  			return anonymCode.ToAnonymousOpcode(ctx)
   752  		}
   753  	}
   754  	return c.value.ToOpcode(ctx)
   755  }
   756  
   757  func (c *StructFieldCode) ToOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes {
   758  	field := &Opcode{
   759  		Idx:        opcodeOffset(ctx.ptrIndex),
   760  		Flags:      c.flags(),
   761  		Key:        c.structKey(ctx),
   762  		Offset:     uint32(c.offset),
   763  		Type:       c.typ,
   764  		DisplayIdx: ctx.opcodeIndex,
   765  		Indent:     ctx.indent,
   766  		DisplayKey: c.key,
   767  	}
   768  	ctx.incIndex()
   769  	valueCodes := c.toValueOpcodes(ctx)
   770  	if isFirstField {
   771  		codes := c.headerOpcodes(ctx, field, valueCodes)
   772  		if isEndField {
   773  			codes = c.addStructEndCode(ctx, codes)
   774  		}
   775  		return codes
   776  	}
   777  	codes := c.fieldOpcodes(ctx, field, valueCodes)
   778  	if isEndField {
   779  		if isEnableStructEndOptimization(c.value) {
   780  			field.Op = field.Op.FieldToEnd()
   781  		} else {
   782  			codes = c.addStructEndCode(ctx, codes)
   783  		}
   784  	}
   785  	return codes
   786  }
   787  
   788  func (c *StructFieldCode) ToAnonymousOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes {
   789  	field := &Opcode{
   790  		Idx:        opcodeOffset(ctx.ptrIndex),
   791  		Flags:      c.flags() | AnonymousHeadFlags,
   792  		Key:        c.structKey(ctx),
   793  		Offset:     uint32(c.offset),
   794  		Type:       c.typ,
   795  		DisplayIdx: ctx.opcodeIndex,
   796  		Indent:     ctx.indent,
   797  		DisplayKey: c.key,
   798  	}
   799  	ctx.incIndex()
   800  	valueCodes := c.toValueOpcodes(ctx)
   801  	if isFirstField {
   802  		return c.headerOpcodes(ctx, field, valueCodes)
   803  	}
   804  	return c.fieldOpcodes(ctx, field, valueCodes)
   805  }
   806  
   807  func isEnableStructEndOptimization(value Code) bool {
   808  	switch value.Kind() {
   809  	case CodeKindInt,
   810  		CodeKindUint,
   811  		CodeKindFloat,
   812  		CodeKindString,
   813  		CodeKindBool,
   814  		CodeKindBytes:
   815  		return true
   816  	case CodeKindPtr:
   817  		return isEnableStructEndOptimization(value.(*PtrCode).value)
   818  	default:
   819  		return false
   820  	}
   821  }
   822  
   823  type InterfaceCode struct {
   824  	typ        *runtime.Type
   825  	fieldQuery *FieldQuery
   826  	isPtr      bool
   827  }
   828  
   829  func (c *InterfaceCode) Kind() CodeKind {
   830  	return CodeKindInterface
   831  }
   832  
   833  func (c *InterfaceCode) ToOpcode(ctx *compileContext) Opcodes {
   834  	var code *Opcode
   835  	switch {
   836  	case c.isPtr:
   837  		code = newOpCode(ctx, c.typ, OpInterfacePtr)
   838  	default:
   839  		code = newOpCode(ctx, c.typ, OpInterface)
   840  	}
   841  	code.FieldQuery = c.fieldQuery
   842  	if c.typ.NumMethod() > 0 {
   843  		code.Flags |= NonEmptyInterfaceFlags
   844  	}
   845  	ctx.incIndex()
   846  	return Opcodes{code}
   847  }
   848  
   849  func (c *InterfaceCode) Filter(query *FieldQuery) Code {
   850  	return &InterfaceCode{
   851  		typ:        c.typ,
   852  		fieldQuery: query,
   853  		isPtr:      c.isPtr,
   854  	}
   855  }
   856  
   857  type MarshalJSONCode struct {
   858  	typ                *runtime.Type
   859  	fieldQuery         *FieldQuery
   860  	isAddrForMarshaler bool
   861  	isNilableType      bool
   862  	isMarshalerContext bool
   863  }
   864  
   865  func (c *MarshalJSONCode) Kind() CodeKind {
   866  	return CodeKindMarshalJSON
   867  }
   868  
   869  func (c *MarshalJSONCode) ToOpcode(ctx *compileContext) Opcodes {
   870  	code := newOpCode(ctx, c.typ, OpMarshalJSON)
   871  	code.FieldQuery = c.fieldQuery
   872  	if c.isAddrForMarshaler {
   873  		code.Flags |= AddrForMarshalerFlags
   874  	}
   875  	if c.isMarshalerContext {
   876  		code.Flags |= MarshalerContextFlags
   877  	}
   878  	if c.isNilableType {
   879  		code.Flags |= IsNilableTypeFlags
   880  	} else {
   881  		code.Flags &= ^IsNilableTypeFlags
   882  	}
   883  	ctx.incIndex()
   884  	return Opcodes{code}
   885  }
   886  
   887  func (c *MarshalJSONCode) Filter(query *FieldQuery) Code {
   888  	return &MarshalJSONCode{
   889  		typ:                c.typ,
   890  		fieldQuery:         query,
   891  		isAddrForMarshaler: c.isAddrForMarshaler,
   892  		isNilableType:      c.isNilableType,
   893  		isMarshalerContext: c.isMarshalerContext,
   894  	}
   895  }
   896  
   897  type MarshalTextCode struct {
   898  	typ                *runtime.Type
   899  	fieldQuery         *FieldQuery
   900  	isAddrForMarshaler bool
   901  	isNilableType      bool
   902  }
   903  
   904  func (c *MarshalTextCode) Kind() CodeKind {
   905  	return CodeKindMarshalText
   906  }
   907  
   908  func (c *MarshalTextCode) ToOpcode(ctx *compileContext) Opcodes {
   909  	code := newOpCode(ctx, c.typ, OpMarshalText)
   910  	code.FieldQuery = c.fieldQuery
   911  	if c.isAddrForMarshaler {
   912  		code.Flags |= AddrForMarshalerFlags
   913  	}
   914  	if c.isNilableType {
   915  		code.Flags |= IsNilableTypeFlags
   916  	} else {
   917  		code.Flags &= ^IsNilableTypeFlags
   918  	}
   919  	ctx.incIndex()
   920  	return Opcodes{code}
   921  }
   922  
   923  func (c *MarshalTextCode) Filter(query *FieldQuery) Code {
   924  	return &MarshalTextCode{
   925  		typ:                c.typ,
   926  		fieldQuery:         query,
   927  		isAddrForMarshaler: c.isAddrForMarshaler,
   928  		isNilableType:      c.isNilableType,
   929  	}
   930  }
   931  
   932  type PtrCode struct {
   933  	typ    *runtime.Type
   934  	value  Code
   935  	ptrNum uint8
   936  }
   937  
   938  func (c *PtrCode) Kind() CodeKind {
   939  	return CodeKindPtr
   940  }
   941  
   942  func (c *PtrCode) ToOpcode(ctx *compileContext) Opcodes {
   943  	codes := c.value.ToOpcode(ctx)
   944  	codes.First().Op = convertPtrOp(codes.First())
   945  	codes.First().PtrNum = c.ptrNum
   946  	return codes
   947  }
   948  
   949  func (c *PtrCode) ToAnonymousOpcode(ctx *compileContext) Opcodes {
   950  	var codes Opcodes
   951  	anonymCode, ok := c.value.(AnonymousCode)
   952  	if ok {
   953  		codes = anonymCode.ToAnonymousOpcode(ctx)
   954  	} else {
   955  		codes = c.value.ToOpcode(ctx)
   956  	}
   957  	codes.First().Op = convertPtrOp(codes.First())
   958  	codes.First().PtrNum = c.ptrNum
   959  	return codes
   960  }
   961  
   962  func (c *PtrCode) Filter(query *FieldQuery) Code {
   963  	return &PtrCode{
   964  		typ:    c.typ,
   965  		value:  c.value.Filter(query),
   966  		ptrNum: c.ptrNum,
   967  	}
   968  }
   969  
   970  func convertPtrOp(code *Opcode) OpType {
   971  	ptrHeadOp := code.Op.HeadToPtrHead()
   972  	if code.Op != ptrHeadOp {
   973  		if code.PtrNum > 0 {
   974  			// ptr field and ptr head
   975  			code.PtrNum--
   976  		}
   977  		return ptrHeadOp
   978  	}
   979  	switch code.Op {
   980  	case OpInt:
   981  		return OpIntPtr
   982  	case OpUint:
   983  		return OpUintPtr
   984  	case OpFloat32:
   985  		return OpFloat32Ptr
   986  	case OpFloat64:
   987  		return OpFloat64Ptr
   988  	case OpString:
   989  		return OpStringPtr
   990  	case OpBool:
   991  		return OpBoolPtr
   992  	case OpBytes:
   993  		return OpBytesPtr
   994  	case OpNumber:
   995  		return OpNumberPtr
   996  	case OpArray:
   997  		return OpArrayPtr
   998  	case OpSlice:
   999  		return OpSlicePtr
  1000  	case OpMap:
  1001  		return OpMapPtr
  1002  	case OpMarshalJSON:
  1003  		return OpMarshalJSONPtr
  1004  	case OpMarshalText:
  1005  		return OpMarshalTextPtr
  1006  	case OpInterface:
  1007  		return OpInterfacePtr
  1008  	case OpRecursive:
  1009  		return OpRecursivePtr
  1010  	}
  1011  	return code.Op
  1012  }
  1013  
  1014  func isEmbeddedStruct(field *StructFieldCode) bool {
  1015  	if !field.isAnonymous {
  1016  		return false
  1017  	}
  1018  	t := field.typ
  1019  	if t.Kind() == reflect.Ptr {
  1020  		t = t.Elem()
  1021  	}
  1022  	return t.Kind() == reflect.Struct
  1023  }