]> Cypherpunks.ru repositories - gostls13.git/blob - test/rangegen.go
7916ed2b9fd35662ffa730d5d127908e580634da
[gostls13.git] / test / rangegen.go
1 // runoutput -goexperiment range
2
3 // Copyright 2023 The Go Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
6
7 // Torture test for range-over-func.
8 //
9 // cmd/internal/testdir runs this like
10 //
11 //      go run rangegen.go >x.go
12 //      go run x.go
13 //
14 // but a longer version can be run using
15 //
16 //      go run rangegen.go long
17 //
18 // In that second form, rangegen takes care of compiling
19 // and running the code it generates, in batches.
20 // That form takes 10-20 minutes to run.
21
22 package main
23
24 import (
25         "bytes"
26         "fmt"
27         "log"
28         "os"
29         "os/exec"
30         "strings"
31 )
32
33 const verbose = false
34
35 func main() {
36         long := len(os.Args) > 1 && os.Args[1] == "long"
37         log.SetFlags(0)
38         log.SetPrefix("rangegen: ")
39
40         b := new(bytes.Buffer)
41         tests := ""
42         flush := func(force bool) {
43                 if !long || (strings.Count(tests, "\n") < 1000 && !force) {
44                         return
45                 }
46                 p(b, mainCode, tests)
47                 err := os.WriteFile("tmp.go", b.Bytes(), 0666)
48                 if err != nil {
49                         log.Fatal(err)
50                 }
51                 out, err := exec.Command("go", "run", "tmp.go").CombinedOutput()
52                 if err != nil {
53                         log.Fatalf("go run tmp.go: %v\n%s", err, out)
54                 }
55                 print(".")
56                 if force {
57                         print("\nPASS\n")
58                 }
59                 b.Reset()
60                 tests = ""
61                 p(b, "package main\n\n")
62                 p(b, "const verbose = %v\n\n", verbose)
63         }
64
65         p(b, "package main\n\n")
66         p(b, "const verbose = %v\n\n", verbose)
67         max := 2
68         if !long {
69                 max = 5
70         }
71         for i := 1; i <= max; i++ {
72                 maxDouble := -1
73                 if long {
74                         maxDouble = i
75                 }
76                 for double := -1; double <= maxDouble; double++ {
77                         code := gen(new(bytes.Buffer), "", "", "", i, double, func(c int) bool { return true })
78                         for j := 0; j < code; j++ {
79                                 hi := j + 1
80                                 if long {
81                                         hi = code
82                                 }
83                                 for k := j; k < hi && k < code; k++ {
84                                         s := fmt.Sprintf("%d_%d_%d_%d", i, double+1, j, k)
85                                         code0 := gen(b, "testFunc"+s, "", "yield2", i, double, func(c int) bool { return c == j || c == k })
86                                         code1 := gen(b, "testSlice"+s, "_, ", "slice2", i, double, func(c int) bool { return c == j || c == k })
87                                         if code0 != code1 {
88                                                 panic("bad generator")
89                                         }
90                                         tests += "test" + s + "()\n"
91                                         p(b, testCode, "test"+s, []int{j, k}, "testFunc"+s, "testSlice"+s)
92                                         flush(false)
93                                 }
94                         }
95                 }
96         }
97         for i := 1; i <= max; i++ {
98                 maxDouble := -1
99                 if long {
100                         maxDouble = i
101                 }
102                 for double := -1; double <= maxDouble; double++ {
103                         s := fmt.Sprintf("%d_%d", i, double+1)
104                         code := gen(b, "testFunc"+s, "", "yield2", i, double, func(c int) bool { return true })
105                         code1 := gen(b, "testSlice"+s, "_, ", "slice2", i, double, func(c int) bool { return true })
106                         if code != code1 {
107                                 panic("bad generator")
108                         }
109                         tests += "test" + s + "()\n"
110                         var all []int
111                         for j := 0; j < code; j++ {
112                                 all = append(all, j)
113                         }
114                         p(b, testCode, "test"+s, all, "testFunc"+s, "testSlice"+s)
115                         flush(false)
116                 }
117         }
118         if long {
119                 flush(true)
120                 os.Remove("tmp.go")
121                 return
122         }
123
124         p(b, mainCode, tests)
125
126         os.Stdout.Write(b.Bytes())
127 }
128
129 func p(b *bytes.Buffer, format string, args ...any) {
130         fmt.Fprintf(b, format, args...)
131 }
132
133 func gen(b *bytes.Buffer, name, prefix, rangeExpr string, depth, double int, allowed func(int) bool) int {
134         p(b, "func %s(o *output, code int) int {\n", name)
135         p(b, "  dfr := 0; _ = dfr\n")
136         code := genLoop(b, 0, prefix, rangeExpr, depth, double, 0, "", allowed)
137         p(b, "  return 0\n")
138         p(b, "}\n\n")
139         return code
140 }
141
142 func genLoop(b *bytes.Buffer, d int, prefix, rangeExpr string, depth, double, code int, labelSuffix string, allowed func(int) bool) int {
143         limit := 1
144         if d == double {
145                 limit = 2
146         }
147         for rep := 0; rep < limit; rep++ {
148                 if rep == 1 {
149                         labelSuffix = "R"
150                 }
151                 s := fmt.Sprintf("%d%s", d, labelSuffix)
152                 p(b, "  o.log(`top%s`)\n", s)
153                 p(b, "  l%sa := 0\n", s)
154                 p(b, "goto L%sa; L%sa:  o.log(`L%sa`)\n", s, s, s)
155                 p(b, "  if l%sa++; l%sa >= 2 { o.log(`loop L%sa`); return -1 }\n", s, s, s)
156                 p(b, "  l%sfor := 0\n", s)
157                 p(b, "goto L%sfor; L%sfor: for f := 0; f < 1; f++ { o.log(`L%sfor`)\n", s, s, s)
158                 p(b, "  if l%sfor++; l%sfor >= 2 { o.log(`loop L%sfor`); return -1 }\n", s, s, s)
159                 p(b, "  l%ssw := 0\n", s)
160                 p(b, "goto L%ssw; L%ssw: switch { default: o.log(`L%ssw`)\n", s, s, s)
161                 p(b, "  if l%ssw++; l%ssw >= 2 { o.log(`loop L%ssw`); return -1 }\n", s, s, s)
162                 p(b, "  l%ssel := 0\n", s)
163                 p(b, "goto L%ssel; L%ssel: select { default: o.log(`L%ssel`)\n", s, s, s)
164                 p(b, "  if l%ssel++; l%ssel >= 2 { o.log(`loop L%ssel`); return -1 }\n", s, s, s)
165                 p(b, "  l%s := 0\n", s)
166                 p(b, "goto L%s; L%s:    for %s i%s := range %s {\n", s, s, prefix, s, rangeExpr)
167                 p(b, "  o.log1(`L%s top`, i%s)\n", s, s)
168                 p(b, "  if l%s++; l%s >= 4 { o.log(`loop L%s`); return -1 }\n", s, s, s)
169                 printTests := func() {
170                         if code++; allowed(code) {
171                                 p(b, "  if code == %v { break }\n", code)
172                         }
173                         if code++; allowed(code) {
174                                 p(b, "  if code == %v { continue }\n", code)
175                         }
176                         if code++; allowed(code) {
177                                 p(b, "  switch { case code == %v: continue }\n", code)
178                         }
179                         if code++; allowed(code) {
180                                 p(b, "  if code == %v { return %[1]v }\n", code)
181                         }
182                         if code++; allowed(code) {
183                                 p(b, "  if code == %v { select { default: break } }\n", code)
184                         }
185                         if code++; allowed(code) {
186                                 p(b, "  if code == %v { switch { default: break } }\n", code)
187                         }
188                         if code++; allowed(code) {
189                                 p(b, "  if code == %v { dfr++; defer o.log1(`defer %d`, dfr) }\n", code, code)
190                         }
191                         for i := d; i > 0; i-- {
192                                 suffix := labelSuffix
193                                 if i < double {
194                                         suffix = ""
195                                 }
196                                 if code++; allowed(code) {
197                                         p(b, "  if code == %v { break L%d%s }\n", code, i, suffix)
198                                 }
199                                 if code++; allowed(code) {
200                                         p(b, "  if code == %v { select { default: break L%d%s } }\n", code, i, suffix)
201                                 }
202                                 if code++; allowed(code) {
203                                         p(b, "  if code == %v { break L%d%s }\n", code, i, suffix)
204                                 }
205                                 if code++; allowed(code) {
206                                         p(b, "  if code == %v { break L%d%ssw }\n", code, i, suffix)
207                                 }
208                                 if code++; allowed(code) {
209                                         p(b, "  if code == %v { break L%d%ssel }\n", code, i, suffix)
210                                 }
211                                 if code++; allowed(code) {
212                                         p(b, "  if code == %v { break L%d%sfor }\n", code, i, suffix)
213                                 }
214                                 if code++; allowed(code) {
215                                         p(b, "  if code == %v { continue L%d%sfor }\n", code, i, suffix)
216                                 }
217                                 if code++; allowed(code) {
218                                         p(b, "  if code == %v { goto L%d%sa }\n", code, i, suffix)
219                                 }
220                                 if code++; allowed(code) {
221                                         p(b, "  if code == %v { goto L%d%s }\n", code, i, suffix)
222                                 }
223                                 if code++; allowed(code) {
224                                         p(b, "  if code == %v { goto L%d%sb }\n", code, i, suffix)
225                                 }
226                         }
227                 }
228                 printTests()
229                 if d < depth {
230                         if rep == 1 {
231                                 double = d // signal to children to use the rep=1 labels
232                         }
233                         code = genLoop(b, d+1, prefix, rangeExpr, depth, double, code, labelSuffix, allowed)
234                         printTests()
235                 }
236                 p(b, "  o.log(`L%s bot`)\n", s)
237                 p(b, "  }\n")
238                 p(b, "  o.log(`L%ssel bot`)\n", s)
239                 p(b, "  }\n")
240                 p(b, "  o.log(`L%ssw bot`)\n", s)
241                 p(b, "  }\n")
242                 p(b, "  o.log(`L%sfor bot`)\n", s)
243                 p(b, "  }\n")
244                 p(b, "  o.log(`done%s`)\n", s)
245                 p(b, "goto L%sb; L%sb: o.log(`L%sb`)\n", s, s, s)
246         }
247         return code
248 }
249
250 var testCode = `
251 func %s() {
252         all := %#v
253         for i := 0; i < len(all); i++ {
254                 c := all[i]
255                 outFunc := run(%s, c)
256                 outSlice := run(%s, c)
257                 if !outFunc.eq(outSlice) {
258                         println("mismatch", "%[3]s", "%[4]s", c)
259                         println()
260                         println("func:")
261                         outFunc.print()
262                         println()
263                         println("slice:")
264                         outSlice.print()
265                         panic("mismatch")
266                 }
267         }
268         if verbose {
269                 println("did", "%[3]s", "%[4]s", len(all))
270         }
271 }
272 `
273
274 var mainCode = `
275
276 func main() {
277         if verbose {
278                 println("main")
279         }
280         %s
281 }
282
283 func yield2(yield func(int)bool) { _ = yield(1) && yield(2) }
284 var slice2 = []int{1,2}
285
286 type output struct {
287         ret int
288         trace []any
289 }
290
291 func (o *output) log(x any) {
292         o.trace = append(o.trace, x)
293 }
294
295 func (o *output) log1(x, y any) {
296         o.trace = append(o.trace, x, y)
297 }
298
299 func (o *output) eq(p *output) bool{
300         if o.ret != p.ret  || len(o.trace) != len(p.trace) {
301                 return false
302         }
303         for i ,x := range o.trace {
304                 if x != p.trace[i] {
305                         return false
306                 }
307         }
308         return true
309 }
310
311 func (o *output) print() {
312         println("ret", o.ret, "trace-len", len(o.trace))
313         for i := 0; i < len(o.trace); i++ {
314                 print("#", i, " ")
315                 switch x := o.trace[i].(type) {
316                 case int:
317                         print(x)
318                 case string:
319                         print(x)
320                 default:
321                         print(x)
322                 }
323                 print("\n")
324         }
325 }
326
327 func run(f func(*output, int)int, i int) *output {
328         o := &output{}
329         o.ret = f(o, i)
330         return o
331 }
332
333 `