mirror of https://github.com/goccy/go-json.git
refactor compiler
This commit is contained in:
parent
fee54d4873
commit
35fdca6927
|
@ -334,6 +334,27 @@ func (c *StructCode) Type() CodeType2 {
|
||||||
return CodeTypeStruct
|
return CodeTypeStruct
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *StructCode) lastFieldCode(field *StructFieldCode, firstField *Opcode) *Opcode {
|
||||||
|
if field.isAnonymous {
|
||||||
|
return c.lastAnonymousFieldCode(firstField)
|
||||||
|
}
|
||||||
|
lastField := firstField
|
||||||
|
for lastField.NextField != nil {
|
||||||
|
lastField = lastField.NextField
|
||||||
|
}
|
||||||
|
return lastField
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StructCode) lastAnonymousFieldCode(firstField *Opcode) *Opcode {
|
||||||
|
// firstField is special StructHead operation for anonymous structure.
|
||||||
|
// So, StructHead's next operation is truely struct head operation.
|
||||||
|
lastField := firstField.Next
|
||||||
|
for lastField.NextField != nil {
|
||||||
|
lastField = lastField.NextField
|
||||||
|
}
|
||||||
|
return lastField
|
||||||
|
}
|
||||||
|
|
||||||
func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes {
|
func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
// header => code => structField => code => end
|
// header => code => structField => code => end
|
||||||
// ^ |
|
// ^ |
|
||||||
|
@ -357,46 +378,29 @@ func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes {
|
||||||
code.Flags |= IndirectFlags
|
code.Flags |= IndirectFlags
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
firstField := fieldCodes.First()
|
||||||
if len(codes) > 0 {
|
if len(codes) > 0 {
|
||||||
codes.Last().Next = fieldCodes.First()
|
codes.Last().Next = firstField
|
||||||
fieldCodes.First().Idx = codes.First().Idx
|
firstField.Idx = codes.First().Idx
|
||||||
}
|
}
|
||||||
if prevField != nil {
|
if prevField != nil {
|
||||||
prevField.NextField = fieldCodes.First()
|
prevField.NextField = firstField
|
||||||
}
|
}
|
||||||
if isEndField {
|
if isEndField {
|
||||||
|
endField := fieldCodes.Last()
|
||||||
if len(codes) > 0 {
|
if len(codes) > 0 {
|
||||||
codes.First().End = fieldCodes.Last()
|
codes.First().End = endField
|
||||||
} else if field.isAnonymous {
|
} else if field.isAnonymous {
|
||||||
fieldCodes.First().End = fieldCodes.Last()
|
firstField.End = endField
|
||||||
//fieldCodes.First().Next.End = fieldCodes.Last()
|
lastField := c.lastAnonymousFieldCode(firstField)
|
||||||
fieldCode := fieldCodes.First().Next
|
lastField.NextField = endField
|
||||||
for fieldCode.NextField != nil {
|
|
||||||
fieldCode = fieldCode.NextField
|
|
||||||
}
|
|
||||||
// link curLastField => endField
|
|
||||||
fieldCode.NextField = fieldCodes.Last()
|
|
||||||
} else {
|
} else {
|
||||||
fieldCodes.First().End = fieldCodes.Last()
|
firstField.End = endField
|
||||||
}
|
}
|
||||||
codes = append(codes, fieldCodes...)
|
codes = append(codes, fieldCodes...)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if field.isAnonymous {
|
prevField = c.lastFieldCode(field, firstField)
|
||||||
// fieldCodes.First() is StructHead operation.
|
|
||||||
// StructHead's next operation is truely head operation.
|
|
||||||
fieldCode := fieldCodes.First().Next
|
|
||||||
for fieldCode.NextField != nil {
|
|
||||||
fieldCode = fieldCode.NextField
|
|
||||||
}
|
|
||||||
prevField = fieldCode
|
|
||||||
} else {
|
|
||||||
fieldCode := fieldCodes.First()
|
|
||||||
for fieldCode.NextField != nil {
|
|
||||||
fieldCode = fieldCode.NextField
|
|
||||||
}
|
|
||||||
prevField = fieldCode
|
|
||||||
}
|
|
||||||
codes = append(codes, fieldCodes...)
|
codes = append(codes, fieldCodes...)
|
||||||
}
|
}
|
||||||
if len(codes) == 0 {
|
if len(codes) == 0 {
|
||||||
|
@ -448,21 +452,23 @@ func (c *StructCode) ToAnonymousOpcode(ctx *compileContext) Opcodes {
|
||||||
code.Flags |= IndirectFlags
|
code.Flags |= IndirectFlags
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
firstField := fieldCodes.First()
|
||||||
if len(codes) > 0 {
|
if len(codes) > 0 {
|
||||||
codes.Last().Next = fieldCodes.First()
|
codes.Last().Next = firstField
|
||||||
fieldCodes.First().Idx = codes.First().Idx
|
firstField.Idx = codes.First().Idx
|
||||||
}
|
}
|
||||||
if prevField != nil {
|
if prevField != nil {
|
||||||
prevField.NextField = fieldCodes.First()
|
prevField.NextField = firstField
|
||||||
}
|
}
|
||||||
if isEndField {
|
if isEndField {
|
||||||
|
lastField := fieldCodes.Last()
|
||||||
if len(codes) > 0 {
|
if len(codes) > 0 {
|
||||||
codes.First().End = fieldCodes.Last()
|
codes.First().End = lastField
|
||||||
} else {
|
} else {
|
||||||
fieldCodes.First().End = fieldCodes.Last()
|
firstField.End = lastField
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prevField = fieldCodes.First()
|
prevField = firstField
|
||||||
codes = append(codes, fieldCodes...)
|
codes = append(codes, fieldCodes...)
|
||||||
}
|
}
|
||||||
return codes
|
return codes
|
||||||
|
@ -538,98 +544,61 @@ func (c *StructFieldCode) getAnonymousStruct() *StructCode {
|
||||||
return c.getStruct()
|
return c.getStruct()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StructFieldCode) ToOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes {
|
func (c *StructFieldCode) headerOpcodes(ctx *compileContext, field *Opcode, valueCodes Opcodes) Opcodes {
|
||||||
var key string
|
value := valueCodes.First()
|
||||||
if ctx.escapeKey {
|
op := optimizeStructHeader(value, c.tag)
|
||||||
rctx := &RuntimeContext{Option: &Option{Flag: HTMLEscapeOption}}
|
|
||||||
key = fmt.Sprintf(`%s:`, string(AppendString(rctx, []byte{}, c.key)))
|
|
||||||
} else {
|
|
||||||
key = fmt.Sprintf(`"%s":`, c.key)
|
|
||||||
}
|
|
||||||
flags := c.flags()
|
|
||||||
if c.isAnonymous {
|
|
||||||
flags |= AnonymousKeyFlags
|
|
||||||
}
|
|
||||||
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()
|
|
||||||
var codes Opcodes
|
|
||||||
if c.isAnonymous {
|
|
||||||
anonymCode, ok := c.value.(AnonymousCode)
|
|
||||||
if ok {
|
|
||||||
codes = anonymCode.ToAnonymousOpcode(ctx.withType(c.typ))
|
|
||||||
} else {
|
|
||||||
codes = c.value.ToOpcode(ctx.withType(c.typ))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
codes = c.value.ToOpcode(ctx.withType(c.typ))
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
end := &Opcode{
|
|
||||||
Op: OpStructEnd,
|
|
||||||
Idx: opcodeOffset(ctx.ptrIndex),
|
|
||||||
DisplayIdx: ctx.opcodeIndex,
|
|
||||||
Indent: ctx.indent,
|
|
||||||
}
|
|
||||||
fieldCodes.Last().Next = end
|
|
||||||
fieldCodes.First().NextField = end
|
|
||||||
fieldCodes = append(fieldCodes, end)
|
|
||||||
ctx.incIndex()
|
|
||||||
}
|
|
||||||
return fieldCodes
|
|
||||||
}
|
|
||||||
op := optimizeStructField(codes.First(), c.tag)
|
|
||||||
field.Op = op
|
field.Op = op
|
||||||
field.NumBitSize = codes.First().NumBitSize
|
field.NumBitSize = value.NumBitSize
|
||||||
field.PtrNum = codes.First().PtrNum
|
field.PtrNum = value.PtrNum
|
||||||
|
fieldCodes := Opcodes{field}
|
||||||
|
if op.IsMultipleOpHead() {
|
||||||
|
field.Next = value
|
||||||
|
fieldCodes = append(fieldCodes, valueCodes...)
|
||||||
|
} else {
|
||||||
|
ctx.decIndex()
|
||||||
|
}
|
||||||
|
return fieldCodes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StructFieldCode) fieldOpcodes(ctx *compileContext, field *Opcode, valueCodes Opcodes) Opcodes {
|
||||||
|
value := valueCodes.First()
|
||||||
|
op := optimizeStructField(value, c.tag)
|
||||||
|
field.Op = op
|
||||||
|
field.NumBitSize = value.NumBitSize
|
||||||
|
field.PtrNum = value.PtrNum
|
||||||
|
|
||||||
fieldCodes := Opcodes{field}
|
fieldCodes := Opcodes{field}
|
||||||
if op.IsMultipleOpField() {
|
if op.IsMultipleOpField() {
|
||||||
field.Next = codes.First()
|
field.Next = value
|
||||||
fieldCodes = append(fieldCodes, codes...)
|
fieldCodes = append(fieldCodes, valueCodes...)
|
||||||
} else {
|
} else {
|
||||||
// optimize codes
|
|
||||||
ctx.decIndex()
|
ctx.decIndex()
|
||||||
}
|
}
|
||||||
if isEndField {
|
|
||||||
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.First().NextField = end
|
|
||||||
fieldCodes = append(fieldCodes, end)
|
|
||||||
ctx.incIndex()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fieldCodes
|
return fieldCodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *StructFieldCode) addStructEndCode(ctx *compileContext, codes Opcodes) Opcodes {
|
||||||
|
end := &Opcode{
|
||||||
|
Op: OpStructEnd,
|
||||||
|
Idx: opcodeOffset(ctx.ptrIndex),
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
}
|
||||||
|
codes.Last().Next = end
|
||||||
|
codes.First().NextField = end
|
||||||
|
codes = append(codes, end)
|
||||||
|
ctx.incIndex()
|
||||||
|
return codes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StructFieldCode) structKey(ctx *compileContext) string {
|
||||||
|
if ctx.escapeKey {
|
||||||
|
rctx := &RuntimeContext{Option: &Option{Flag: HTMLEscapeOption}}
|
||||||
|
return fmt.Sprintf(`%s:`, string(AppendString(rctx, []byte{}, c.key)))
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(`"%s":`, c.key)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *StructFieldCode) flags() OpFlags {
|
func (c *StructFieldCode) flags() OpFlags {
|
||||||
var flags OpFlags
|
var flags OpFlags
|
||||||
if c.isTaggedKey {
|
if c.isTaggedKey {
|
||||||
|
@ -647,26 +616,27 @@ func (c *StructFieldCode) flags() OpFlags {
|
||||||
if c.isNextOpPtrType {
|
if c.isNextOpPtrType {
|
||||||
flags |= IsNextOpPtrTypeFlags
|
flags |= IsNextOpPtrTypeFlags
|
||||||
}
|
}
|
||||||
return flags
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *StructFieldCode) ToAnonymousOpcode(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)
|
|
||||||
}
|
|
||||||
flags := c.flags()
|
|
||||||
flags |= AnonymousHeadFlags
|
|
||||||
if c.isAnonymous {
|
if c.isAnonymous {
|
||||||
flags |= AnonymousKeyFlags
|
flags |= AnonymousKeyFlags
|
||||||
}
|
}
|
||||||
|
return flags
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StructFieldCode) toValueOpcodes(ctx *compileContext) Opcodes {
|
||||||
|
if c.isAnonymous {
|
||||||
|
anonymCode, ok := c.value.(AnonymousCode)
|
||||||
|
if ok {
|
||||||
|
return anonymCode.ToAnonymousOpcode(ctx.withType(c.typ))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.value.ToOpcode(ctx.withType(c.typ))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *StructFieldCode) ToOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes {
|
||||||
field := &Opcode{
|
field := &Opcode{
|
||||||
Idx: opcodeOffset(ctx.ptrIndex),
|
Idx: opcodeOffset(ctx.ptrIndex),
|
||||||
Flags: flags,
|
Flags: c.flags(),
|
||||||
Key: key,
|
Key: c.structKey(ctx),
|
||||||
Offset: uint32(c.offset),
|
Offset: uint32(c.offset),
|
||||||
Type: c.typ,
|
Type: c.typ,
|
||||||
DisplayIdx: ctx.opcodeIndex,
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
@ -674,45 +644,42 @@ func (c *StructFieldCode) ToAnonymousOpcode(ctx *compileContext, isFirstField, i
|
||||||
DisplayKey: c.key,
|
DisplayKey: c.key,
|
||||||
}
|
}
|
||||||
ctx.incIndex()
|
ctx.incIndex()
|
||||||
var codes Opcodes
|
valueCodes := c.toValueOpcodes(ctx)
|
||||||
if c.isAnonymous {
|
|
||||||
anonymCode, ok := c.value.(AnonymousCode)
|
|
||||||
if ok {
|
|
||||||
codes = anonymCode.ToAnonymousOpcode(ctx.withType(c.typ))
|
|
||||||
} else {
|
|
||||||
codes = c.value.ToOpcode(ctx.withType(c.typ))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
codes = c.value.ToOpcode(ctx.withType(c.typ))
|
|
||||||
}
|
|
||||||
if isFirstField {
|
if isFirstField {
|
||||||
op := optimizeStructHeader(codes.First(), c.tag)
|
codes := c.headerOpcodes(ctx, field, valueCodes)
|
||||||
field.Op = op
|
if isEndField {
|
||||||
field.NumBitSize = codes.First().NumBitSize
|
codes = c.addStructEndCode(ctx, codes)
|
||||||
field.PtrNum = codes.First().PtrNum
|
|
||||||
fieldCodes := Opcodes{field}
|
|
||||||
if op.IsMultipleOpHead() {
|
|
||||||
field.Next = codes.First()
|
|
||||||
fieldCodes = append(fieldCodes, codes...)
|
|
||||||
} else {
|
|
||||||
ctx.decIndex()
|
|
||||||
}
|
}
|
||||||
return fieldCodes
|
return codes
|
||||||
}
|
}
|
||||||
op := optimizeStructField(codes.First(), c.tag)
|
codes := c.fieldOpcodes(ctx, field, valueCodes)
|
||||||
field.Op = op
|
if isEndField {
|
||||||
field.NumBitSize = codes.First().NumBitSize
|
if isEnableStructEndOptimizationType(c.value.Type()) {
|
||||||
field.PtrNum = codes.First().PtrNum
|
field.Op = field.Op.FieldToEnd()
|
||||||
|
} else {
|
||||||
|
codes = c.addStructEndCode(ctx, codes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return codes
|
||||||
|
}
|
||||||
|
|
||||||
fieldCodes := Opcodes{field}
|
func (c *StructFieldCode) ToAnonymousOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes {
|
||||||
if op.IsMultipleOpField() {
|
field := &Opcode{
|
||||||
field.Next = codes.First()
|
Idx: opcodeOffset(ctx.ptrIndex),
|
||||||
fieldCodes = append(fieldCodes, codes...)
|
Flags: c.flags() | AnonymousHeadFlags,
|
||||||
} else {
|
Key: c.structKey(ctx),
|
||||||
// optimize codes
|
Offset: uint32(c.offset),
|
||||||
ctx.decIndex()
|
Type: c.typ,
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
DisplayKey: c.key,
|
||||||
}
|
}
|
||||||
return fieldCodes
|
ctx.incIndex()
|
||||||
|
valueCodes := c.toValueOpcodes(ctx)
|
||||||
|
if isFirstField {
|
||||||
|
return c.headerOpcodes(ctx, field, valueCodes)
|
||||||
|
}
|
||||||
|
return c.fieldOpcodes(ctx, field, valueCodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isEnableStructEndOptimizationType(typ CodeType2) bool {
|
func isEnableStructEndOptimizationType(typ CodeType2) bool {
|
||||||
|
|
Loading…
Reference in New Issue