gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

code.go (22515B)


      1 package encoder
      2 
      3 import (
      4 	"fmt"
      5 	"reflect"
      6 	"unsafe"
      7 
      8 	"github.com/goccy/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 }