forked from mirror/go-json
add opcode generator
This commit is contained in:
parent
d11fc7fe6c
commit
d631a21b59
|
@ -1,7 +1,9 @@
|
||||||
package encoder
|
package encoder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goccy/go-json/internal/errors"
|
"github.com/goccy/go-json/internal/errors"
|
||||||
"github.com/goccy/go-json/internal/runtime"
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
@ -9,7 +11,23 @@ import (
|
||||||
|
|
||||||
type Code interface {
|
type Code interface {
|
||||||
Type() CodeType2
|
Type() CodeType2
|
||||||
ToOpcode() []*Opcode
|
ToOpcode(*compileContext) Opcodes
|
||||||
|
}
|
||||||
|
|
||||||
|
type Opcodes []*Opcode
|
||||||
|
|
||||||
|
func (o Opcodes) First() *Opcode {
|
||||||
|
if len(o) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return o[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Opcodes) Last() *Opcode {
|
||||||
|
if len(o) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return o[len(o)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
type CodeType2 int
|
type CodeType2 int
|
||||||
|
@ -29,6 +47,7 @@ const (
|
||||||
CodeTypeBytes
|
CodeTypeBytes
|
||||||
CodeTypeMarshalJSON
|
CodeTypeMarshalJSON
|
||||||
CodeTypeMarshalText
|
CodeTypeMarshalText
|
||||||
|
CodeTypeRecursive
|
||||||
)
|
)
|
||||||
|
|
||||||
type IntCode struct {
|
type IntCode struct {
|
||||||
|
@ -42,8 +61,19 @@ func (c *IntCode) Type() CodeType2 {
|
||||||
return CodeTypeInt
|
return CodeTypeInt
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *IntCode) ToOpcode() []*Opcode {
|
func (c *IntCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
return []*Opcode{}
|
var code *Opcode
|
||||||
|
switch {
|
||||||
|
case c.isPtr:
|
||||||
|
code = newOpCode(ctx, OpIntPtr)
|
||||||
|
case c.isString:
|
||||||
|
code = newOpCode(ctx, OpIntString)
|
||||||
|
default:
|
||||||
|
code = newOpCode(ctx, OpInt)
|
||||||
|
}
|
||||||
|
code.NumBitSize = c.bitSize
|
||||||
|
ctx.incIndex()
|
||||||
|
return Opcodes{code}
|
||||||
}
|
}
|
||||||
|
|
||||||
type UintCode struct {
|
type UintCode struct {
|
||||||
|
@ -57,8 +87,19 @@ func (c *UintCode) Type() CodeType2 {
|
||||||
return CodeTypeUint
|
return CodeTypeUint
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *UintCode) ToOpcode() []*Opcode {
|
func (c *UintCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
return []*Opcode{}
|
var code *Opcode
|
||||||
|
switch {
|
||||||
|
case c.isPtr:
|
||||||
|
code = newOpCode(ctx, OpUintPtr)
|
||||||
|
case c.isString:
|
||||||
|
code = newOpCode(ctx, OpUintString)
|
||||||
|
default:
|
||||||
|
code = newOpCode(ctx, OpUint)
|
||||||
|
}
|
||||||
|
code.NumBitSize = c.bitSize
|
||||||
|
ctx.incIndex()
|
||||||
|
return Opcodes{code}
|
||||||
}
|
}
|
||||||
|
|
||||||
type FloatCode struct {
|
type FloatCode struct {
|
||||||
|
@ -72,8 +113,26 @@ func (c *FloatCode) Type() CodeType2 {
|
||||||
return CodeTypeFloat
|
return CodeTypeFloat
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FloatCode) ToOpcode() []*Opcode {
|
func (c *FloatCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
return []*Opcode{}
|
var code *Opcode
|
||||||
|
switch {
|
||||||
|
case c.isPtr:
|
||||||
|
switch c.bitSize {
|
||||||
|
case 32:
|
||||||
|
code = newOpCode(ctx, OpFloat32Ptr)
|
||||||
|
default:
|
||||||
|
code = newOpCode(ctx, OpFloat64Ptr)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
switch c.bitSize {
|
||||||
|
case 32:
|
||||||
|
code = newOpCode(ctx, OpFloat32)
|
||||||
|
default:
|
||||||
|
code = newOpCode(ctx, OpFloat64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.incIndex()
|
||||||
|
return Opcodes{code}
|
||||||
}
|
}
|
||||||
|
|
||||||
type StringCode struct {
|
type StringCode struct {
|
||||||
|
@ -86,8 +145,24 @@ func (c *StringCode) Type() CodeType2 {
|
||||||
return CodeTypeString
|
return CodeTypeString
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StringCode) ToOpcode() []*Opcode {
|
func (c *StringCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
return []*Opcode{}
|
isJsonNumberType := c.typ == runtime.Type2RType(jsonNumberType)
|
||||||
|
var code *Opcode
|
||||||
|
if c.isPtr {
|
||||||
|
if isJsonNumberType {
|
||||||
|
code = newOpCode(ctx, OpNumberPtr)
|
||||||
|
} else {
|
||||||
|
code = newOpCode(ctx, OpStringPtr)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if isJsonNumberType {
|
||||||
|
code = newOpCode(ctx, OpNumber)
|
||||||
|
} else {
|
||||||
|
code = newOpCode(ctx, OpString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.incIndex()
|
||||||
|
return Opcodes{code}
|
||||||
}
|
}
|
||||||
|
|
||||||
type BoolCode struct {
|
type BoolCode struct {
|
||||||
|
@ -100,44 +175,16 @@ func (c *BoolCode) Type() CodeType2 {
|
||||||
return CodeTypeBool
|
return CodeTypeBool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *BoolCode) ToOpcode() []*Opcode {
|
func (c *BoolCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
return []*Opcode{}
|
var code *Opcode
|
||||||
|
switch {
|
||||||
|
case c.isPtr:
|
||||||
|
code = newOpCode(ctx, OpBoolPtr)
|
||||||
|
default:
|
||||||
|
code = newOpCode(ctx, OpBool)
|
||||||
}
|
}
|
||||||
|
ctx.incIndex()
|
||||||
type SliceCode struct {
|
return Opcodes{code}
|
||||||
typ *runtime.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SliceCode) Type() CodeType2 {
|
|
||||||
return CodeTypeSlice
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SliceCode) ToOpcode() []*Opcode {
|
|
||||||
return []*Opcode{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArrayCode struct {
|
|
||||||
typ *runtime.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ArrayCode) Type() CodeType2 {
|
|
||||||
return CodeTypeArray
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ArrayCode) ToOpcode() []*Opcode {
|
|
||||||
return []*Opcode{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type MapCode struct {
|
|
||||||
typ *runtime.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MapCode) Type() CodeType2 {
|
|
||||||
return CodeTypeMap
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MapCode) ToOpcode() []*Opcode {
|
|
||||||
return []*Opcode{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type BytesCode struct {
|
type BytesCode struct {
|
||||||
|
@ -149,8 +196,125 @@ func (c *BytesCode) Type() CodeType2 {
|
||||||
return CodeTypeBytes
|
return CodeTypeBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *BytesCode) ToOpcode() []*Opcode {
|
func (c *BytesCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
return []*Opcode{}
|
var code *Opcode
|
||||||
|
switch {
|
||||||
|
case c.isPtr:
|
||||||
|
code = newOpCode(ctx, OpBytesPtr)
|
||||||
|
default:
|
||||||
|
code = newOpCode(ctx, OpBytes)
|
||||||
|
}
|
||||||
|
ctx.incIndex()
|
||||||
|
return Opcodes{code}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SliceCode struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
value Code
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SliceCode) Type() CodeType2 {
|
||||||
|
return CodeTypeSlice
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SliceCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
|
// header => opcode => elem => end
|
||||||
|
// ^ |
|
||||||
|
// |________|
|
||||||
|
size := c.typ.Elem().Size()
|
||||||
|
header := newSliceHeaderCode(ctx)
|
||||||
|
ctx.incIndex()
|
||||||
|
codes := c.value.ToOpcode(ctx)
|
||||||
|
elemCode := newSliceElemCode(ctx, header, size)
|
||||||
|
ctx.incIndex()
|
||||||
|
end := newOpCode(ctx, OpSliceEnd)
|
||||||
|
ctx.incIndex()
|
||||||
|
header.End = end
|
||||||
|
header.Next = codes.First()
|
||||||
|
codes.Last().Next = elemCode
|
||||||
|
elemCode.Next = codes.First()
|
||||||
|
elemCode.End = end
|
||||||
|
return Opcodes{header}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArrayCode struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
value Code
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ArrayCode) Type() CodeType2 {
|
||||||
|
return CodeTypeArray
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ArrayCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
|
// header => opcode => elem => end
|
||||||
|
// ^ |
|
||||||
|
// |________|
|
||||||
|
elem := c.typ.Elem()
|
||||||
|
alen := c.typ.Len()
|
||||||
|
size := elem.Size()
|
||||||
|
|
||||||
|
header := newArrayHeaderCode(ctx, alen)
|
||||||
|
ctx.incIndex()
|
||||||
|
|
||||||
|
codes := c.value.ToOpcode(ctx)
|
||||||
|
|
||||||
|
elemCode := newArrayElemCode(ctx, header, alen, size)
|
||||||
|
ctx.incIndex()
|
||||||
|
|
||||||
|
end := newOpCode(ctx, OpArrayEnd)
|
||||||
|
ctx.incIndex()
|
||||||
|
|
||||||
|
header.End = end
|
||||||
|
header.Next = codes.First()
|
||||||
|
codes.Last().Next = elemCode
|
||||||
|
elemCode.Next = codes.First()
|
||||||
|
elemCode.End = end
|
||||||
|
return Opcodes{header}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MapCode struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
key Code
|
||||||
|
value Code
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MapCode) Type() CodeType2 {
|
||||||
|
return CodeTypeMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MapCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
|
// header => code => value => code => key => code => value => code => end
|
||||||
|
// ^ |
|
||||||
|
// |_______________________|
|
||||||
|
ctx = ctx.incIndent()
|
||||||
|
header := newMapHeaderCode(ctx)
|
||||||
|
ctx.incIndex()
|
||||||
|
|
||||||
|
keyCodes := c.key.ToOpcode(ctx)
|
||||||
|
|
||||||
|
value := newMapValueCode(ctx, header)
|
||||||
|
ctx.incIndex()
|
||||||
|
valueCodes := c.value.ToOpcode(ctx)
|
||||||
|
|
||||||
|
key := newMapKeyCode(ctx, header)
|
||||||
|
ctx.incIndex()
|
||||||
|
|
||||||
|
ctx = ctx.decIndent()
|
||||||
|
|
||||||
|
end := newMapEndCode(ctx, header)
|
||||||
|
ctx.incIndex()
|
||||||
|
|
||||||
|
header.Next = keyCodes.First()
|
||||||
|
keyCodes.Last().Next = value
|
||||||
|
value.Next = valueCodes.First()
|
||||||
|
valueCodes.Last().Next = key
|
||||||
|
key.Next = keyCodes.First()
|
||||||
|
|
||||||
|
header.End = end
|
||||||
|
key.End = end
|
||||||
|
value.End = end
|
||||||
|
return Opcodes{header}
|
||||||
}
|
}
|
||||||
|
|
||||||
type StructCode struct {
|
type StructCode struct {
|
||||||
|
@ -158,14 +322,79 @@ type StructCode struct {
|
||||||
isPtr bool
|
isPtr bool
|
||||||
fields []*StructFieldCode
|
fields []*StructFieldCode
|
||||||
disableIndirectConversion bool
|
disableIndirectConversion bool
|
||||||
|
isIndirect bool
|
||||||
|
isRecursive bool
|
||||||
|
recursiveCodes Opcodes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StructCode) Type() CodeType2 {
|
func (c *StructCode) Type() CodeType2 {
|
||||||
return CodeTypeStruct
|
return CodeTypeStruct
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StructCode) ToOpcode() []*Opcode {
|
func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
return []*Opcode{}
|
// header => code => structField => code => end
|
||||||
|
// ^ |
|
||||||
|
// |__________|
|
||||||
|
var recursive *Opcode
|
||||||
|
compiled := &CompiledCode{}
|
||||||
|
if c.isRecursive {
|
||||||
|
recursive = newRecursiveCode(ctx, compiled)
|
||||||
|
ctx.incIndex()
|
||||||
|
}
|
||||||
|
if len(c.recursiveCodes) > 0 {
|
||||||
|
c.linkRecursiveCode(compiled, c.recursiveCodes)
|
||||||
|
return Opcodes{recursive}
|
||||||
|
}
|
||||||
|
codes := Opcodes{}
|
||||||
|
var prevField *Opcode
|
||||||
|
for idx, field := range c.fields {
|
||||||
|
isFirstField := idx == 0
|
||||||
|
isEndField := idx == len(c.fields)-1
|
||||||
|
fieldCodes := field.ToOpcode(ctx, isFirstField, isEndField)
|
||||||
|
for _, code := range fieldCodes {
|
||||||
|
if c.isIndirect {
|
||||||
|
code.Flags |= IndirectFlags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(codes) > 0 {
|
||||||
|
codes.Last().Next = fieldCodes.First()
|
||||||
|
}
|
||||||
|
if prevField != nil {
|
||||||
|
prevField.NextField = fieldCodes.First()
|
||||||
|
}
|
||||||
|
prevField = fieldCodes.First()
|
||||||
|
codes = append(codes, fieldCodes...)
|
||||||
|
}
|
||||||
|
if c.isRecursive {
|
||||||
|
c.recursiveCodes = codes
|
||||||
|
c.linkRecursiveCode(compiled, c.recursiveCodes)
|
||||||
|
return Opcodes{recursive}
|
||||||
|
}
|
||||||
|
return codes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StructCode) linkRecursiveCode(compiled *CompiledCode, codes Opcodes) {
|
||||||
|
compiled.Code = copyOpcode(codes.First())
|
||||||
|
code := compiled.Code
|
||||||
|
code.End.Next = newEndOp(&compileContext{})
|
||||||
|
code.Op = code.Op.PtrHeadToHead()
|
||||||
|
|
||||||
|
beforeLastCode := code.End
|
||||||
|
lastCode := beforeLastCode.Next
|
||||||
|
|
||||||
|
lastCode.Idx = beforeLastCode.Idx + uintptrSize
|
||||||
|
lastCode.ElemIdx = lastCode.Idx + uintptrSize
|
||||||
|
lastCode.Length = lastCode.Idx + 2*uintptrSize
|
||||||
|
|
||||||
|
// extend length to alloc slot for elemIdx + length
|
||||||
|
totalLength := uintptr(codes.First().TotalLength() + 3)
|
||||||
|
nextTotalLength := uintptr(code.TotalLength() + 3)
|
||||||
|
|
||||||
|
code.End.Next.Op = OpRecursiveEnd
|
||||||
|
|
||||||
|
compiled.CurLen = totalLength
|
||||||
|
compiled.NextLen = nextTotalLength
|
||||||
|
compiled.Linked = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StructCode) removeFieldsByTags(tags runtime.StructTags) {
|
func (c *StructCode) removeFieldsByTags(tags runtime.StructTags) {
|
||||||
|
@ -173,7 +402,7 @@ func (c *StructCode) removeFieldsByTags(tags runtime.StructTags) {
|
||||||
for _, field := range c.fields {
|
for _, field := range c.fields {
|
||||||
if field.isAnonymous {
|
if field.isAnonymous {
|
||||||
structCode := field.getAnonymousStruct()
|
structCode := field.getAnonymousStruct()
|
||||||
if structCode != nil {
|
if structCode != nil && !structCode.isRecursive {
|
||||||
structCode.removeFieldsByTags(tags)
|
structCode.removeFieldsByTags(tags)
|
||||||
if len(structCode.fields) > 0 {
|
if len(structCode.fields) > 0 {
|
||||||
fields = append(fields, field)
|
fields = append(fields, field)
|
||||||
|
@ -189,9 +418,25 @@ func (c *StructCode) removeFieldsByTags(tags runtime.StructTags) {
|
||||||
c.fields = fields
|
c.fields = fields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *StructCode) enableIndirect() {
|
||||||
|
if c.isIndirect {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.isIndirect = true
|
||||||
|
if len(c.fields) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
structCode := c.fields[0].getStruct()
|
||||||
|
if structCode == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
structCode.enableIndirect()
|
||||||
|
}
|
||||||
|
|
||||||
type StructFieldCode struct {
|
type StructFieldCode struct {
|
||||||
typ *runtime.Type
|
typ *runtime.Type
|
||||||
key string
|
key string
|
||||||
|
tag *runtime.StructTag
|
||||||
value Code
|
value Code
|
||||||
offset uintptr
|
offset uintptr
|
||||||
isAnonymous bool
|
isAnonymous bool
|
||||||
|
@ -202,15 +447,128 @@ type StructFieldCode struct {
|
||||||
isNextOpPtrType bool
|
isNextOpPtrType bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *StructFieldCode) getStruct() *StructCode {
|
||||||
|
value := c.value
|
||||||
|
ptr, ok := value.(*PtrCode)
|
||||||
|
if ok {
|
||||||
|
value = ptr.value
|
||||||
|
}
|
||||||
|
structCode, ok := value.(*StructCode)
|
||||||
|
if ok {
|
||||||
|
return structCode
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *StructFieldCode) getAnonymousStruct() *StructCode {
|
func (c *StructFieldCode) getAnonymousStruct() *StructCode {
|
||||||
if !c.isAnonymous {
|
if !c.isAnonymous {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
code, ok := c.value.(*StructCode)
|
return c.getStruct()
|
||||||
if ok {
|
}
|
||||||
return code
|
|
||||||
|
func (c *StructFieldCode) ToOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes {
|
||||||
|
var key string
|
||||||
|
if ctx.escapeKey {
|
||||||
|
rctx := &RuntimeContext{Option: &Option{Flag: HTMLEscapeOption}}
|
||||||
|
key = fmt.Sprintf(`%s:`, string(AppendString(rctx, []byte{}, c.key)))
|
||||||
|
} else {
|
||||||
|
key = fmt.Sprintf(`"%s":`, c.key)
|
||||||
|
}
|
||||||
|
var flags OpFlags
|
||||||
|
if c.isAnonymous {
|
||||||
|
flags |= AnonymousKeyFlags
|
||||||
|
}
|
||||||
|
if c.isTaggedKey {
|
||||||
|
flags |= IsTaggedKeyFlags
|
||||||
|
}
|
||||||
|
if c.isNilableType {
|
||||||
|
flags |= IsNilableTypeFlags
|
||||||
|
}
|
||||||
|
if c.isNilCheck {
|
||||||
|
flags |= NilCheckFlags
|
||||||
|
}
|
||||||
|
if c.isAddrForMarshaler {
|
||||||
|
flags |= AddrForMarshalerFlags
|
||||||
|
}
|
||||||
|
if c.isNextOpPtrType {
|
||||||
|
flags |= IsNextOpPtrTypeFlags
|
||||||
|
}
|
||||||
|
field := &Opcode{
|
||||||
|
Idx: opcodeOffset(ctx.ptrIndex),
|
||||||
|
Flags: flags,
|
||||||
|
Key: key,
|
||||||
|
Offset: uint32(c.offset),
|
||||||
|
Type: c.typ,
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
DisplayKey: c.key,
|
||||||
|
}
|
||||||
|
ctx.incIndex()
|
||||||
|
codes := c.value.ToOpcode(ctx)
|
||||||
|
if isFirstField {
|
||||||
|
op := optimizeStructHeader(codes.First(), c.tag)
|
||||||
|
field.Op = op
|
||||||
|
field.NumBitSize = codes.First().NumBitSize
|
||||||
|
field.PtrNum = codes.First().PtrNum
|
||||||
|
fieldCodes := Opcodes{field}
|
||||||
|
if op.IsMultipleOpHead() {
|
||||||
|
field.Next = codes.First()
|
||||||
|
fieldCodes = append(fieldCodes, codes...)
|
||||||
|
} else {
|
||||||
|
ctx.decIndex()
|
||||||
|
}
|
||||||
|
if isEndField && !c.isAnonymous {
|
||||||
|
end := &Opcode{
|
||||||
|
Op: OpStructEnd,
|
||||||
|
Idx: opcodeOffset(ctx.ptrIndex),
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
}
|
||||||
|
fieldCodes.Last().Next = end
|
||||||
|
fieldCodes = append(fieldCodes, end)
|
||||||
|
ctx.incIndex()
|
||||||
|
}
|
||||||
|
return fieldCodes
|
||||||
|
}
|
||||||
|
op := optimizeStructField(codes.First(), c.tag)
|
||||||
|
field.Op = op
|
||||||
|
field.NumBitSize = codes.First().NumBitSize
|
||||||
|
field.PtrNum = codes.First().PtrNum
|
||||||
|
|
||||||
|
fieldCodes := Opcodes{field}
|
||||||
|
if op.IsMultipleOpField() {
|
||||||
|
field.Next = codes.First()
|
||||||
|
fieldCodes = append(fieldCodes, codes...)
|
||||||
|
} else {
|
||||||
|
// optimize codes
|
||||||
|
ctx.decIndex()
|
||||||
|
}
|
||||||
|
if isEndField && !c.isAnonymous {
|
||||||
|
if isEnableStructEndOptimizationType(c.value.Type()) {
|
||||||
|
field.Op = field.Op.FieldToEnd()
|
||||||
|
} else {
|
||||||
|
end := &Opcode{
|
||||||
|
Op: OpStructEnd,
|
||||||
|
Idx: opcodeOffset(ctx.ptrIndex),
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
}
|
||||||
|
fieldCodes.Last().Next = end
|
||||||
|
fieldCodes = append(fieldCodes, end)
|
||||||
|
ctx.incIndex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fieldCodes
|
||||||
|
}
|
||||||
|
|
||||||
|
func isEnableStructEndOptimizationType(typ CodeType2) bool {
|
||||||
|
switch typ {
|
||||||
|
case CodeTypeInt, CodeTypeUint, CodeTypeFloat, CodeTypeString, CodeTypeBool:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type InterfaceCode struct {
|
type InterfaceCode struct {
|
||||||
|
@ -222,8 +580,16 @@ func (c *InterfaceCode) Type() CodeType2 {
|
||||||
return CodeTypeInterface
|
return CodeTypeInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *InterfaceCode) ToOpcode() []*Opcode {
|
func (c *InterfaceCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
return []*Opcode{}
|
var code *Opcode
|
||||||
|
switch {
|
||||||
|
case c.isPtr:
|
||||||
|
code = newOpCode(ctx, OpInterfacePtr)
|
||||||
|
default:
|
||||||
|
code = newOpCode(ctx, OpInterface)
|
||||||
|
}
|
||||||
|
ctx.incIndex()
|
||||||
|
return Opcodes{code}
|
||||||
}
|
}
|
||||||
|
|
||||||
type MarshalJSONCode struct {
|
type MarshalJSONCode struct {
|
||||||
|
@ -234,8 +600,22 @@ func (c *MarshalJSONCode) Type() CodeType2 {
|
||||||
return CodeTypeMarshalJSON
|
return CodeTypeMarshalJSON
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MarshalJSONCode) ToOpcode() []*Opcode {
|
func (c *MarshalJSONCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
return []*Opcode{}
|
code := newOpCode(ctx, OpMarshalJSON)
|
||||||
|
typ := c.typ
|
||||||
|
if isPtrMarshalJSONType(typ) {
|
||||||
|
code.Flags |= AddrForMarshalerFlags
|
||||||
|
}
|
||||||
|
if typ.Implements(marshalJSONContextType) || runtime.PtrTo(typ).Implements(marshalJSONContextType) {
|
||||||
|
code.Flags |= MarshalerContextFlags
|
||||||
|
}
|
||||||
|
if isNilableType(typ) {
|
||||||
|
code.Flags |= IsNilableTypeFlags
|
||||||
|
} else {
|
||||||
|
code.Flags &= ^IsNilableTypeFlags
|
||||||
|
}
|
||||||
|
ctx.incIndex()
|
||||||
|
return Opcodes{code}
|
||||||
}
|
}
|
||||||
|
|
||||||
type MarshalTextCode struct {
|
type MarshalTextCode struct {
|
||||||
|
@ -246,21 +626,35 @@ func (c *MarshalTextCode) Type() CodeType2 {
|
||||||
return CodeTypeMarshalText
|
return CodeTypeMarshalText
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MarshalTextCode) ToOpcode() []*Opcode {
|
func (c *MarshalTextCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
return []*Opcode{}
|
code := newOpCode(ctx, OpMarshalText)
|
||||||
|
typ := c.typ
|
||||||
|
if !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType) {
|
||||||
|
code.Flags |= AddrForMarshalerFlags
|
||||||
|
}
|
||||||
|
if isNilableType(typ) {
|
||||||
|
code.Flags |= IsNilableTypeFlags
|
||||||
|
} else {
|
||||||
|
code.Flags &= ^IsNilableTypeFlags
|
||||||
|
}
|
||||||
|
ctx.incIndex()
|
||||||
|
return Opcodes{code}
|
||||||
}
|
}
|
||||||
|
|
||||||
type PtrCode struct {
|
type PtrCode struct {
|
||||||
typ *runtime.Type
|
typ *runtime.Type
|
||||||
value Code
|
value Code
|
||||||
|
ptrNum uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PtrCode) Type() CodeType2 {
|
func (c *PtrCode) Type() CodeType2 {
|
||||||
return CodeTypePtr
|
return CodeTypePtr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PtrCode) ToOpcode() []*Opcode {
|
func (c *PtrCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
return []*Opcode{}
|
codes := c.value.ToOpcode(ctx)
|
||||||
|
codes.First().PtrNum = c.ptrNum
|
||||||
|
return codes
|
||||||
}
|
}
|
||||||
|
|
||||||
func type2code(ctx *compileContext) (Code, error) {
|
func type2code(ctx *compileContext) (Code, error) {
|
||||||
|
@ -450,6 +844,46 @@ func compileFloat642(ctx *compileContext, isPtr bool) (*FloatCode, error) {
|
||||||
return &FloatCode{typ: ctx.typ, bitSize: 64, isPtr: isPtr}, nil
|
return &FloatCode{typ: ctx.typ, bitSize: 64, isPtr: isPtr}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func compileIntString2(ctx *compileContext) (*IntCode, error) {
|
||||||
|
return &IntCode{typ: ctx.typ, bitSize: intSize, isString: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileInt8String2(ctx *compileContext) (*IntCode, error) {
|
||||||
|
return &IntCode{typ: ctx.typ, bitSize: intSize, isString: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileInt16String2(ctx *compileContext) (*IntCode, error) {
|
||||||
|
return &IntCode{typ: ctx.typ, bitSize: 8, isString: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileInt32String2(ctx *compileContext) (*IntCode, error) {
|
||||||
|
return &IntCode{typ: ctx.typ, bitSize: 16, isString: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileInt64String2(ctx *compileContext) (*IntCode, error) {
|
||||||
|
return &IntCode{typ: ctx.typ, bitSize: 64, isString: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileUintString2(ctx *compileContext) (*UintCode, error) {
|
||||||
|
return &UintCode{typ: ctx.typ, bitSize: intSize, isString: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileUint8String2(ctx *compileContext) (*UintCode, error) {
|
||||||
|
return &UintCode{typ: ctx.typ, bitSize: intSize, isString: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileUint16String2(ctx *compileContext) (*UintCode, error) {
|
||||||
|
return &UintCode{typ: ctx.typ, bitSize: 8, isString: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileUint32String2(ctx *compileContext) (*UintCode, error) {
|
||||||
|
return &UintCode{typ: ctx.typ, bitSize: 16, isString: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileUint64String2(ctx *compileContext) (*UintCode, error) {
|
||||||
|
return &UintCode{typ: ctx.typ, bitSize: 64, isString: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func compileString2(ctx *compileContext, isString bool) (*StringCode, error) {
|
func compileString2(ctx *compileContext, isString bool) (*StringCode, error) {
|
||||||
return &StringCode{typ: ctx.typ, isString: isString}, nil
|
return &StringCode{typ: ctx.typ, isString: isString}, nil
|
||||||
}
|
}
|
||||||
|
@ -459,15 +893,47 @@ func compileBool2(ctx *compileContext, isString bool) (*BoolCode, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileSlice2(ctx *compileContext) (*SliceCode, error) {
|
func compileSlice2(ctx *compileContext) (*SliceCode, error) {
|
||||||
return &SliceCode{typ: ctx.typ}, nil
|
elem := ctx.typ.Elem()
|
||||||
|
code, err := compileListElem2(ctx.withType(elem))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if code.Type() == CodeTypeStruct {
|
||||||
|
structCode := code.(*StructCode)
|
||||||
|
structCode.enableIndirect()
|
||||||
|
}
|
||||||
|
return &SliceCode{typ: ctx.typ, value: code}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileArray2(ctx *compileContext) (*ArrayCode, error) {
|
func compileArray2(ctx *compileContext) (*ArrayCode, error) {
|
||||||
return &ArrayCode{typ: ctx.typ}, nil
|
typ := ctx.typ
|
||||||
|
elem := typ.Elem()
|
||||||
|
code, err := compileListElem2(ctx.withType(elem))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if code.Type() == CodeTypeStruct {
|
||||||
|
structCode := code.(*StructCode)
|
||||||
|
structCode.enableIndirect()
|
||||||
|
}
|
||||||
|
return &ArrayCode{typ: ctx.typ, value: code}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileMap2(ctx *compileContext) (*MapCode, error) {
|
func compileMap2(ctx *compileContext) (*MapCode, error) {
|
||||||
return &MapCode{typ: ctx.typ}, nil
|
typ := ctx.typ
|
||||||
|
keyCode, err := compileMapKey(ctx.withType(typ.Key()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
valueCode, err := compileMapValue2(ctx.withType(typ.Elem()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if valueCode.Type() == CodeTypeStruct {
|
||||||
|
structCode := valueCode.(*StructCode)
|
||||||
|
structCode.enableIndirect()
|
||||||
|
}
|
||||||
|
return &MapCode{typ: ctx.typ, key: keyCode, value: valueCode}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileBytes2(ctx *compileContext, isPtr bool) (*BytesCode, error) {
|
func compileBytes2(ctx *compileContext, isPtr bool) (*BytesCode, error) {
|
||||||
|
@ -491,21 +957,109 @@ func compilePtr2(ctx *compileContext) (*PtrCode, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &PtrCode{typ: ctx.typ, value: code}, nil
|
ptr, ok := code.(*PtrCode)
|
||||||
|
if ok {
|
||||||
|
return &PtrCode{typ: ctx.typ, value: ptr.value, ptrNum: ptr.ptrNum + 1}, nil
|
||||||
|
}
|
||||||
|
return &PtrCode{typ: ctx.typ, value: code, ptrNum: 1}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileListElem2(ctx *compileContext) (Code, error) {
|
||||||
|
typ := ctx.typ
|
||||||
|
switch {
|
||||||
|
case isPtrMarshalJSONType(typ):
|
||||||
|
return compileMarshalJSON2(ctx)
|
||||||
|
case !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType):
|
||||||
|
return compileMarshalText2(ctx)
|
||||||
|
case typ.Kind() == reflect.Map:
|
||||||
|
return compilePtr2(ctx.withType(runtime.PtrTo(typ)))
|
||||||
|
default:
|
||||||
|
code, err := type2codeWithPtr(ctx, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ptr, ok := code.(*PtrCode)
|
||||||
|
if ok {
|
||||||
|
if ptr.value.Type() == CodeTypeMap {
|
||||||
|
ptr.ptrNum++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return code, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileMapKey(ctx *compileContext) (Code, error) {
|
||||||
|
typ := ctx.typ
|
||||||
|
switch {
|
||||||
|
case implementsMarshalJSON(typ):
|
||||||
|
return compileMarshalJSON2(ctx)
|
||||||
|
case implementsMarshalText(typ):
|
||||||
|
return compileMarshalText2(ctx)
|
||||||
|
}
|
||||||
|
switch typ.Kind() {
|
||||||
|
case reflect.Ptr:
|
||||||
|
return compilePtr2(ctx)
|
||||||
|
case reflect.String:
|
||||||
|
return compileString2(ctx, false)
|
||||||
|
case reflect.Int:
|
||||||
|
return compileIntString2(ctx)
|
||||||
|
case reflect.Int8:
|
||||||
|
return compileInt8String2(ctx)
|
||||||
|
case reflect.Int16:
|
||||||
|
return compileInt16String2(ctx)
|
||||||
|
case reflect.Int32:
|
||||||
|
return compileInt32String2(ctx)
|
||||||
|
case reflect.Int64:
|
||||||
|
return compileInt64String2(ctx)
|
||||||
|
case reflect.Uint:
|
||||||
|
return compileUintString2(ctx)
|
||||||
|
case reflect.Uint8:
|
||||||
|
return compileUint8String2(ctx)
|
||||||
|
case reflect.Uint16:
|
||||||
|
return compileUint16String2(ctx)
|
||||||
|
case reflect.Uint32:
|
||||||
|
return compileUint32String2(ctx)
|
||||||
|
case reflect.Uint64:
|
||||||
|
return compileUint64String2(ctx)
|
||||||
|
case reflect.Uintptr:
|
||||||
|
return compileUintString2(ctx)
|
||||||
|
}
|
||||||
|
return nil, &errors.UnsupportedTypeError{Type: runtime.RType2Type(typ)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileMapValue2(ctx *compileContext) (Code, error) {
|
||||||
|
switch ctx.typ.Kind() {
|
||||||
|
case reflect.Map:
|
||||||
|
return compilePtr2(ctx.withType(runtime.PtrTo(ctx.typ)))
|
||||||
|
default:
|
||||||
|
code, err := type2codeWithPtr(ctx, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ptr, ok := code.(*PtrCode)
|
||||||
|
if ok {
|
||||||
|
if ptr.value.Type() == CodeTypeMap {
|
||||||
|
ptr.ptrNum++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return code, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileStruct2(ctx *compileContext, isPtr bool) (*StructCode, error) {
|
func compileStruct2(ctx *compileContext, isPtr bool) (*StructCode, error) {
|
||||||
//typeptr := uintptr(unsafe.Pointer(typ))
|
|
||||||
//compiled := &CompiledCode{}
|
|
||||||
//ctx.structTypeToCompiledCode[typeptr] = compiled
|
|
||||||
// header => code => structField => code => end
|
|
||||||
// ^ |
|
|
||||||
// |__________|
|
|
||||||
typ := ctx.typ
|
typ := ctx.typ
|
||||||
|
typeptr := uintptr(unsafe.Pointer(typ))
|
||||||
|
if code, exists := ctx.structTypeToCode[typeptr]; exists {
|
||||||
|
derefCode := *code
|
||||||
|
derefCode.isRecursive = true
|
||||||
|
return &derefCode, nil
|
||||||
|
}
|
||||||
|
indirect := runtime.IfaceIndir(typ)
|
||||||
|
code := &StructCode{typ: typ, isPtr: isPtr, isIndirect: indirect}
|
||||||
|
ctx.structTypeToCode[typeptr] = code
|
||||||
|
|
||||||
fieldNum := typ.NumField()
|
fieldNum := typ.NumField()
|
||||||
//indirect := runtime.IfaceIndir(typ)
|
|
||||||
tags := typeToStructTags(typ)
|
tags := typeToStructTags(typ)
|
||||||
code := &StructCode{typ: typ, isPtr: isPtr}
|
|
||||||
fields := []*StructFieldCode{}
|
fields := []*StructFieldCode{}
|
||||||
for i, tag := range tags {
|
for i, tag := range tags {
|
||||||
isOnlyOneFirstField := i == 0 && fieldNum == 1
|
isOnlyOneFirstField := i == 0 && fieldNum == 1
|
||||||
|
@ -518,12 +1072,35 @@ func compileStruct2(ctx *compileContext, isPtr bool) (*StructCode, error) {
|
||||||
if structCode != nil {
|
if structCode != nil {
|
||||||
structCode.removeFieldsByTags(tags)
|
structCode.removeFieldsByTags(tags)
|
||||||
}
|
}
|
||||||
|
if isAssignableIndirect(field, isPtr) {
|
||||||
|
if indirect {
|
||||||
|
structCode.isIndirect = true
|
||||||
|
} else {
|
||||||
|
structCode.isIndirect = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
structCode := field.getStruct()
|
||||||
|
if structCode != nil {
|
||||||
|
if indirect {
|
||||||
|
// if parent is indirect type, set child indirect property to true
|
||||||
|
structCode.isIndirect = true
|
||||||
|
} else {
|
||||||
|
// if parent is not indirect type, set child indirect property to false.
|
||||||
|
// but if parent's indirect is false and isPtr is true, then indirect must be true.
|
||||||
|
// Do this only if indirectConversion is enabled at the end of compileStruct.
|
||||||
|
structCode.isIndirect = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fields = append(fields, field)
|
fields = append(fields, field)
|
||||||
}
|
}
|
||||||
fieldMap := getFieldMap(fields)
|
fieldMap := getFieldMap(fields)
|
||||||
duplicatedFieldMap := getDuplicatedFieldMap(fieldMap)
|
duplicatedFieldMap := getDuplicatedFieldMap(fieldMap)
|
||||||
code.fields = filteredDuplicatedFields(fields, duplicatedFieldMap)
|
code.fields = filteredDuplicatedFields(fields, duplicatedFieldMap)
|
||||||
|
if !code.disableIndirectConversion && !indirect && isPtr {
|
||||||
|
code.enableIndirect()
|
||||||
|
}
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,7 +1109,7 @@ func getFieldMap(fields []*StructFieldCode) map[string][]*StructFieldCode {
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
if field.isAnonymous {
|
if field.isAnonymous {
|
||||||
structCode := field.getAnonymousStruct()
|
structCode := field.getAnonymousStruct()
|
||||||
if structCode != nil {
|
if structCode != nil && !structCode.isRecursive {
|
||||||
for k, v := range getFieldMap(structCode.fields) {
|
for k, v := range getFieldMap(structCode.fields) {
|
||||||
fieldMap[k] = append(fieldMap[k], v...)
|
fieldMap[k] = append(fieldMap[k], v...)
|
||||||
}
|
}
|
||||||
|
@ -571,7 +1148,7 @@ func filteredDuplicatedFields(fields []*StructFieldCode, duplicatedFieldMap map[
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
if field.isAnonymous {
|
if field.isAnonymous {
|
||||||
structCode := field.getAnonymousStruct()
|
structCode := field.getAnonymousStruct()
|
||||||
if structCode != nil {
|
if structCode != nil && !structCode.isRecursive {
|
||||||
structCode.fields = filteredDuplicatedFields(structCode.fields, duplicatedFieldMap)
|
structCode.fields = filteredDuplicatedFields(structCode.fields, duplicatedFieldMap)
|
||||||
if len(structCode.fields) > 0 {
|
if len(structCode.fields) > 0 {
|
||||||
filteredFields = append(filteredFields, field)
|
filteredFields = append(filteredFields, field)
|
||||||
|
@ -629,6 +1206,7 @@ func (c *StructCode) compileStructField(ctx *compileContext, tag *runtime.Struct
|
||||||
fieldCode := &StructFieldCode{
|
fieldCode := &StructFieldCode{
|
||||||
typ: fieldType,
|
typ: fieldType,
|
||||||
key: tag.Key,
|
key: tag.Key,
|
||||||
|
tag: tag,
|
||||||
offset: field.Offset,
|
offset: field.Offset,
|
||||||
isAnonymous: field.Anonymous && !tag.IsTaggedKey,
|
isAnonymous: field.Anonymous && !tag.IsTaggedKey,
|
||||||
isTaggedKey: tag.IsTaggedKey,
|
isTaggedKey: tag.IsTaggedKey,
|
||||||
|
@ -644,6 +1222,7 @@ func (c *StructCode) compileStructField(ctx *compileContext, tag *runtime.Struct
|
||||||
fieldCode.value = code
|
fieldCode.value = code
|
||||||
fieldCode.isAddrForMarshaler = true
|
fieldCode.isAddrForMarshaler = true
|
||||||
fieldCode.isNilCheck = false
|
fieldCode.isNilCheck = false
|
||||||
|
c.isIndirect = false
|
||||||
c.disableIndirectConversion = true
|
c.disableIndirectConversion = true
|
||||||
case isMovePointerPositionFromHeadToFirstMarshalTextFieldCase(fieldType, isIndirectSpecialCase):
|
case isMovePointerPositionFromHeadToFirstMarshalTextFieldCase(fieldType, isIndirectSpecialCase):
|
||||||
code, err := compileMarshalText2(ctx.withType(fieldType))
|
code, err := compileMarshalText2(ctx.withType(fieldType))
|
||||||
|
@ -653,6 +1232,7 @@ func (c *StructCode) compileStructField(ctx *compileContext, tag *runtime.Struct
|
||||||
fieldCode.value = code
|
fieldCode.value = code
|
||||||
fieldCode.isAddrForMarshaler = true
|
fieldCode.isAddrForMarshaler = true
|
||||||
fieldCode.isNilCheck = false
|
fieldCode.isNilCheck = false
|
||||||
|
c.isIndirect = false
|
||||||
c.disableIndirectConversion = true
|
c.disableIndirectConversion = true
|
||||||
case isPtr && isPtrMarshalJSONType(fieldType):
|
case isPtr && isPtrMarshalJSONType(fieldType):
|
||||||
// *struct{ field T }
|
// *struct{ field T }
|
||||||
|
@ -688,3 +1268,17 @@ func (c *StructCode) compileStructField(ctx *compileContext, tag *runtime.Struct
|
||||||
}
|
}
|
||||||
return fieldCode, nil
|
return fieldCode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isAssignableIndirect(fieldCode *StructFieldCode, isPtr bool) bool {
|
||||||
|
if isPtr {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
codeType := fieldCode.value.Type()
|
||||||
|
if codeType == CodeTypeMarshalJSON {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if codeType == CodeTypeMarshalText {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
|
|
||||||
"github.com/goccy/go-json/internal/errors"
|
"github.com/goccy/go-json/internal/errors"
|
||||||
"github.com/goccy/go-json/internal/runtime"
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
"github.com/k0kubun/pp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type marshalerContext interface {
|
type marshalerContext interface {
|
||||||
|
@ -102,7 +101,12 @@ func compileHead(ctx *compileContext) (*Opcode, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
pp.Println(code)
|
//pp.Println(code)
|
||||||
|
newCtx := *ctx
|
||||||
|
codes := code.ToOpcode(&newCtx)
|
||||||
|
codes.Last().Next = newEndOp(ctx)
|
||||||
|
//pp.Println(codes)
|
||||||
|
fmt.Println(codes.First().Dump())
|
||||||
|
|
||||||
typ := ctx.typ
|
typ := ctx.typ
|
||||||
switch {
|
switch {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build !race
|
||||||
// +build !race
|
// +build !race
|
||||||
|
|
||||||
package encoder
|
package encoder
|
||||||
|
@ -23,6 +24,7 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
||||||
noescapeKeyCode, err := compileHead(&compileContext{
|
noescapeKeyCode, err := compileHead(&compileContext{
|
||||||
typ: copiedType,
|
typ: copiedType,
|
||||||
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
||||||
|
structTypeToCode: map[uintptr]*StructCode{},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -30,6 +32,7 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
||||||
escapeKeyCode, err := compileHead(&compileContext{
|
escapeKeyCode, err := compileHead(&compileContext{
|
||||||
typ: copiedType,
|
typ: copiedType,
|
||||||
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
||||||
|
structTypeToCode: map[uintptr]*StructCode{},
|
||||||
escapeKey: true,
|
escapeKey: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build race
|
||||||
// +build race
|
// +build race
|
||||||
|
|
||||||
package encoder
|
package encoder
|
||||||
|
@ -29,6 +30,7 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
||||||
noescapeKeyCode, err := compileHead(&compileContext{
|
noescapeKeyCode, err := compileHead(&compileContext{
|
||||||
typ: copiedType,
|
typ: copiedType,
|
||||||
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
||||||
|
structTypeToCode: map[uintptr]*StructCode{},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -36,6 +38,7 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
||||||
escapeKeyCode, err := compileHead(&compileContext{
|
escapeKeyCode, err := compileHead(&compileContext{
|
||||||
typ: copiedType,
|
typ: copiedType,
|
||||||
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
||||||
|
structTypeToCode: map[uintptr]*StructCode{},
|
||||||
escapeKey: true,
|
escapeKey: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -15,6 +15,7 @@ type compileContext struct {
|
||||||
indent uint32
|
indent uint32
|
||||||
escapeKey bool
|
escapeKey bool
|
||||||
structTypeToCompiledCode map[uintptr]*CompiledCode
|
structTypeToCompiledCode map[uintptr]*CompiledCode
|
||||||
|
structTypeToCode map[uintptr]*StructCode
|
||||||
|
|
||||||
parent *compileContext
|
parent *compileContext
|
||||||
}
|
}
|
||||||
|
@ -27,6 +28,7 @@ func (c *compileContext) context() *compileContext {
|
||||||
indent: c.indent,
|
indent: c.indent,
|
||||||
escapeKey: c.escapeKey,
|
escapeKey: c.escapeKey,
|
||||||
structTypeToCompiledCode: c.structTypeToCompiledCode,
|
structTypeToCompiledCode: c.structTypeToCompiledCode,
|
||||||
|
structTypeToCode: c.structTypeToCode,
|
||||||
parent: c,
|
parent: c,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue