blob: df90107837ef81b65c175b8bd2a887e2555aa72b [file] [log] [blame]
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package generator
import (
"bytes"
"fmt"
"strings"
)
// structparm describes a parameter of struct type; it implements the
// "parm" interface.
type structparm struct {
sname string
qname string
fields []parm
isBlank
addrTakenHow
isGenValFunc
skipCompare
}
func (p structparm) TypeName() string {
return p.sname
}
func (p structparm) QualName() string {
return p.qname
}
func (p structparm) Declare(b *bytes.Buffer, prefix string, suffix string, caller bool) {
n := p.sname
if caller {
n = p.qname
}
b.WriteString(fmt.Sprintf("%s %s%s", prefix, n, suffix))
}
func (p structparm) FieldName(i int) string {
if p.fields[i].IsBlank() {
return "_"
}
return fmt.Sprintf("F%d", i)
}
func (p structparm) String() string {
var buf bytes.Buffer
buf.WriteString(fmt.Sprintf("struct %s {\n", p.sname))
for fi, f := range p.fields {
buf.WriteString(fmt.Sprintf("%s %s\n", p.FieldName(fi), f.String()))
}
buf.WriteString("}")
return buf.String()
}
func (p structparm) GenValue(s *genstate, f *funcdef, value int, caller bool) (string, int) {
var buf bytes.Buffer
verb(5, "structparm.GenValue(%d)", value)
n := p.sname
if caller {
n = p.qname
}
buf.WriteString(fmt.Sprintf("%s{", n))
nbfi := 0
for fi, fld := range p.fields {
var valstr string
valstr, value = s.GenValue(f, fld, value, caller)
if p.fields[fi].IsBlank() {
buf.WriteString("/* ")
valstr = strings.ReplaceAll(valstr, "/*", "[[")
valstr = strings.ReplaceAll(valstr, "*/", "]]")
} else {
writeCom(&buf, nbfi)
}
buf.WriteString(p.FieldName(fi) + ": ")
buf.WriteString(valstr)
if p.fields[fi].IsBlank() {
buf.WriteString(" */")
} else {
nbfi++
}
}
buf.WriteString("}")
return buf.String(), value
}
func (p structparm) IsControl() bool {
return false
}
func (p structparm) NumElements() int {
ne := 0
for _, f := range p.fields {
ne += f.NumElements()
}
return ne
}
func (p structparm) GenElemRef(elidx int, path string) (string, parm) {
ct := 0
verb(4, "begin GenElemRef(%d,%s) on %s", elidx, path, p.String())
for fi, f := range p.fields {
fne := f.NumElements()
//verb(4, "+ examining field %d fne %d ct %d", fi, fne, ct)
// Empty field. Continue on.
if elidx == ct && fne == 0 {
continue
}
// Is this field the element we're interested in?
if fne == 1 && elidx == ct {
// The field in question may be a composite that has only
// multiple elements but a single non-zero-sized element.
// If this is the case, keep going.
if sp, ok := f.(*structparm); ok {
if len(sp.fields) > 1 {
ppath := fmt.Sprintf("%s.F%d", path, fi)
if p.fields[fi].IsBlank() || path == "_" {
ppath = "_"
}
return f.GenElemRef(elidx-ct, ppath)
}
}
verb(4, "found field %d type %s in GenElemRef(%d,%s)", fi, f.TypeName(), elidx, path)
ppath := fmt.Sprintf("%s.F%d", path, fi)
if p.fields[fi].IsBlank() || path == "_" {
ppath = "_"
}
return ppath, f
}
// Is the element we want somewhere inside this field?
if fne > 1 && elidx >= ct && elidx < ct+fne {
ppath := fmt.Sprintf("%s.F%d", path, fi)
if p.fields[fi].IsBlank() || path == "_" {
ppath = "_"
}
return f.GenElemRef(elidx-ct, ppath)
}
ct += fne
}
panic(fmt.Sprintf("GenElemRef failed for struct %s elidx %d", p.TypeName(), elidx))
}
func (p structparm) HasPointer() bool {
for _, f := range p.fields {
if f.HasPointer() {
return true
}
}
return false
}