2021-03-16 13:44:32 +03:00
|
|
|
package encoder
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math"
|
|
|
|
"strings"
|
|
|
|
"unsafe"
|
|
|
|
|
|
|
|
"github.com/goccy/go-json/internal/runtime"
|
|
|
|
)
|
|
|
|
|
|
|
|
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
|
|
|
|
|
|
|
type Opcode struct {
|
|
|
|
Op OpType // operation type
|
|
|
|
Type *runtime.Type // go type
|
|
|
|
DisplayIdx int // opcode index
|
|
|
|
Key []byte // struct field key
|
|
|
|
EscapedKey []byte // struct field key ( HTML escaped )
|
|
|
|
PtrNum int // pointer number: e.g. double pointer is 2.
|
|
|
|
DisplayKey string // key text to display
|
|
|
|
IsTaggedKey bool // whether tagged key
|
|
|
|
AnonymousKey bool // whether anonymous key
|
|
|
|
AnonymousHead bool // whether anonymous head or not
|
|
|
|
Indirect bool // whether indirect or not
|
|
|
|
Nilcheck bool // whether needs to nilcheck or not
|
|
|
|
AddrForMarshaler bool // whether needs to addr for marshaler or not
|
|
|
|
RshiftNum uint8 // use to take bit for judging whether negative integer or not
|
|
|
|
Mask uint64 // mask for number
|
|
|
|
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
|
|
|
|
MapPos uintptr // offset to access position list for sorted map
|
|
|
|
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
|
|
|
|
PrevField *Opcode // prev struct field
|
|
|
|
NextField *Opcode // next struct field
|
|
|
|
Next *Opcode // next opcode
|
|
|
|
Jmp *CompiledCode // for recursive call
|
|
|
|
}
|
|
|
|
|
|
|
|
func rshitNum(bitSize uint8) uint8 {
|
|
|
|
return bitSize - 1
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Opcode) setMaskAndRshiftNum(bitSize uint8) {
|
|
|
|
switch bitSize {
|
|
|
|
case 8:
|
|
|
|
c.Mask = math.MaxUint8
|
|
|
|
case 16:
|
|
|
|
c.Mask = math.MaxUint16
|
|
|
|
case 32:
|
|
|
|
c.Mask = math.MaxUint32
|
|
|
|
case 64:
|
|
|
|
c.Mask = math.MaxUint64
|
|
|
|
}
|
|
|
|
c.RshiftNum = rshitNum(bitSize)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Opcode) ToHeaderType() OpType {
|
|
|
|
switch c.Op {
|
|
|
|
case OpInt:
|
|
|
|
return OpStructHeadInt
|
|
|
|
case OpIntPtr:
|
|
|
|
return OpStructHeadIntPtr
|
|
|
|
case OpUint:
|
|
|
|
return OpStructHeadUint
|
|
|
|
case OpUintPtr:
|
|
|
|
return OpStructHeadUintPtr
|
|
|
|
case OpFloat32:
|
|
|
|
return OpStructHeadFloat32
|
|
|
|
case OpFloat32Ptr:
|
|
|
|
return OpStructHeadFloat32Ptr
|
|
|
|
case OpFloat64:
|
|
|
|
return OpStructHeadFloat64
|
|
|
|
case OpFloat64Ptr:
|
|
|
|
return OpStructHeadFloat64Ptr
|
|
|
|
case OpString:
|
|
|
|
return OpStructHeadString
|
|
|
|
case OpStringPtr:
|
|
|
|
return OpStructHeadStringPtr
|
|
|
|
case OpNumber:
|
|
|
|
return OpStructHeadNumber
|
|
|
|
case OpNumberPtr:
|
|
|
|
return OpStructHeadNumberPtr
|
|
|
|
case OpBool:
|
|
|
|
return OpStructHeadBool
|
|
|
|
case OpBoolPtr:
|
|
|
|
return OpStructHeadBoolPtr
|
|
|
|
case OpMap:
|
|
|
|
return OpStructHeadMap
|
|
|
|
case OpMapPtr:
|
|
|
|
c.Op = OpMap
|
|
|
|
return OpStructHeadMapPtr
|
|
|
|
case OpArray:
|
|
|
|
return OpStructHeadArray
|
|
|
|
case OpArrayPtr:
|
|
|
|
c.Op = OpArray
|
|
|
|
return OpStructHeadArrayPtr
|
|
|
|
case OpSlice:
|
|
|
|
return OpStructHeadSlice
|
|
|
|
case OpSlicePtr:
|
|
|
|
c.Op = OpSlice
|
|
|
|
return OpStructHeadSlicePtr
|
|
|
|
case OpMarshalJSON:
|
|
|
|
return OpStructHeadMarshalJSON
|
|
|
|
case OpMarshalJSONPtr:
|
|
|
|
return OpStructHeadMarshalJSONPtr
|
|
|
|
case OpMarshalText:
|
|
|
|
return OpStructHeadMarshalText
|
|
|
|
case OpMarshalTextPtr:
|
|
|
|
return OpStructHeadMarshalTextPtr
|
|
|
|
}
|
|
|
|
return OpStructHead
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Opcode) ToFieldType() OpType {
|
|
|
|
switch c.Op {
|
|
|
|
case OpInt:
|
|
|
|
return OpStructFieldInt
|
|
|
|
case OpIntPtr:
|
|
|
|
return OpStructFieldIntPtr
|
|
|
|
case OpUint:
|
|
|
|
return OpStructFieldUint
|
|
|
|
case OpUintPtr:
|
|
|
|
return OpStructFieldUintPtr
|
|
|
|
case OpFloat32:
|
|
|
|
return OpStructFieldFloat32
|
|
|
|
case OpFloat32Ptr:
|
|
|
|
return OpStructFieldFloat32Ptr
|
|
|
|
case OpFloat64:
|
|
|
|
return OpStructFieldFloat64
|
|
|
|
case OpFloat64Ptr:
|
|
|
|
return OpStructFieldFloat64Ptr
|
|
|
|
case OpString:
|
|
|
|
return OpStructFieldString
|
|
|
|
case OpStringPtr:
|
|
|
|
return OpStructFieldStringPtr
|
|
|
|
case OpNumber:
|
|
|
|
return OpStructFieldNumber
|
|
|
|
case OpNumberPtr:
|
|
|
|
return OpStructFieldNumberPtr
|
|
|
|
case OpBool:
|
|
|
|
return OpStructFieldBool
|
|
|
|
case OpBoolPtr:
|
|
|
|
return OpStructFieldBoolPtr
|
|
|
|
case OpMap:
|
|
|
|
return OpStructFieldMap
|
|
|
|
case OpMapPtr:
|
|
|
|
c.Op = OpMap
|
|
|
|
return OpStructFieldMapPtr
|
|
|
|
case OpArray:
|
|
|
|
return OpStructFieldArray
|
|
|
|
case OpArrayPtr:
|
|
|
|
c.Op = OpArray
|
|
|
|
return OpStructFieldArrayPtr
|
|
|
|
case OpSlice:
|
|
|
|
return OpStructFieldSlice
|
|
|
|
case OpSlicePtr:
|
|
|
|
c.Op = OpSlice
|
|
|
|
return OpStructFieldSlicePtr
|
|
|
|
case OpMarshalJSON:
|
|
|
|
return OpStructFieldMarshalJSON
|
|
|
|
case OpMarshalJSONPtr:
|
|
|
|
return OpStructFieldMarshalJSONPtr
|
|
|
|
case OpMarshalText:
|
|
|
|
return OpStructFieldMarshalText
|
|
|
|
case OpMarshalTextPtr:
|
|
|
|
return OpStructFieldMarshalTextPtr
|
|
|
|
}
|
|
|
|
return OpStructField
|
|
|
|
}
|
|
|
|
|
|
|
|
func newOpCode(ctx *compileContext, op OpType) *Opcode {
|
|
|
|
return newOpCodeWithNext(ctx, op, newEndOp(ctx))
|
|
|
|
}
|
|
|
|
|
|
|
|
func opcodeOffset(idx int) uintptr {
|
|
|
|
return uintptr(idx) * uintptrSize
|
|
|
|
}
|
|
|
|
|
|
|
|
func copyOpcode(code *Opcode) *Opcode {
|
|
|
|
codeMap := map[uintptr]*Opcode{}
|
|
|
|
return code.copy(codeMap)
|
|
|
|
}
|
|
|
|
|
|
|
|
func newOpCodeWithNext(ctx *compileContext, op OpType, next *Opcode) *Opcode {
|
|
|
|
return &Opcode{
|
|
|
|
Op: op,
|
|
|
|
Type: ctx.typ,
|
|
|
|
DisplayIdx: ctx.opcodeIndex,
|
|
|
|
Indent: ctx.indent,
|
|
|
|
Idx: opcodeOffset(ctx.ptrIndex),
|
|
|
|
Next: next,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func newEndOp(ctx *compileContext) *Opcode {
|
|
|
|
return newOpCodeWithNext(ctx, OpEnd, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
Type: c.Type,
|
|
|
|
DisplayIdx: c.DisplayIdx,
|
|
|
|
Key: c.Key,
|
|
|
|
EscapedKey: c.EscapedKey,
|
|
|
|
DisplayKey: c.DisplayKey,
|
|
|
|
PtrNum: c.PtrNum,
|
|
|
|
Mask: c.Mask,
|
|
|
|
RshiftNum: c.RshiftNum,
|
|
|
|
IsTaggedKey: c.IsTaggedKey,
|
|
|
|
AnonymousKey: c.AnonymousKey,
|
|
|
|
AnonymousHead: c.AnonymousHead,
|
|
|
|
Indirect: c.Indirect,
|
|
|
|
Nilcheck: c.Nilcheck,
|
|
|
|
AddrForMarshaler: c.AddrForMarshaler,
|
|
|
|
Indent: c.Indent,
|
|
|
|
Idx: c.Idx,
|
|
|
|
HeadIdx: c.HeadIdx,
|
|
|
|
ElemIdx: c.ElemIdx,
|
|
|
|
Length: c.Length,
|
|
|
|
MapIter: c.MapIter,
|
|
|
|
MapPos: c.MapPos,
|
|
|
|
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)
|
|
|
|
copied.PrevField = c.PrevField.copy(codeMap)
|
|
|
|
copied.NextField = c.NextField.copy(codeMap)
|
|
|
|
copied.Next = c.Next.copy(codeMap)
|
|
|
|
copied.Jmp = c.Jmp
|
|
|
|
return copied
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Opcode) BeforeLastCode() *Opcode {
|
|
|
|
code := c
|
|
|
|
for {
|
|
|
|
var nextCode *Opcode
|
|
|
|
switch code.Op.CodeType() {
|
|
|
|
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
|
|
|
nextCode = code.End
|
|
|
|
default:
|
|
|
|
nextCode = code.Next
|
|
|
|
}
|
|
|
|
if nextCode.Op == OpEnd {
|
|
|
|
return code
|
|
|
|
}
|
|
|
|
code = nextCode
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Opcode) TotalLength() int {
|
|
|
|
var idx int
|
|
|
|
for code := c; code.Op != OpEnd; {
|
|
|
|
idx = int(code.Idx / uintptrSize)
|
|
|
|
if code.Op == OpStructFieldRecursiveEnd {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
switch code.Op.CodeType() {
|
|
|
|
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
|
|
|
code = code.End
|
|
|
|
default:
|
|
|
|
code = code.Next
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return idx + 2 // opEnd + 1
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Opcode) decOpcodeIndex() {
|
|
|
|
for code := c; code.Op != OpEnd; {
|
|
|
|
code.DisplayIdx--
|
|
|
|
code.Idx -= uintptrSize
|
|
|
|
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
|
|
|
|
}
|
|
|
|
switch code.Op.CodeType() {
|
|
|
|
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
|
|
|
code = code.End
|
|
|
|
default:
|
|
|
|
code = code.Next
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Opcode) decIndent() {
|
|
|
|
for code := c; code.Op != OpEnd; {
|
|
|
|
code.Indent--
|
|
|
|
switch code.Op.CodeType() {
|
|
|
|
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
|
|
|
code = code.End
|
|
|
|
default:
|
|
|
|
code = code.Next
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Opcode) dumpHead(code *Opcode) string {
|
|
|
|
var length uintptr
|
|
|
|
if code.Op.CodeType() == CodeArrayHead {
|
|
|
|
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,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Opcode) dumpMapEnd(code *Opcode) string {
|
|
|
|
return fmt.Sprintf(
|
|
|
|
`[%d]%s%s ([idx:%d][mapPos:%d][length:%d])`,
|
|
|
|
code.DisplayIdx,
|
|
|
|
strings.Repeat("-", code.Indent),
|
|
|
|
code.Op,
|
|
|
|
code.Idx/uintptrSize,
|
|
|
|
code.MapPos/uintptrSize,
|
|
|
|
code.Length/uintptrSize,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Opcode) dumpElem(code *Opcode) string {
|
|
|
|
var length uintptr
|
|
|
|
if code.Op.CodeType() == CodeArrayElem {
|
|
|
|
length = code.Length
|
|
|
|
} else {
|
|
|
|
length = code.Length / uintptrSize
|
|
|
|
}
|
|
|
|
return fmt.Sprintf(
|
|
|
|
`[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d][size:%d])`,
|
|
|
|
code.DisplayIdx,
|
|
|
|
strings.Repeat("-", code.Indent),
|
|
|
|
code.Op,
|
|
|
|
code.Idx/uintptrSize,
|
|
|
|
code.HeadIdx/uintptrSize,
|
|
|
|
code.ElemIdx/uintptrSize,
|
|
|
|
length,
|
|
|
|
code.Size,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Opcode) dumpField(code *Opcode) string {
|
|
|
|
return fmt.Sprintf(
|
|
|
|
`[%d]%s%s ([idx:%d][key:%s][offset:%d][headIdx:%d])`,
|
|
|
|
code.DisplayIdx,
|
|
|
|
strings.Repeat("-", code.Indent),
|
|
|
|
code.Op,
|
|
|
|
code.Idx/uintptrSize,
|
|
|
|
code.DisplayKey,
|
|
|
|
code.Offset,
|
|
|
|
code.HeadIdx/uintptrSize,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Opcode) dumpKey(code *Opcode) string {
|
|
|
|
return fmt.Sprintf(
|
|
|
|
`[%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])`,
|
|
|
|
code.DisplayIdx,
|
|
|
|
strings.Repeat("-", code.Indent),
|
|
|
|
code.Op,
|
|
|
|
code.Idx/uintptrSize,
|
|
|
|
code.MapIter/uintptrSize,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-03-16 18:22:19 +03:00
|
|
|
func (c *Opcode) Dump() string {
|
2021-03-16 13:44:32 +03:00
|
|
|
codes := []string{}
|
|
|
|
for code := c; code.Op != OpEnd; {
|
|
|
|
switch code.Op.CodeType() {
|
|
|
|
case CodeSliceHead:
|
|
|
|
codes = append(codes, c.dumpHead(code))
|
|
|
|
code = code.Next
|
|
|
|
case CodeMapHead:
|
|
|
|
codes = append(codes, c.dumpMapHead(code))
|
|
|
|
code = code.Next
|
|
|
|
case CodeArrayElem, CodeSliceElem:
|
|
|
|
codes = append(codes, c.dumpElem(code))
|
|
|
|
code = code.End
|
|
|
|
case CodeMapKey:
|
|
|
|
codes = append(codes, c.dumpKey(code))
|
|
|
|
code = code.End
|
|
|
|
case CodeMapValue:
|
|
|
|
codes = append(codes, c.dumpValue(code))
|
|
|
|
code = code.Next
|
|
|
|
case CodeMapEnd:
|
|
|
|
codes = append(codes, c.dumpMapEnd(code))
|
|
|
|
code = code.Next
|
|
|
|
case CodeStructField:
|
|
|
|
codes = append(codes, c.dumpField(code))
|
|
|
|
code = code.Next
|
|
|
|
case CodeStructEnd:
|
|
|
|
codes = append(codes, c.dumpField(code))
|
|
|
|
code = code.Next
|
|
|
|
default:
|
|
|
|
codes = append(codes, fmt.Sprintf(
|
|
|
|
"[%d]%s%s ([idx:%d])",
|
|
|
|
code.DisplayIdx,
|
|
|
|
strings.Repeat("-", code.Indent),
|
|
|
|
code.Op,
|
|
|
|
code.Idx/uintptrSize,
|
|
|
|
))
|
|
|
|
code = code.Next
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return strings.Join(codes, "\n")
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
func linkPrevToNextField(cur *Opcode, removedFields map[*Opcode]struct{}) {
|
|
|
|
prev := prevField(cur.PrevField, removedFields)
|
|
|
|
prev.NextField = nextField(cur.NextField, removedFields)
|
|
|
|
code := prev
|
|
|
|
fcode := cur
|
|
|
|
for {
|
|
|
|
var nextCode *Opcode
|
|
|
|
switch code.Op.CodeType() {
|
|
|
|
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
|
|
|
nextCode = code.End
|
|
|
|
default:
|
|
|
|
nextCode = code.Next
|
|
|
|
}
|
|
|
|
if nextCode == fcode {
|
|
|
|
code.Next = fcode.Next
|
|
|
|
break
|
|
|
|
} else if nextCode.Op == OpEnd {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
code = nextCode
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func newSliceHeaderCode(ctx *compileContext) *Opcode {
|
|
|
|
idx := opcodeOffset(ctx.ptrIndex)
|
|
|
|
ctx.incPtrIndex()
|
|
|
|
elemIdx := opcodeOffset(ctx.ptrIndex)
|
|
|
|
ctx.incPtrIndex()
|
|
|
|
length := opcodeOffset(ctx.ptrIndex)
|
|
|
|
return &Opcode{
|
|
|
|
Op: OpSlice,
|
|
|
|
DisplayIdx: ctx.opcodeIndex,
|
|
|
|
Idx: idx,
|
|
|
|
HeadIdx: idx,
|
|
|
|
ElemIdx: elemIdx,
|
|
|
|
Length: length,
|
|
|
|
Indent: ctx.indent,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func newSliceElemCode(ctx *compileContext, head *Opcode, size uintptr) *Opcode {
|
|
|
|
return &Opcode{
|
|
|
|
Op: OpSliceElem,
|
|
|
|
DisplayIdx: ctx.opcodeIndex,
|
|
|
|
Idx: opcodeOffset(ctx.ptrIndex),
|
|
|
|
HeadIdx: head.Idx,
|
|
|
|
ElemIdx: head.ElemIdx,
|
|
|
|
Length: head.Length,
|
|
|
|
Indent: ctx.indent,
|
|
|
|
Size: size,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func newArrayHeaderCode(ctx *compileContext, alen int) *Opcode {
|
|
|
|
idx := opcodeOffset(ctx.ptrIndex)
|
|
|
|
ctx.incPtrIndex()
|
|
|
|
elemIdx := opcodeOffset(ctx.ptrIndex)
|
|
|
|
return &Opcode{
|
|
|
|
Op: OpArray,
|
|
|
|
DisplayIdx: ctx.opcodeIndex,
|
|
|
|
Idx: idx,
|
|
|
|
HeadIdx: idx,
|
|
|
|
ElemIdx: elemIdx,
|
|
|
|
Indent: ctx.indent,
|
|
|
|
Length: uintptr(alen),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func newArrayElemCode(ctx *compileContext, head *Opcode, length int, size uintptr) *Opcode {
|
|
|
|
return &Opcode{
|
|
|
|
Op: OpArrayElem,
|
|
|
|
DisplayIdx: ctx.opcodeIndex,
|
|
|
|
Idx: opcodeOffset(ctx.ptrIndex),
|
|
|
|
ElemIdx: head.ElemIdx,
|
|
|
|
HeadIdx: head.HeadIdx,
|
|
|
|
Length: uintptr(length),
|
|
|
|
Indent: ctx.indent,
|
|
|
|
Size: size,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func newMapHeaderCode(ctx *compileContext) *Opcode {
|
|
|
|
idx := opcodeOffset(ctx.ptrIndex)
|
|
|
|
ctx.incPtrIndex()
|
|
|
|
elemIdx := opcodeOffset(ctx.ptrIndex)
|
|
|
|
ctx.incPtrIndex()
|
|
|
|
length := opcodeOffset(ctx.ptrIndex)
|
|
|
|
ctx.incPtrIndex()
|
|
|
|
mapIter := opcodeOffset(ctx.ptrIndex)
|
|
|
|
return &Opcode{
|
|
|
|
Op: OpMap,
|
|
|
|
Type: ctx.typ,
|
|
|
|
DisplayIdx: ctx.opcodeIndex,
|
|
|
|
Idx: idx,
|
|
|
|
ElemIdx: elemIdx,
|
|
|
|
Length: length,
|
|
|
|
MapIter: mapIter,
|
|
|
|
Indent: ctx.indent,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func newMapKeyCode(ctx *compileContext, head *Opcode) *Opcode {
|
|
|
|
return &Opcode{
|
|
|
|
Op: OpMapKey,
|
|
|
|
DisplayIdx: ctx.opcodeIndex,
|
|
|
|
Idx: opcodeOffset(ctx.ptrIndex),
|
|
|
|
ElemIdx: head.ElemIdx,
|
|
|
|
Length: head.Length,
|
|
|
|
MapIter: head.MapIter,
|
|
|
|
Indent: ctx.indent,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func newMapValueCode(ctx *compileContext, head *Opcode) *Opcode {
|
|
|
|
return &Opcode{
|
|
|
|
Op: OpMapValue,
|
|
|
|
DisplayIdx: ctx.opcodeIndex,
|
|
|
|
Idx: opcodeOffset(ctx.ptrIndex),
|
|
|
|
ElemIdx: head.ElemIdx,
|
|
|
|
Length: head.Length,
|
|
|
|
MapIter: head.MapIter,
|
|
|
|
Indent: ctx.indent,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func newMapEndCode(ctx *compileContext, head *Opcode) *Opcode {
|
|
|
|
mapPos := opcodeOffset(ctx.ptrIndex)
|
|
|
|
ctx.incPtrIndex()
|
|
|
|
idx := opcodeOffset(ctx.ptrIndex)
|
|
|
|
return &Opcode{
|
|
|
|
Op: OpMapEnd,
|
|
|
|
DisplayIdx: ctx.opcodeIndex,
|
|
|
|
Idx: idx,
|
|
|
|
Length: head.Length,
|
|
|
|
MapPos: mapPos,
|
|
|
|
Indent: ctx.indent,
|
|
|
|
Next: newEndOp(ctx),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func newInterfaceCode(ctx *compileContext) *Opcode {
|
|
|
|
return &Opcode{
|
|
|
|
Op: OpInterface,
|
|
|
|
Type: ctx.typ,
|
|
|
|
DisplayIdx: ctx.opcodeIndex,
|
|
|
|
Idx: opcodeOffset(ctx.ptrIndex),
|
|
|
|
Indent: ctx.indent,
|
|
|
|
Next: newEndOp(ctx),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func newRecursiveCode(ctx *compileContext, jmp *CompiledCode) *Opcode {
|
|
|
|
return &Opcode{
|
|
|
|
Op: OpStructFieldRecursive,
|
|
|
|
Type: ctx.typ,
|
|
|
|
DisplayIdx: ctx.opcodeIndex,
|
|
|
|
Idx: opcodeOffset(ctx.ptrIndex),
|
|
|
|
Indent: ctx.indent,
|
|
|
|
Next: newEndOp(ctx),
|
|
|
|
Jmp: jmp,
|
|
|
|
}
|
|
|
|
}
|