1 | // Copyright 2021 The Go Authors. All rights reserved. |
---|---|
2 | // Use of this source code is governed by a BSD-style |
3 | // license that can be found in the LICENSE file. |
4 | |
5 | package generator |
6 | |
7 | import ( |
8 | "bytes" |
9 | "fmt" |
10 | "strings" |
11 | ) |
12 | |
13 | // structparm describes a parameter of struct type; it implements the |
14 | // "parm" interface. |
15 | type structparm struct { |
16 | sname string |
17 | qname string |
18 | fields []parm |
19 | isBlank |
20 | addrTakenHow |
21 | isGenValFunc |
22 | skipCompare |
23 | } |
24 | |
25 | func (p structparm) TypeName() string { |
26 | return p.sname |
27 | } |
28 | |
29 | func (p structparm) QualName() string { |
30 | return p.qname |
31 | } |
32 | |
33 | func (p structparm) Declare(b *bytes.Buffer, prefix string, suffix string, caller bool) { |
34 | n := p.sname |
35 | if caller { |
36 | n = p.qname |
37 | } |
38 | b.WriteString(fmt.Sprintf("%s %s%s", prefix, n, suffix)) |
39 | } |
40 | |
41 | func (p structparm) FieldName(i int) string { |
42 | if p.fields[i].IsBlank() { |
43 | return "_" |
44 | } |
45 | return fmt.Sprintf("F%d", i) |
46 | } |
47 | |
48 | func (p structparm) String() string { |
49 | var buf bytes.Buffer |
50 | |
51 | buf.WriteString(fmt.Sprintf("struct %s {\n", p.sname)) |
52 | for fi, f := range p.fields { |
53 | buf.WriteString(fmt.Sprintf("%s %s\n", p.FieldName(fi), f.String())) |
54 | } |
55 | buf.WriteString("}") |
56 | return buf.String() |
57 | } |
58 | |
59 | func (p structparm) GenValue(s *genstate, f *funcdef, value int, caller bool) (string, int) { |
60 | var buf bytes.Buffer |
61 | |
62 | verb(5, "structparm.GenValue(%d)", value) |
63 | |
64 | n := p.sname |
65 | if caller { |
66 | n = p.qname |
67 | } |
68 | buf.WriteString(fmt.Sprintf("%s{", n)) |
69 | nbfi := 0 |
70 | for fi, fld := range p.fields { |
71 | var valstr string |
72 | valstr, value = s.GenValue(f, fld, value, caller) |
73 | if p.fields[fi].IsBlank() { |
74 | buf.WriteString("/* ") |
75 | valstr = strings.ReplaceAll(valstr, "/*", "[[") |
76 | valstr = strings.ReplaceAll(valstr, "*/", "]]") |
77 | } else { |
78 | writeCom(&buf, nbfi) |
79 | } |
80 | buf.WriteString(p.FieldName(fi) + ": ") |
81 | buf.WriteString(valstr) |
82 | if p.fields[fi].IsBlank() { |
83 | buf.WriteString(" */") |
84 | } else { |
85 | nbfi++ |
86 | } |
87 | } |
88 | buf.WriteString("}") |
89 | return buf.String(), value |
90 | } |
91 | |
92 | func (p structparm) IsControl() bool { |
93 | return false |
94 | } |
95 | |
96 | func (p structparm) NumElements() int { |
97 | ne := 0 |
98 | for _, f := range p.fields { |
99 | ne += f.NumElements() |
100 | } |
101 | return ne |
102 | } |
103 | |
104 | func (p structparm) GenElemRef(elidx int, path string) (string, parm) { |
105 | ct := 0 |
106 | verb(4, "begin GenElemRef(%d,%s) on %s", elidx, path, p.String()) |
107 | |
108 | for fi, f := range p.fields { |
109 | fne := f.NumElements() |
110 | |
111 | //verb(4, "+ examining field %d fne %d ct %d", fi, fne, ct) |
112 | |
113 | // Empty field. Continue on. |
114 | if elidx == ct && fne == 0 { |
115 | continue |
116 | } |
117 | |
118 | // Is this field the element we're interested in? |
119 | if fne == 1 && elidx == ct { |
120 | |
121 | // The field in question may be a composite that has only |
122 | // multiple elements but a single non-zero-sized element. |
123 | // If this is the case, keep going. |
124 | if sp, ok := f.(*structparm); ok { |
125 | if len(sp.fields) > 1 { |
126 | ppath := fmt.Sprintf("%s.F%d", path, fi) |
127 | if p.fields[fi].IsBlank() || path == "_" { |
128 | ppath = "_" |
129 | } |
130 | return f.GenElemRef(elidx-ct, ppath) |
131 | } |
132 | } |
133 | |
134 | verb(4, "found field %d type %s in GenElemRef(%d,%s)", fi, f.TypeName(), elidx, path) |
135 | ppath := fmt.Sprintf("%s.F%d", path, fi) |
136 | if p.fields[fi].IsBlank() || path == "_" { |
137 | ppath = "_" |
138 | } |
139 | return ppath, f |
140 | } |
141 | |
142 | // Is the element we want somewhere inside this field? |
143 | if fne > 1 && elidx >= ct && elidx < ct+fne { |
144 | ppath := fmt.Sprintf("%s.F%d", path, fi) |
145 | if p.fields[fi].IsBlank() || path == "_" { |
146 | ppath = "_" |
147 | } |
148 | return f.GenElemRef(elidx-ct, ppath) |
149 | } |
150 | |
151 | ct += fne |
152 | } |
153 | panic(fmt.Sprintf("GenElemRef failed for struct %s elidx %d", p.TypeName(), elidx)) |
154 | } |
155 | |
156 | func (p structparm) HasPointer() bool { |
157 | for _, f := range p.fields { |
158 | if f.HasPointer() { |
159 | return true |
160 | } |
161 | } |
162 | return false |
163 | } |
164 |
Members