diff --git a/internal/encoder/code.go b/internal/encoder/code.go index 3e03f97..ce91714 100644 --- a/internal/encoder/code.go +++ b/internal/encoder/code.go @@ -238,7 +238,7 @@ func (c *SliceCode) ToOpcode(ctx *compileContext) Opcodes { codes.Last().Next = elemCode elemCode.Next = codes.First() elemCode.End = end - return Opcodes{header} + return append(append(Opcodes{header}, codes...), elemCode, end) } type ArrayCode struct { @@ -261,9 +261,9 @@ func (c *ArrayCode) ToOpcode(ctx *compileContext) Opcodes { header := newArrayHeaderCode(ctx, alen) ctx.incIndex() - codes := c.value.ToOpcode(ctx) + codes := c.value.ToOpcode(ctx.incIndent()) - elemCode := newArrayElemCode(ctx.withType(c.typ.Elem()).incIndent(), header, alen, size) + elemCode := newArrayElemCode(ctx.withType(elem), header, alen, size) ctx.incIndex() end := newOpCode(ctx, OpArrayEnd) @@ -274,7 +274,8 @@ func (c *ArrayCode) ToOpcode(ctx *compileContext) Opcodes { codes.Last().Next = elemCode elemCode.Next = codes.First() elemCode.End = end - return Opcodes{header} + + return append(append(Opcodes{header}, codes...), elemCode, end) } type MapCode struct { @@ -318,7 +319,7 @@ func (c *MapCode) ToOpcode(ctx *compileContext) Opcodes { header.End = end key.End = end value.End = end - return Opcodes{header} + return append(append(append(append(append(Opcodes{header}, keyCodes...), value), valueCodes...), key), end) } type StructCode struct { @@ -371,11 +372,21 @@ func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes { if isEndField { if len(codes) > 0 { codes.First().End = fieldCodes.Last() + } else if field.isAnonymous { + fieldCodes.First().End = fieldCodes.Last() + //fieldCodes.First().Next.End = fieldCodes.Last() + fieldCodes.First().Next.NextField = fieldCodes.Last() } else { fieldCodes.First().End = fieldCodes.Last() } } - prevField = fieldCodes.First() + if field.isAnonymous { + // fieldCodes.First() is StructHead operation. + // StructHead's next operation is truely head operation. + prevField = fieldCodes.First().Next + } else { + prevField = fieldCodes.First() + } codes = append(codes, fieldCodes...) } ctx = ctx.decIndent() @@ -539,25 +550,10 @@ func (c *StructFieldCode) ToOpcode(ctx *compileContext, isFirstField, isEndField } else { key = fmt.Sprintf(`"%s":`, c.key) } - var flags OpFlags + flags := c.flags() 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, @@ -633,17 +629,8 @@ func (c *StructFieldCode) ToOpcode(ctx *compileContext, isFirstField, isEndField return fieldCodes } -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) - } +func (c *StructFieldCode) flags() OpFlags { var flags OpFlags - flags |= AnonymousHeadFlags - flags |= AnonymousKeyFlags if c.isTaggedKey { flags |= IsTaggedKeyFlags } @@ -659,6 +646,20 @@ func (c *StructFieldCode) ToAnonymousOpcode(ctx *compileContext, isFirstField, i if c.isNextOpPtrType { 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 + flags |= AnonymousKeyFlags field := &Opcode{ Idx: opcodeOffset(ctx.ptrIndex), Flags: flags, diff --git a/internal/encoder/opcode.go b/internal/encoder/opcode.go index 618b37d..642cf6a 100644 --- a/internal/encoder/opcode.go +++ b/internal/encoder/opcode.go @@ -490,7 +490,7 @@ func (c *Opcode) dumpHead(code *Opcode) string { length = code.Length / uintptrSize } return fmt.Sprintf( - `[%d]%s%s ([idx:%d][elemIdx:%d][length:%d])`, + `[%02d]%s%s ([idx:%d][elemIdx:%d][length:%d])`, code.DisplayIdx, strings.Repeat("-", int(code.Indent)), code.Op, @@ -502,7 +502,7 @@ func (c *Opcode) dumpHead(code *Opcode) string { func (c *Opcode) dumpMapHead(code *Opcode) string { return fmt.Sprintf( - `[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`, + `[%02d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`, code.DisplayIdx, strings.Repeat("-", int(code.Indent)), code.Op, @@ -515,7 +515,7 @@ func (c *Opcode) dumpMapHead(code *Opcode) string { func (c *Opcode) dumpMapEnd(code *Opcode) string { return fmt.Sprintf( - `[%d]%s%s ([idx:%d][mapPos:%d][length:%d])`, + `[%02d]%s%s ([idx:%d][mapPos:%d][length:%d])`, code.DisplayIdx, strings.Repeat("-", int(code.Indent)), code.Op, @@ -533,7 +533,7 @@ func (c *Opcode) dumpElem(code *Opcode) string { length = code.Length / uintptrSize } return fmt.Sprintf( - `[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][size:%d])`, + `[%02d]%s%s ([idx:%d][elemIdx:%d][length:%d][size:%d])`, code.DisplayIdx, strings.Repeat("-", int(code.Indent)), code.Op, @@ -546,7 +546,7 @@ func (c *Opcode) dumpElem(code *Opcode) string { func (c *Opcode) dumpField(code *Opcode) string { return fmt.Sprintf( - `[%d]%s%s ([idx:%d][key:%s][offset:%d])`, + `[%02d]%s%s ([idx:%d][key:%s][offset:%d])`, code.DisplayIdx, strings.Repeat("-", int(code.Indent)), code.Op, @@ -558,7 +558,7 @@ func (c *Opcode) dumpField(code *Opcode) string { func (c *Opcode) dumpKey(code *Opcode) string { return fmt.Sprintf( - `[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`, + `[%02d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`, code.DisplayIdx, strings.Repeat("-", int(code.Indent)), code.Op, @@ -571,7 +571,7 @@ func (c *Opcode) dumpKey(code *Opcode) string { func (c *Opcode) dumpValue(code *Opcode) string { return fmt.Sprintf( - `[%d]%s%s ([idx:%d][mapIter:%d])`, + `[%02d]%s%s ([idx:%d][mapIter:%d])`, code.DisplayIdx, strings.Repeat("-", int(code.Indent)), code.Op, @@ -610,7 +610,7 @@ func (c *Opcode) Dump() string { code = code.Next default: codes = append(codes, fmt.Sprintf( - "[%d]%s%s ([idx:%d])", + "[%02d]%s%s ([idx:%d])", code.DisplayIdx, strings.Repeat("-", int(code.Indent)), code.Op, diff --git a/test/cover/cover_array_test.go b/test/cover/cover_array_test.go index 336ef39..1614078 100644 --- a/test/cover/cover_array_test.go +++ b/test/cover/cover_array_test.go @@ -2,6 +2,7 @@ package json_test import ( "bytes" + "fmt" "testing" "github.com/goccy/go-json" @@ -1840,19 +1841,21 @@ func TestCoverArray(t *testing.T) { for _, test := range tests { for _, indent := range []bool{true, false} { for _, htmlEscape := range []bool{true, false} { - var buf bytes.Buffer - enc := json.NewEncoder(&buf) - enc.SetEscapeHTML(htmlEscape) - if indent { - enc.SetIndent("", " ") - } - if err := enc.Encode(test.data); err != nil { - t.Fatalf("%s(htmlEscape:%v,indent:%v): %+v: %s", test.name, htmlEscape, indent, test.data, err) - } - stdresult := encodeByEncodingJSON(test.data, indent, htmlEscape) - if buf.String() != stdresult { - t.Errorf("%s(htmlEscape:%v,indent:%v): doesn't compatible with encoding/json. expected %q but got %q", test.name, htmlEscape, indent, stdresult, buf.String()) - } + t.Run(fmt.Sprintf("%s_indent_%t_escape_%t", test.name, indent, htmlEscape), func(t *testing.T) { + var buf bytes.Buffer + enc := json.NewEncoder(&buf) + enc.SetEscapeHTML(htmlEscape) + if indent { + enc.SetIndent("", " ") + } + if err := enc.Encode(test.data); err != nil { + t.Fatalf("%s(htmlEscape:%v,indent:%v): %+v: %s", test.name, htmlEscape, indent, test.data, err) + } + stdresult := encodeByEncodingJSON(test.data, indent, htmlEscape) + if buf.String() != stdresult { + t.Errorf("%s(htmlEscape:%v,indent:%v): doesn't compatible with encoding/json. expected %q but got %q", test.name, htmlEscape, indent, stdresult, buf.String()) + } + }) } } }