Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.0.1-2020.1.5 / internal / gosmith / stmt.go
1 package main
2
3 import (
4         _ "fmt"
5 )
6
7 func (smith *Smith) initStatements() {
8         smith.statements = []func(){
9                 smith.stmtOas,
10                 smith.stmtAs,
11                 smith.stmtInc,
12                 smith.stmtIf,
13                 smith.stmtFor,
14                 smith.stmtSend,
15                 smith.stmtRecv,
16                 smith.stmtSelect,
17                 smith.stmtSwitchExpr,
18                 smith.stmtSwitchType,
19                 smith.stmtTypeDecl,
20                 smith.stmtVarDecl,
21                 smith.stmtCall,
22                 smith.stmtReturn,
23                 smith.stmtBreak,
24                 smith.stmtContinue,
25                 smith.stmtGoto,
26                 smith.stmtSink,
27         }
28 }
29
30 func (smith *Smith) genStatement() {
31         if smith.stmtCount >= NStatements {
32                 return
33         }
34         smith.exprCount = 0
35         smith.stmtCount++
36         smith.statements[smith.rnd(len(smith.statements))]()
37 }
38
39 func (smith *Smith) stmtOas() {
40         list := smith.atypeList(TraitAny)
41         str, vars := smith.fmtOasVarList(list)
42         smith.line("%v := %v", str, smith.fmtRvalueList(list))
43         for _, v := range vars {
44                 smith.defineVar(v.id, v.typ)
45         }
46 }
47
48 func (smith *Smith) stmtReturn() {
49         smith.line("return %v", smith.fmtRvalueList(smith.curFunc.rets))
50 }
51
52 func (smith *Smith) stmtAs() {
53         types := smith.atypeList(TraitAny)
54         smith.line("%v = %v", smith.fmtLvalueList(types), smith.fmtRvalueList(types))
55 }
56
57 func (smith *Smith) stmtInc() {
58         smith.line("%v %v", smith.lvalueOrMapIndex(smith.atype(ClassNumeric)), smith.choice("--", "++"))
59 }
60
61 func (smith *Smith) stmtIf() {
62         smith.enterBlock(true)
63         smith.enterBlock(true)
64         if smith.rndBool() {
65                 smith.line("if %v {", smith.rvalue(smith.atype(ClassBoolean)))
66         } else {
67                 smith.line("if %v; %v {", smith.stmtSimple(true, nil), smith.rvalue(smith.atype(ClassBoolean)))
68         }
69         smith.genBlock()
70         if smith.rndBool() {
71                 smith.line("} else {")
72                 smith.genBlock()
73         }
74         smith.leaveBlock()
75         smith.line("}")
76         smith.leaveBlock()
77 }
78
79 func (smith *Smith) stmtFor() {
80         smith.enterBlock(true)
81         smith.enterBlock(true)
82         smith.curBlock.isBreakable = true
83         smith.curBlock.isContinuable = true
84         var vars []*Var
85         switch smith.choice("simple", "complex", "range") {
86         case "simple":
87                 smith.line("for %v {", smith.rvalue(smith.atype(ClassBoolean)))
88         case "complex":
89                 smith.line("for %v; %v; %v {", smith.stmtSimple(true, nil), smith.rvalue(smith.atype(ClassBoolean)), smith.stmtSimple(false, nil))
90         case "range":
91                 switch smith.choice("slice", "string", "channel", "map") {
92                 case "slice":
93                         t := smith.atype(TraitAny)
94                         s := smith.rvalue(smith.sliceOf(t))
95                         switch smith.choice("one", "two", "oneDecl", "twoDecl") {
96                         case "one":
97                                 smith.line("for %v = range %v {", smith.lvalueOrBlank(smith.intType), s)
98                         case "two":
99                                 smith.line("for %v, %v = range %v {", smith.lvalueOrBlank(smith.intType), smith.lvalueOrBlank(t), s)
100                         case "oneDecl":
101                                 id := smith.newId("Var")
102                                 smith.line("for %v := range %v {", id, s)
103                                 vars = append(vars, &Var{id: id, typ: smith.intType})
104                         case "twoDecl":
105                                 types := []*Type{smith.intType, t}
106                                 str := ""
107                                 str, vars = smith.fmtOasVarList(types)
108                                 smith.line("for %v := range %v {", str, s)
109                         default:
110                                 panic("bad")
111                         }
112                 case "string":
113                         s := smith.rvalue(smith.stringType)
114                         switch smith.choice("one", "two", "oneDecl", "twoDecl") {
115                         case "one":
116                                 smith.line("for %v = range %v {", smith.lvalueOrBlank(smith.intType), s)
117                         case "two":
118                                 smith.line("for %v, %v = range %v {", smith.lvalueOrBlank(smith.intType), smith.lvalueOrBlank(smith.runeType), s)
119                         case "oneDecl":
120                                 id := smith.newId("Var")
121                                 smith.line("for %v := range %v {", id, s)
122                                 vars = append(vars, &Var{id: id, typ: smith.intType})
123                         case "twoDecl":
124                                 types := []*Type{smith.intType, smith.runeType}
125                                 str := ""
126                                 str, vars = smith.fmtOasVarList(types)
127                                 smith.line("for %v := range %v {", str, s)
128                         default:
129                                 panic("bad")
130                         }
131                 case "channel":
132                         cht := smith.atype(ClassChan)
133                         ch := smith.rvalue(cht)
134                         switch smith.choice("one", "oneDecl") {
135                         case "one":
136                                 smith.line("for %v = range %v {", smith.lvalueOrBlank(cht.ktyp), ch)
137                         case "oneDecl":
138                                 id := smith.newId("Var")
139                                 smith.line("for %v := range %v {", id, ch)
140                                 vars = append(vars, &Var{id: id, typ: cht.ktyp})
141                         default:
142                                 panic("bad")
143                         }
144                 case "map":
145                         t := smith.atype(ClassMap)
146                         m := smith.rvalue(t)
147                         switch smith.choice("one", "two", "oneDecl", "twoDecl") {
148                         case "one":
149                                 smith.line("for %v = range %v {", smith.lvalueOrBlank(t.ktyp), m)
150                         case "two":
151                                 smith.line("for %v, %v = range %v {", smith.lvalueOrBlank(t.ktyp), smith.lvalueOrBlank(t.vtyp), m)
152                         case "oneDecl":
153                                 id := smith.newId("Var")
154                                 smith.line("for %v := range %v {", id, m)
155                                 vars = append(vars, &Var{id: id, typ: t.ktyp})
156                         case "twoDecl":
157                                 types := []*Type{t.ktyp, t.vtyp}
158                                 str := ""
159                                 str, vars = smith.fmtOasVarList(types)
160                                 smith.line("for %v := range %v {", str, m)
161                         default:
162                                 panic("bad")
163                         }
164                 default:
165                         panic("bad")
166                 }
167         default:
168                 panic("bad")
169         }
170         smith.enterBlock(true)
171         if len(vars) > 0 {
172                 smith.line("")
173                 for _, v := range vars {
174                         smith.defineVar(v.id, v.typ)
175                 }
176         }
177         smith.genBlock()
178         smith.leaveBlock()
179         smith.leaveBlock()
180         smith.line("}")
181         smith.leaveBlock()
182 }
183
184 func (smith *Smith) stmtSimple(oas bool, newVars *[]*Var) string {
185         // We emit a fake statement in "oas", so make sure that nothing can be inserted in between.
186         if smith.curBlock.extendable {
187                 panic("bad")
188         }
189         // "send" crashes gccgo with random errors too frequently.
190         // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61273
191         switch smith.choice("empty", "inc", "assign", "oas", "send", "expr") {
192         case "empty":
193                 return ""
194         case "inc":
195                 return F("%v %v", smith.lvalueOrMapIndex(smith.atype(ClassNumeric)), smith.choice("--", "++"))
196         case "assign":
197                 list := smith.atypeList(TraitAny)
198                 return F("%v = %v", smith.fmtLvalueList(list), smith.fmtRvalueList(list))
199         case "oas":
200                 if !oas {
201                         return ""
202                 }
203                 list := smith.atypeList(TraitAny)
204                 str, vars := smith.fmtOasVarList(list)
205                 if newVars != nil {
206                         *newVars = vars
207                 }
208                 res := F("%v := %v", str, smith.fmtRvalueList(list))
209                 smith.line("")
210                 for _, v := range vars {
211                         smith.defineVar(v.id, v.typ)
212                 }
213                 return res
214         case "send":
215                 t := smith.atype(TraitSendable)
216                 return F("%v <- %v", smith.rvalue(t), smith.rvalue(t.ktyp))
217         case "expr":
218                 return ""
219         default:
220                 panic("bad")
221         }
222 }
223
224 func (smith *Smith) stmtSend() {
225         t := smith.atype(TraitSendable)
226         smith.line("%v <- %v", smith.rvalue(t), smith.rvalue(t.ktyp))
227 }
228
229 func (smith *Smith) stmtRecv() {
230         t := smith.atype(TraitReceivable)
231         ch := smith.rvalue(t)
232         switch smith.choice("normal", "decl") {
233         case "normal":
234                 smith.line("%v, %v = <-%v", smith.lvalueOrBlank(t.ktyp), smith.lvalueOrBlank(smith.boolType), ch)
235         case "decl":
236                 vv := smith.newId("Var")
237                 ok := smith.newId("Var")
238                 smith.line("%v, %v := <-%v", vv, ok, ch)
239                 smith.defineVar(vv, t.ktyp)
240                 smith.defineVar(ok, smith.boolType)
241         default:
242                 panic("bad")
243         }
244 }
245
246 func (smith *Smith) stmtTypeDecl() {
247         id := smith.newId("Type")
248         t := smith.atype(TraitAny)
249         smith.line("type %v %v", id, t.id)
250
251         newTyp := new(Type)
252         *newTyp = *t
253         newTyp.id = id
254         newTyp.namedUserType = true
255         if t.class == ClassStruct {
256                 newTyp.literal = func() string {
257                         // replace struct name with new type id
258                         l := t.literal()
259                         l = l[len(t.id)+1:]
260                         return "(" + id + l
261                 }
262                 newTyp.complexLiteral = func() string {
263                         // replace struct name with new type id
264                         l := t.complexLiteral()
265                         l = l[len(t.id)+1:]
266                         return "(" + id + l
267                 }
268         } else {
269                 newTyp.literal = func() string {
270                         return F("%v(%v)", id, t.literal())
271                 }
272                 if t.complexLiteral != nil {
273                         newTyp.complexLiteral = func() string {
274                                 return F("%v(%v)", id, t.complexLiteral())
275                         }
276                 }
277         }
278         smith.defineType(newTyp)
279 }
280
281 func (smith *Smith) stmtVarDecl() {
282         id := smith.newId("Var")
283         t := smith.atype(TraitAny)
284         smith.line("var %v %v = %v", id, t.id, smith.rvalue(t))
285         smith.defineVar(id, t)
286 }
287
288 func (smith *Smith) stmtSelect() {
289         smith.enterBlock(true)
290         smith.line("select {")
291         for smith.rnd(5) != 0 {
292                 smith.enterBlock(true)
293                 elem := smith.atype(TraitAny)
294                 cht := smith.chanOf(elem)
295                 ch := smith.rvalue(cht)
296                 if smith.rndBool() {
297                         smith.line("case %v <- %v:", ch, smith.rvalue(elem))
298                 } else {
299                         switch smith.choice("one", "two", "oneDecl", "twoDecl") {
300                         case "one":
301                                 smith.line("case %v = <-%v:", smith.lvalueOrBlank(elem), ch)
302                         case "two":
303                                 smith.line("case %v, %v = <-%v:", smith.lvalueOrBlank(elem), smith.lvalueOrBlank(smith.boolType), ch)
304                         case "oneDecl":
305                                 vv := smith.newId("Var")
306                                 smith.line("case %v := <-%v:", vv, ch)
307                                 smith.defineVar(vv, elem)
308                         case "twoDecl":
309                                 vv := smith.newId("Var")
310                                 ok := smith.newId("Var")
311                                 smith.line("case %v, %v := <-%v:", vv, ok, ch)
312                                 smith.defineVar(vv, elem)
313                                 smith.defineVar(ok, smith.boolType)
314                         default:
315                                 panic("bad")
316                         }
317                 }
318                 smith.genBlock()
319                 smith.leaveBlock()
320         }
321         if smith.rndBool() {
322                 smith.enterBlock(true)
323                 smith.line("default:")
324                 smith.genBlock()
325                 smith.leaveBlock()
326         }
327         smith.line("}")
328         smith.leaveBlock()
329 }
330
331 func (smith *Smith) stmtSwitchExpr() {
332         var t *Type
333         cond := ""
334         if smith.rndBool() {
335                 t = smith.atype(TraitComparable)
336                 cond = smith.rvalue(t)
337         } else {
338                 t = smith.boolType
339         }
340         smith.enterBlock(true)
341         smith.enterBlock(true)
342         smith.curBlock.isBreakable = true
343         var vars []*Var
344         if smith.rndBool() {
345                 smith.line("switch %v {", cond)
346         } else {
347                 smith.line("switch %v; %v {", smith.stmtSimple(true, &vars), cond)
348         }
349         // TODO: we generate at most one case, because if we generate more,
350         // we can generate two cases with equal constants.
351         fallth := false
352         if smith.rndBool() {
353                 smith.enterBlock(true)
354                 smith.line("case %v:", smith.rvalue(t))
355                 smith.genBlock()
356                 smith.leaveBlock()
357                 if smith.rndBool() {
358                         fallth = true
359                         smith.line("fallthrough")
360                 }
361         }
362         if fallth || len(vars) > 0 || smith.rndBool() {
363                 smith.enterBlock(true)
364                 smith.line("default:")
365                 smith.genBlock()
366                 for _, v := range vars {
367                         smith.line("_ = %v", v.id)
368                         v.used = true
369                 }
370                 smith.leaveBlock()
371         }
372         smith.leaveBlock()
373         smith.line("}")
374         smith.leaveBlock()
375 }
376
377 func (smith *Smith) stmtSwitchType() {
378         cond := smith.lvalue(smith.atype(TraitAny))
379         smith.enterBlock(true)
380         smith.curBlock.isBreakable = true
381         smith.line("switch COND := (interface{})(%v); COND.(type) {", cond)
382         if smith.rndBool() {
383                 smith.enterBlock(true)
384                 smith.line("case %v:", smith.atype(TraitAny).id)
385                 smith.genBlock()
386                 smith.leaveBlock()
387         }
388         if smith.rndBool() {
389                 smith.enterBlock(true)
390                 smith.line("default:")
391                 smith.genBlock()
392                 smith.leaveBlock()
393         }
394         smith.line("}")
395         smith.leaveBlock()
396 }
397
398 func (smith *Smith) stmtCall() {
399         if smith.rndBool() {
400                 smith.stmtCallBuiltin()
401         }
402         t := smith.atype(ClassFunction)
403         prefix := smith.choice("", "go", "defer")
404         smith.line("%v %v(%v)", prefix, smith.rvalue(t), smith.fmtRvalueList(t.styp))
405 }
406
407 func (smith *Smith) stmtCallBuiltin() {
408         prefix := smith.choice("", "go", "defer")
409         switch fn := smith.choice("close", "copy", "delete", "panic", "print", "println", "recover"); fn {
410         case "close":
411                 smith.line("%v %v(%v)", prefix, fn, smith.rvalue(smith.atype(ClassChan)))
412         case "copy":
413                 smith.line("%v %v", prefix, smith.exprCopySlice())
414         case "delete":
415                 t := smith.atype(ClassMap)
416                 smith.line("%v %v(%v, %v)", prefix, fn, smith.rvalue(t), smith.rvalue(t.ktyp))
417         case "panic":
418                 smith.line("%v %v(%v)", prefix, fn, smith.rvalue(smith.atype(TraitAny)))
419         case "print":
420                 fallthrough
421         case "println":
422                 list := smith.atypeList(TraitPrintable)
423                 smith.line("%v %v(%v)", prefix, fn, smith.fmtRvalueList(list))
424         case "recover":
425                 smith.line("%v %v()", prefix, fn)
426         default:
427                 panic("bad")
428         }
429 }
430
431 func (smith *Smith) stmtBreak() {
432         if !smith.curBlock.isBreakable {
433                 return
434         }
435         smith.line("break")
436 }
437
438 func (smith *Smith) stmtContinue() {
439         if !smith.curBlock.isContinuable {
440                 return
441         }
442         smith.line("continue")
443 }
444
445 func (smith *Smith) stmtGoto() {
446         // TODO: suppport goto down
447         id := smith.materializeGotoLabel()
448         smith.line("goto %v", id)
449 }
450
451 func (smith *Smith) stmtSink() {
452         // Makes var escape.
453         smith.line("SINK = %v", smith.exprVar(smith.atype(TraitAny)))
454 }