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
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
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
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
399
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
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
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
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 }
1024
View as plain text