2020-04-29 18:31:50 +03:00
|
|
|
package json
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
2020-12-09 13:12:33 +03:00
|
|
|
const uintptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
|
2020-08-09 11:48:28 +03:00
|
|
|
|
2020-04-29 18:31:50 +03:00
|
|
|
type opcode struct {
|
2020-08-31 15:59:22 +03:00
|
|
|
op opType // operation type
|
|
|
|
typ *rtype // go type
|
|
|
|
displayIdx int // opcode index
|
|
|
|
key []byte // struct field key
|
2020-09-16 19:26:39 +03:00
|
|
|
escapedKey []byte // struct field key ( HTML escaped )
|
2020-12-23 07:13:34 +03:00
|
|
|
ptrNum int // pointer number: e.g. double pointer is 2.
|
2020-08-31 15:59:22 +03:00
|
|
|
displayKey string // key text to display
|
|
|
|
isTaggedKey bool // whether tagged key
|
|
|
|
anonymousKey bool // whether anonymous key
|
|
|
|
root bool // whether root
|
|
|
|
indent int // indent number
|
|
|
|
|
|
|
|
idx uintptr // offset to access ptr
|
|
|
|
headIdx uintptr // offset to access slice/struct head
|
|
|
|
elemIdx uintptr // offset to access array/slice/map elem
|
|
|
|
length uintptr // offset to access slice/map length or array length
|
|
|
|
mapIter uintptr // offset to access map iterator
|
2020-09-16 08:51:37 +03:00
|
|
|
mapPos uintptr // offset to access position list for sorted map
|
2020-08-31 15:59:22 +03:00
|
|
|
offset uintptr // offset size from struct header
|
|
|
|
size uintptr // array/slice elem size
|
|
|
|
|
|
|
|
mapKey *opcode // map key
|
|
|
|
mapValue *opcode // map value
|
|
|
|
elem *opcode // array/slice elem
|
|
|
|
end *opcode // array/slice/struct/map end
|
2020-11-16 15:28:33 +03:00
|
|
|
prevField *opcode // prev struct field
|
2020-08-31 15:59:22 +03:00
|
|
|
nextField *opcode // next struct field
|
|
|
|
next *opcode // next opcode
|
|
|
|
jmp *compiledCode // for recursive call
|
2020-04-29 18:31:50 +03:00
|
|
|
}
|
|
|
|
|
2020-08-29 09:35:03 +03:00
|
|
|
func newOpCode(ctx *encodeCompileContext, op opType) *opcode {
|
2020-08-30 11:32:26 +03:00
|
|
|
return newOpCodeWithNext(ctx, op, newEndOp(ctx))
|
2020-08-29 09:35:03 +03:00
|
|
|
}
|
|
|
|
|
2020-08-31 15:59:22 +03:00
|
|
|
func opcodeOffset(idx int) uintptr {
|
|
|
|
return uintptr(idx) * uintptrSize
|
|
|
|
}
|
|
|
|
|
2020-09-15 14:47:41 +03:00
|
|
|
func copyOpcode(code *opcode) *opcode {
|
|
|
|
codeMap := map[uintptr]*opcode{}
|
|
|
|
return code.copy(codeMap)
|
|
|
|
}
|
|
|
|
|
2020-12-25 11:03:56 +03:00
|
|
|
func newOpCodeWithNext(ctx *encodeCompileContext, op opType, next *opcode) *opcode {
|
2020-08-29 09:35:03 +03:00
|
|
|
return &opcode{
|
2020-08-31 15:59:22 +03:00
|
|
|
op: op,
|
|
|
|
typ: ctx.typ,
|
|
|
|
displayIdx: ctx.opcodeIndex,
|
|
|
|
indent: ctx.indent,
|
2020-09-01 16:26:26 +03:00
|
|
|
idx: opcodeOffset(ctx.ptrIndex),
|
2020-08-31 15:59:22 +03:00
|
|
|
next: next,
|
2020-04-29 18:31:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-29 09:35:03 +03:00
|
|
|
func newEndOp(ctx *encodeCompileContext) *opcode {
|
|
|
|
return newOpCodeWithNext(ctx, opEnd, nil)
|
2020-04-29 18:31:50 +03:00
|
|
|
}
|
|
|
|
|
2020-09-15 14:47:41 +03:00
|
|
|
func (c *opcode) copy(codeMap map[uintptr]*opcode) *opcode {
|
|
|
|
if c == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
addr := uintptr(unsafe.Pointer(c))
|
|
|
|
if code, exists := codeMap[addr]; exists {
|
|
|
|
return code
|
|
|
|
}
|
|
|
|
copied := &opcode{
|
|
|
|
op: c.op,
|
|
|
|
typ: c.typ,
|
|
|
|
displayIdx: c.displayIdx,
|
|
|
|
key: c.key,
|
2020-09-16 19:26:39 +03:00
|
|
|
escapedKey: c.escapedKey,
|
2020-09-15 14:47:41 +03:00
|
|
|
displayKey: c.displayKey,
|
2020-12-23 07:13:34 +03:00
|
|
|
ptrNum: c.ptrNum,
|
2020-09-15 14:47:41 +03:00
|
|
|
isTaggedKey: c.isTaggedKey,
|
|
|
|
anonymousKey: c.anonymousKey,
|
|
|
|
root: c.root,
|
|
|
|
indent: c.indent,
|
|
|
|
idx: c.idx,
|
|
|
|
headIdx: c.headIdx,
|
|
|
|
elemIdx: c.elemIdx,
|
|
|
|
length: c.length,
|
|
|
|
mapIter: c.mapIter,
|
2020-09-16 08:51:37 +03:00
|
|
|
mapPos: c.mapPos,
|
2020-09-15 14:47:41 +03:00
|
|
|
offset: c.offset,
|
|
|
|
size: c.size,
|
|
|
|
}
|
|
|
|
codeMap[addr] = copied
|
|
|
|
copied.mapKey = c.mapKey.copy(codeMap)
|
|
|
|
copied.mapValue = c.mapValue.copy(codeMap)
|
|
|
|
copied.elem = c.elem.copy(codeMap)
|
|
|
|
copied.end = c.end.copy(codeMap)
|
2020-11-16 15:28:33 +03:00
|
|
|
copied.prevField = c.prevField.copy(codeMap)
|
2020-09-15 14:47:41 +03:00
|
|
|
copied.nextField = c.nextField.copy(codeMap)
|
|
|
|
copied.next = c.next.copy(codeMap)
|
|
|
|
copied.jmp = c.jmp
|
|
|
|
return copied
|
|
|
|
}
|
|
|
|
|
2020-04-29 18:31:50 +03:00
|
|
|
func (c *opcode) beforeLastCode() *opcode {
|
|
|
|
code := c
|
|
|
|
for {
|
|
|
|
var nextCode *opcode
|
2020-08-22 06:58:34 +03:00
|
|
|
switch code.op.codeType() {
|
2020-08-31 15:59:22 +03:00
|
|
|
case codeArrayElem, codeSliceElem, codeMapKey:
|
|
|
|
nextCode = code.end
|
2020-04-30 07:39:47 +03:00
|
|
|
default:
|
2020-04-29 18:31:50 +03:00
|
|
|
nextCode = code.next
|
|
|
|
}
|
|
|
|
if nextCode.op == opEnd {
|
|
|
|
return code
|
|
|
|
}
|
|
|
|
code = nextCode
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-08-31 15:59:22 +03:00
|
|
|
func (c *opcode) totalLength() int {
|
2020-08-30 11:52:59 +03:00
|
|
|
var idx int
|
|
|
|
for code := c; code.op != opEnd; {
|
2020-09-03 09:36:11 +03:00
|
|
|
idx = int(code.idx / uintptrSize)
|
2021-01-24 17:27:23 +03:00
|
|
|
if code.op == opStructFieldRecursiveEnd {
|
2020-09-03 09:36:11 +03:00
|
|
|
break
|
|
|
|
}
|
2020-08-30 11:52:59 +03:00
|
|
|
switch code.op.codeType() {
|
2020-08-31 15:59:22 +03:00
|
|
|
case codeArrayElem, codeSliceElem, codeMapKey:
|
|
|
|
code = code.end
|
2020-08-30 11:52:59 +03:00
|
|
|
default:
|
|
|
|
code = code.next
|
|
|
|
}
|
|
|
|
}
|
2020-09-03 09:36:11 +03:00
|
|
|
return idx + 2 // opEnd + 1
|
2020-08-30 11:52:59 +03:00
|
|
|
}
|
|
|
|
|
2020-08-30 11:32:26 +03:00
|
|
|
func (c *opcode) decOpcodeIndex() {
|
|
|
|
for code := c; code.op != opEnd; {
|
2020-08-30 21:14:37 +03:00
|
|
|
code.displayIdx--
|
2020-09-01 16:26:26 +03:00
|
|
|
code.idx -= uintptrSize
|
2020-09-01 17:23:07 +03:00
|
|
|
if code.headIdx > 0 {
|
|
|
|
code.headIdx -= uintptrSize
|
|
|
|
}
|
|
|
|
if code.elemIdx > 0 {
|
|
|
|
code.elemIdx -= uintptrSize
|
|
|
|
}
|
|
|
|
if code.mapIter > 0 {
|
|
|
|
code.mapIter -= uintptrSize
|
|
|
|
}
|
|
|
|
if code.length > 0 && code.op.codeType() != codeArrayHead && code.op.codeType() != codeArrayElem {
|
|
|
|
code.length -= uintptrSize
|
|
|
|
}
|
2020-08-30 11:32:26 +03:00
|
|
|
switch code.op.codeType() {
|
2020-08-31 15:59:22 +03:00
|
|
|
case codeArrayElem, codeSliceElem, codeMapKey:
|
|
|
|
code = code.end
|
2020-08-30 11:32:26 +03:00
|
|
|
default:
|
|
|
|
code = code.next
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-01 16:26:26 +03:00
|
|
|
func (c *opcode) dumpHead(code *opcode) string {
|
|
|
|
var length uintptr
|
2020-09-01 17:23:07 +03:00
|
|
|
if code.op.codeType() == codeArrayHead {
|
2020-09-01 16:26:26 +03:00
|
|
|
length = code.length
|
|
|
|
} else {
|
|
|
|
length = code.length / uintptrSize
|
|
|
|
}
|
|
|
|
return fmt.Sprintf(
|
|
|
|
`[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d])`,
|
|
|
|
code.displayIdx,
|
|
|
|
strings.Repeat("-", code.indent),
|
|
|
|
code.op,
|
|
|
|
code.idx/uintptrSize,
|
|
|
|
code.headIdx/uintptrSize,
|
|
|
|
code.elemIdx/uintptrSize,
|
|
|
|
length,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *opcode) dumpMapHead(code *opcode) string {
|
|
|
|
return fmt.Sprintf(
|
|
|
|
`[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d][mapIter:%d])`,
|
|
|
|
code.displayIdx,
|
|
|
|
strings.Repeat("-", code.indent),
|
|
|
|
code.op,
|
|
|
|
code.idx/uintptrSize,
|
|
|
|
code.headIdx/uintptrSize,
|
|
|
|
code.elemIdx/uintptrSize,
|
|
|
|
code.length/uintptrSize,
|
|
|
|
code.mapIter/uintptrSize,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-09-16 08:51:37 +03:00
|
|
|
func (c *opcode) dumpMapEnd(code *opcode) string {
|
|
|
|
return fmt.Sprintf(
|
2020-09-16 12:17:17 +03:00
|
|
|
`[%d]%s%s ([idx:%d][mapPos:%d][length:%d])`,
|
2020-09-16 08:51:37 +03:00
|
|
|
code.displayIdx,
|
|
|
|
strings.Repeat("-", code.indent),
|
|
|
|
code.op,
|
|
|
|
code.idx/uintptrSize,
|
|
|
|
code.mapPos/uintptrSize,
|
|
|
|
code.length/uintptrSize,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-08-31 15:59:22 +03:00
|
|
|
func (c *opcode) dumpElem(code *opcode) string {
|
2020-09-01 16:26:26 +03:00
|
|
|
var length uintptr
|
|
|
|
if code.op.codeType() == codeArrayElem {
|
|
|
|
length = code.length
|
|
|
|
} else {
|
|
|
|
length = code.length / uintptrSize
|
|
|
|
}
|
2020-08-31 15:59:22 +03:00
|
|
|
return fmt.Sprintf(
|
2020-09-01 16:26:26 +03:00
|
|
|
`[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d][size:%d])`,
|
2020-08-31 15:59:22 +03:00
|
|
|
code.displayIdx,
|
|
|
|
strings.Repeat("-", code.indent),
|
|
|
|
code.op,
|
2020-09-01 16:26:26 +03:00
|
|
|
code.idx/uintptrSize,
|
|
|
|
code.headIdx/uintptrSize,
|
|
|
|
code.elemIdx/uintptrSize,
|
|
|
|
length,
|
2020-08-31 15:59:22 +03:00
|
|
|
code.size,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *opcode) dumpField(code *opcode) string {
|
|
|
|
return fmt.Sprintf(
|
2020-09-01 16:26:26 +03:00
|
|
|
`[%d]%s%s ([idx:%d][key:%s][offset:%d][headIdx:%d])`,
|
2020-08-31 15:59:22 +03:00
|
|
|
code.displayIdx,
|
|
|
|
strings.Repeat("-", code.indent),
|
|
|
|
code.op,
|
2020-09-01 16:26:26 +03:00
|
|
|
code.idx/uintptrSize,
|
2020-08-31 15:59:22 +03:00
|
|
|
code.displayKey,
|
|
|
|
code.offset,
|
2020-09-01 16:26:26 +03:00
|
|
|
code.headIdx/uintptrSize,
|
2020-08-31 15:59:22 +03:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *opcode) dumpKey(code *opcode) string {
|
|
|
|
return fmt.Sprintf(
|
2020-09-01 16:26:26 +03:00
|
|
|
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`,
|
|
|
|
code.displayIdx,
|
|
|
|
strings.Repeat("-", code.indent),
|
|
|
|
code.op,
|
|
|
|
code.idx/uintptrSize,
|
|
|
|
code.elemIdx/uintptrSize,
|
|
|
|
code.length/uintptrSize,
|
|
|
|
code.mapIter/uintptrSize,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *opcode) dumpValue(code *opcode) string {
|
|
|
|
return fmt.Sprintf(
|
|
|
|
`[%d]%s%s ([idx:%d][mapIter:%d])`,
|
2020-08-31 15:59:22 +03:00
|
|
|
code.displayIdx,
|
|
|
|
strings.Repeat("-", code.indent),
|
|
|
|
code.op,
|
2020-09-01 16:26:26 +03:00
|
|
|
code.idx/uintptrSize,
|
|
|
|
code.mapIter/uintptrSize,
|
2020-08-31 15:59:22 +03:00
|
|
|
)
|
2020-08-09 11:48:28 +03:00
|
|
|
}
|
|
|
|
|
2020-04-29 18:31:50 +03:00
|
|
|
func (c *opcode) dump() string {
|
|
|
|
codes := []string{}
|
|
|
|
for code := c; code.op != opEnd; {
|
2020-08-22 06:58:34 +03:00
|
|
|
switch code.op.codeType() {
|
2020-09-01 16:26:26 +03:00
|
|
|
case codeSliceHead:
|
|
|
|
codes = append(codes, c.dumpHead(code))
|
|
|
|
code = code.next
|
|
|
|
case codeMapHead:
|
|
|
|
codes = append(codes, c.dumpMapHead(code))
|
|
|
|
code = code.next
|
2020-08-31 15:59:22 +03:00
|
|
|
case codeArrayElem, codeSliceElem:
|
|
|
|
codes = append(codes, c.dumpElem(code))
|
|
|
|
code = code.end
|
2020-08-22 06:58:34 +03:00
|
|
|
case codeMapKey:
|
2020-08-31 15:59:22 +03:00
|
|
|
codes = append(codes, c.dumpKey(code))
|
|
|
|
code = code.end
|
2020-09-01 16:26:26 +03:00
|
|
|
case codeMapValue:
|
|
|
|
codes = append(codes, c.dumpValue(code))
|
|
|
|
code = code.next
|
2020-09-16 08:51:37 +03:00
|
|
|
case codeMapEnd:
|
|
|
|
codes = append(codes, c.dumpMapEnd(code))
|
|
|
|
code = code.next
|
2020-08-22 12:13:44 +03:00
|
|
|
case codeStructField:
|
2020-08-31 15:59:22 +03:00
|
|
|
codes = append(codes, c.dumpField(code))
|
2020-08-22 12:13:44 +03:00
|
|
|
code = code.next
|
2020-12-29 18:13:45 +03:00
|
|
|
case codeStructEnd:
|
|
|
|
codes = append(codes, c.dumpField(code))
|
|
|
|
code = code.next
|
2020-04-30 07:39:47 +03:00
|
|
|
default:
|
2020-08-31 15:59:22 +03:00
|
|
|
codes = append(codes, fmt.Sprintf(
|
2020-09-01 16:26:26 +03:00
|
|
|
"[%d]%s%s ([idx:%d])",
|
2020-08-31 15:59:22 +03:00
|
|
|
code.displayIdx,
|
|
|
|
strings.Repeat("-", code.indent),
|
|
|
|
code.op,
|
2020-09-01 16:26:26 +03:00
|
|
|
code.idx/uintptrSize,
|
2020-08-31 15:59:22 +03:00
|
|
|
))
|
2020-04-29 18:31:50 +03:00
|
|
|
code = code.next
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return strings.Join(codes, "\n")
|
|
|
|
}
|
|
|
|
|
2020-11-16 15:28:33 +03:00
|
|
|
func prevField(code *opcode, removedFields map[*opcode]struct{}) *opcode {
|
|
|
|
if _, exists := removedFields[code]; exists {
|
|
|
|
return prevField(code.prevField, removedFields)
|
|
|
|
}
|
|
|
|
return code
|
|
|
|
}
|
|
|
|
|
|
|
|
func nextField(code *opcode, removedFields map[*opcode]struct{}) *opcode {
|
|
|
|
if _, exists := removedFields[code]; exists {
|
|
|
|
return nextField(code.nextField, removedFields)
|
|
|
|
}
|
|
|
|
return code
|
|
|
|
}
|
|
|
|
|
2021-01-31 16:45:59 +03:00
|
|
|
func encodeLinkPrevToNextField(cur *opcode, removedFields map[*opcode]struct{}) {
|
2020-11-16 15:28:33 +03:00
|
|
|
prev := prevField(cur.prevField, removedFields)
|
|
|
|
prev.nextField = nextField(cur.nextField, removedFields)
|
2020-08-31 15:59:22 +03:00
|
|
|
code := prev
|
|
|
|
fcode := cur
|
2020-08-22 06:58:34 +03:00
|
|
|
for {
|
|
|
|
var nextCode *opcode
|
|
|
|
switch code.op.codeType() {
|
2020-08-31 15:59:22 +03:00
|
|
|
case codeArrayElem, codeSliceElem, codeMapKey:
|
|
|
|
nextCode = code.end
|
2020-08-22 06:58:34 +03:00
|
|
|
default:
|
|
|
|
nextCode = code.next
|
|
|
|
}
|
|
|
|
if nextCode == fcode {
|
|
|
|
code.next = fcode.next
|
|
|
|
break
|
|
|
|
} else if nextCode.op == opEnd {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
code = nextCode
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-31 15:59:22 +03:00
|
|
|
func newSliceHeaderCode(ctx *encodeCompileContext) *opcode {
|
2020-09-01 16:26:26 +03:00
|
|
|
idx := opcodeOffset(ctx.ptrIndex)
|
|
|
|
ctx.incPtrIndex()
|
|
|
|
elemIdx := opcodeOffset(ctx.ptrIndex)
|
|
|
|
ctx.incPtrIndex()
|
|
|
|
length := opcodeOffset(ctx.ptrIndex)
|
2020-08-31 15:59:22 +03:00
|
|
|
return &opcode{
|
|
|
|
op: opSliceHead,
|
|
|
|
displayIdx: ctx.opcodeIndex,
|
2020-09-01 16:26:26 +03:00
|
|
|
idx: idx,
|
|
|
|
headIdx: idx,
|
|
|
|
elemIdx: elemIdx,
|
|
|
|
length: length,
|
2020-08-31 15:59:22 +03:00
|
|
|
indent: ctx.indent,
|
2020-08-09 11:48:28 +03:00
|
|
|
}
|
2020-04-30 07:39:47 +03:00
|
|
|
}
|
|
|
|
|
2020-09-01 16:26:26 +03:00
|
|
|
func newSliceElemCode(ctx *encodeCompileContext, head *opcode, size uintptr) *opcode {
|
2020-08-31 15:59:22 +03:00
|
|
|
return &opcode{
|
|
|
|
op: opSliceElem,
|
|
|
|
displayIdx: ctx.opcodeIndex,
|
2020-09-01 16:26:26 +03:00
|
|
|
idx: opcodeOffset(ctx.ptrIndex),
|
|
|
|
headIdx: head.idx,
|
|
|
|
elemIdx: head.elemIdx,
|
|
|
|
length: head.length,
|
2020-08-31 15:59:22 +03:00
|
|
|
indent: ctx.indent,
|
|
|
|
size: size,
|
2020-08-09 11:48:28 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-31 15:59:22 +03:00
|
|
|
func newArrayHeaderCode(ctx *encodeCompileContext, alen int) *opcode {
|
2020-09-01 16:26:26 +03:00
|
|
|
idx := opcodeOffset(ctx.ptrIndex)
|
|
|
|
ctx.incPtrIndex()
|
|
|
|
elemIdx := opcodeOffset(ctx.ptrIndex)
|
2020-08-31 15:59:22 +03:00
|
|
|
return &opcode{
|
|
|
|
op: opArrayHead,
|
|
|
|
displayIdx: ctx.opcodeIndex,
|
2020-09-01 16:26:26 +03:00
|
|
|
idx: idx,
|
|
|
|
headIdx: idx,
|
|
|
|
elemIdx: elemIdx,
|
2020-08-31 15:59:22 +03:00
|
|
|
indent: ctx.indent,
|
|
|
|
length: uintptr(alen),
|
2020-08-09 11:48:28 +03:00
|
|
|
}
|
2020-04-30 07:39:47 +03:00
|
|
|
}
|
|
|
|
|
2020-09-01 16:26:26 +03:00
|
|
|
func newArrayElemCode(ctx *encodeCompileContext, head *opcode, length int, size uintptr) *opcode {
|
2020-08-31 15:59:22 +03:00
|
|
|
return &opcode{
|
|
|
|
op: opArrayElem,
|
|
|
|
displayIdx: ctx.opcodeIndex,
|
2020-09-01 16:26:26 +03:00
|
|
|
idx: opcodeOffset(ctx.ptrIndex),
|
|
|
|
elemIdx: head.elemIdx,
|
|
|
|
headIdx: head.headIdx,
|
|
|
|
length: uintptr(length),
|
2020-08-31 15:59:22 +03:00
|
|
|
size: size,
|
2020-08-09 11:48:28 +03:00
|
|
|
}
|
2020-04-30 07:39:47 +03:00
|
|
|
}
|
|
|
|
|
2020-08-31 15:59:22 +03:00
|
|
|
func newMapHeaderCode(ctx *encodeCompileContext, withLoad bool) *opcode {
|
2020-08-08 12:53:01 +03:00
|
|
|
var op opType
|
|
|
|
if withLoad {
|
2020-09-16 12:15:47 +03:00
|
|
|
op = opMapHeadLoad
|
2020-08-08 12:53:01 +03:00
|
|
|
} else {
|
2020-09-16 12:15:47 +03:00
|
|
|
op = opMapHead
|
2020-08-08 12:53:01 +03:00
|
|
|
}
|
2020-09-01 16:26:26 +03:00
|
|
|
idx := opcodeOffset(ctx.ptrIndex)
|
|
|
|
ctx.incPtrIndex()
|
|
|
|
elemIdx := opcodeOffset(ctx.ptrIndex)
|
|
|
|
ctx.incPtrIndex()
|
|
|
|
length := opcodeOffset(ctx.ptrIndex)
|
|
|
|
ctx.incPtrIndex()
|
|
|
|
mapIter := opcodeOffset(ctx.ptrIndex)
|
2020-08-31 15:59:22 +03:00
|
|
|
return &opcode{
|
|
|
|
op: op,
|
|
|
|
typ: ctx.typ,
|
|
|
|
displayIdx: ctx.opcodeIndex,
|
2020-09-01 16:26:26 +03:00
|
|
|
idx: idx,
|
|
|
|
elemIdx: elemIdx,
|
|
|
|
length: length,
|
|
|
|
mapIter: mapIter,
|
2020-08-31 15:59:22 +03:00
|
|
|
indent: ctx.indent,
|
2020-04-30 07:39:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-01 16:26:26 +03:00
|
|
|
func newMapKeyCode(ctx *encodeCompileContext, head *opcode) *opcode {
|
2020-08-31 15:59:22 +03:00
|
|
|
return &opcode{
|
2020-09-16 12:15:47 +03:00
|
|
|
op: opMapKey,
|
2020-08-31 15:59:22 +03:00
|
|
|
displayIdx: ctx.opcodeIndex,
|
2020-09-01 16:26:26 +03:00
|
|
|
idx: opcodeOffset(ctx.ptrIndex),
|
|
|
|
elemIdx: head.elemIdx,
|
|
|
|
length: head.length,
|
|
|
|
mapIter: head.mapIter,
|
2020-08-31 15:59:22 +03:00
|
|
|
indent: ctx.indent,
|
2020-04-30 07:39:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-01 16:26:26 +03:00
|
|
|
func newMapValueCode(ctx *encodeCompileContext, head *opcode) *opcode {
|
2020-08-31 15:59:22 +03:00
|
|
|
return &opcode{
|
2020-09-16 12:15:47 +03:00
|
|
|
op: opMapValue,
|
2020-08-31 15:59:22 +03:00
|
|
|
displayIdx: ctx.opcodeIndex,
|
2020-09-01 16:26:26 +03:00
|
|
|
idx: opcodeOffset(ctx.ptrIndex),
|
|
|
|
elemIdx: head.elemIdx,
|
|
|
|
length: head.length,
|
|
|
|
mapIter: head.mapIter,
|
2020-08-31 15:59:22 +03:00
|
|
|
indent: ctx.indent,
|
2020-04-30 07:39:47 +03:00
|
|
|
}
|
|
|
|
}
|
2020-08-12 12:42:29 +03:00
|
|
|
|
2020-09-16 08:51:37 +03:00
|
|
|
func newMapEndCode(ctx *encodeCompileContext, head *opcode) *opcode {
|
|
|
|
mapPos := opcodeOffset(ctx.ptrIndex)
|
|
|
|
ctx.incPtrIndex()
|
|
|
|
idx := opcodeOffset(ctx.ptrIndex)
|
|
|
|
return &opcode{
|
2020-09-16 12:15:47 +03:00
|
|
|
op: opMapEnd,
|
2020-09-16 08:51:37 +03:00
|
|
|
displayIdx: ctx.opcodeIndex,
|
|
|
|
idx: idx,
|
|
|
|
length: head.length,
|
|
|
|
mapPos: mapPos,
|
|
|
|
indent: ctx.indent,
|
|
|
|
next: newEndOp(ctx),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-31 15:59:22 +03:00
|
|
|
func newInterfaceCode(ctx *encodeCompileContext) *opcode {
|
|
|
|
return &opcode{
|
|
|
|
op: opInterface,
|
|
|
|
typ: ctx.typ,
|
|
|
|
displayIdx: ctx.opcodeIndex,
|
2020-09-01 16:26:26 +03:00
|
|
|
idx: opcodeOffset(ctx.ptrIndex),
|
2020-08-31 15:59:22 +03:00
|
|
|
indent: ctx.indent,
|
|
|
|
root: ctx.root,
|
2020-09-03 09:36:11 +03:00
|
|
|
next: newEndOp(ctx),
|
2020-08-12 12:42:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-31 15:59:22 +03:00
|
|
|
func newRecursiveCode(ctx *encodeCompileContext, jmp *compiledCode) *opcode {
|
|
|
|
return &opcode{
|
|
|
|
op: opStructFieldRecursive,
|
|
|
|
typ: ctx.typ,
|
|
|
|
displayIdx: ctx.opcodeIndex,
|
2020-09-01 16:26:26 +03:00
|
|
|
idx: opcodeOffset(ctx.ptrIndex),
|
2020-08-31 15:59:22 +03:00
|
|
|
indent: ctx.indent,
|
|
|
|
next: newEndOp(ctx),
|
|
|
|
jmp: jmp,
|
2020-08-12 12:42:29 +03:00
|
|
|
}
|
|
|
|
}
|