+++ /dev/null
-package main
-
-import (
- _ "fmt"
-)
-
-func (smith *Smith) initStatements() {
- smith.statements = []func(){
- smith.stmtOas,
- smith.stmtAs,
- smith.stmtInc,
- smith.stmtIf,
- smith.stmtFor,
- smith.stmtSend,
- smith.stmtRecv,
- smith.stmtSelect,
- smith.stmtSwitchExpr,
- smith.stmtSwitchType,
- smith.stmtTypeDecl,
- smith.stmtVarDecl,
- smith.stmtCall,
- smith.stmtReturn,
- smith.stmtBreak,
- smith.stmtContinue,
- smith.stmtGoto,
- smith.stmtSink,
- }
-}
-
-func (smith *Smith) genStatement() {
- if smith.stmtCount >= NStatements {
- return
- }
- smith.exprCount = 0
- smith.stmtCount++
- smith.statements[smith.rnd(len(smith.statements))]()
-}
-
-func (smith *Smith) stmtOas() {
- list := smith.atypeList(TraitAny)
- str, vars := smith.fmtOasVarList(list)
- smith.line("%v := %v", str, smith.fmtRvalueList(list))
- for _, v := range vars {
- smith.defineVar(v.id, v.typ)
- }
-}
-
-func (smith *Smith) stmtReturn() {
- smith.line("return %v", smith.fmtRvalueList(smith.curFunc.rets))
-}
-
-func (smith *Smith) stmtAs() {
- types := smith.atypeList(TraitAny)
- smith.line("%v = %v", smith.fmtLvalueList(types), smith.fmtRvalueList(types))
-}
-
-func (smith *Smith) stmtInc() {
- smith.line("%v %v", smith.lvalueOrMapIndex(smith.atype(ClassNumeric)), smith.choice("--", "++"))
-}
-
-func (smith *Smith) stmtIf() {
- smith.enterBlock(true)
- smith.enterBlock(true)
- if smith.rndBool() {
- smith.line("if %v {", smith.rvalue(smith.atype(ClassBoolean)))
- } else {
- smith.line("if %v; %v {", smith.stmtSimple(true, nil), smith.rvalue(smith.atype(ClassBoolean)))
- }
- smith.genBlock()
- if smith.rndBool() {
- smith.line("} else {")
- smith.genBlock()
- }
- smith.leaveBlock()
- smith.line("}")
- smith.leaveBlock()
-}
-
-func (smith *Smith) stmtFor() {
- smith.enterBlock(true)
- smith.enterBlock(true)
- smith.curBlock.isBreakable = true
- smith.curBlock.isContinuable = true
- var vars []*Var
- switch smith.choice("simple", "complex", "range") {
- case "simple":
- smith.line("for %v {", smith.rvalue(smith.atype(ClassBoolean)))
- case "complex":
- smith.line("for %v; %v; %v {", smith.stmtSimple(true, nil), smith.rvalue(smith.atype(ClassBoolean)), smith.stmtSimple(false, nil))
- case "range":
- switch smith.choice("slice", "string", "channel", "map") {
- case "slice":
- t := smith.atype(TraitAny)
- s := smith.rvalue(smith.sliceOf(t))
- switch smith.choice("one", "two", "oneDecl", "twoDecl") {
- case "one":
- smith.line("for %v = range %v {", smith.lvalueOrBlank(smith.intType), s)
- case "two":
- smith.line("for %v, %v = range %v {", smith.lvalueOrBlank(smith.intType), smith.lvalueOrBlank(t), s)
- case "oneDecl":
- id := smith.newId("Var")
- smith.line("for %v := range %v {", id, s)
- vars = append(vars, &Var{id: id, typ: smith.intType})
- case "twoDecl":
- types := []*Type{smith.intType, t}
- str := ""
- str, vars = smith.fmtOasVarList(types)
- smith.line("for %v := range %v {", str, s)
- default:
- panic("bad")
- }
- case "string":
- s := smith.rvalue(smith.stringType)
- switch smith.choice("one", "two", "oneDecl", "twoDecl") {
- case "one":
- smith.line("for %v = range %v {", smith.lvalueOrBlank(smith.intType), s)
- case "two":
- smith.line("for %v, %v = range %v {", smith.lvalueOrBlank(smith.intType), smith.lvalueOrBlank(smith.runeType), s)
- case "oneDecl":
- id := smith.newId("Var")
- smith.line("for %v := range %v {", id, s)
- vars = append(vars, &Var{id: id, typ: smith.intType})
- case "twoDecl":
- types := []*Type{smith.intType, smith.runeType}
- str := ""
- str, vars = smith.fmtOasVarList(types)
- smith.line("for %v := range %v {", str, s)
- default:
- panic("bad")
- }
- case "channel":
- cht := smith.atype(ClassChan)
- ch := smith.rvalue(cht)
- switch smith.choice("one", "oneDecl") {
- case "one":
- smith.line("for %v = range %v {", smith.lvalueOrBlank(cht.ktyp), ch)
- case "oneDecl":
- id := smith.newId("Var")
- smith.line("for %v := range %v {", id, ch)
- vars = append(vars, &Var{id: id, typ: cht.ktyp})
- default:
- panic("bad")
- }
- case "map":
- t := smith.atype(ClassMap)
- m := smith.rvalue(t)
- switch smith.choice("one", "two", "oneDecl", "twoDecl") {
- case "one":
- smith.line("for %v = range %v {", smith.lvalueOrBlank(t.ktyp), m)
- case "two":
- smith.line("for %v, %v = range %v {", smith.lvalueOrBlank(t.ktyp), smith.lvalueOrBlank(t.vtyp), m)
- case "oneDecl":
- id := smith.newId("Var")
- smith.line("for %v := range %v {", id, m)
- vars = append(vars, &Var{id: id, typ: t.ktyp})
- case "twoDecl":
- types := []*Type{t.ktyp, t.vtyp}
- str := ""
- str, vars = smith.fmtOasVarList(types)
- smith.line("for %v := range %v {", str, m)
- default:
- panic("bad")
- }
- default:
- panic("bad")
- }
- default:
- panic("bad")
- }
- smith.enterBlock(true)
- if len(vars) > 0 {
- smith.line("")
- for _, v := range vars {
- smith.defineVar(v.id, v.typ)
- }
- }
- smith.genBlock()
- smith.leaveBlock()
- smith.leaveBlock()
- smith.line("}")
- smith.leaveBlock()
-}
-
-func (smith *Smith) stmtSimple(oas bool, newVars *[]*Var) string {
- // We emit a fake statement in "oas", so make sure that nothing can be inserted in between.
- if smith.curBlock.extendable {
- panic("bad")
- }
- // "send" crashes gccgo with random errors too frequently.
- // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61273
- switch smith.choice("empty", "inc", "assign", "oas", "send", "expr") {
- case "empty":
- return ""
- case "inc":
- return F("%v %v", smith.lvalueOrMapIndex(smith.atype(ClassNumeric)), smith.choice("--", "++"))
- case "assign":
- list := smith.atypeList(TraitAny)
- return F("%v = %v", smith.fmtLvalueList(list), smith.fmtRvalueList(list))
- case "oas":
- if !oas {
- return ""
- }
- list := smith.atypeList(TraitAny)
- str, vars := smith.fmtOasVarList(list)
- if newVars != nil {
- *newVars = vars
- }
- res := F("%v := %v", str, smith.fmtRvalueList(list))
- smith.line("")
- for _, v := range vars {
- smith.defineVar(v.id, v.typ)
- }
- return res
- case "send":
- t := smith.atype(TraitSendable)
- return F("%v <- %v", smith.rvalue(t), smith.rvalue(t.ktyp))
- case "expr":
- return ""
- default:
- panic("bad")
- }
-}
-
-func (smith *Smith) stmtSend() {
- t := smith.atype(TraitSendable)
- smith.line("%v <- %v", smith.rvalue(t), smith.rvalue(t.ktyp))
-}
-
-func (smith *Smith) stmtRecv() {
- t := smith.atype(TraitReceivable)
- ch := smith.rvalue(t)
- switch smith.choice("normal", "decl") {
- case "normal":
- smith.line("%v, %v = <-%v", smith.lvalueOrBlank(t.ktyp), smith.lvalueOrBlank(smith.boolType), ch)
- case "decl":
- vv := smith.newId("Var")
- ok := smith.newId("Var")
- smith.line("%v, %v := <-%v", vv, ok, ch)
- smith.defineVar(vv, t.ktyp)
- smith.defineVar(ok, smith.boolType)
- default:
- panic("bad")
- }
-}
-
-func (smith *Smith) stmtTypeDecl() {
- id := smith.newId("Type")
- t := smith.atype(TraitAny)
- smith.line("type %v %v", id, t.id)
-
- newTyp := new(Type)
- *newTyp = *t
- newTyp.id = id
- newTyp.namedUserType = true
- if t.class == ClassStruct {
- newTyp.literal = func() string {
- // replace struct name with new type id
- l := t.literal()
- l = l[len(t.id)+1:]
- return "(" + id + l
- }
- newTyp.complexLiteral = func() string {
- // replace struct name with new type id
- l := t.complexLiteral()
- l = l[len(t.id)+1:]
- return "(" + id + l
- }
- } else {
- newTyp.literal = func() string {
- return F("%v(%v)", id, t.literal())
- }
- if t.complexLiteral != nil {
- newTyp.complexLiteral = func() string {
- return F("%v(%v)", id, t.complexLiteral())
- }
- }
- }
- smith.defineType(newTyp)
-}
-
-func (smith *Smith) stmtVarDecl() {
- id := smith.newId("Var")
- t := smith.atype(TraitAny)
- smith.line("var %v %v = %v", id, t.id, smith.rvalue(t))
- smith.defineVar(id, t)
-}
-
-func (smith *Smith) stmtSelect() {
- smith.enterBlock(true)
- smith.line("select {")
- for smith.rnd(5) != 0 {
- smith.enterBlock(true)
- elem := smith.atype(TraitAny)
- cht := smith.chanOf(elem)
- ch := smith.rvalue(cht)
- if smith.rndBool() {
- smith.line("case %v <- %v:", ch, smith.rvalue(elem))
- } else {
- switch smith.choice("one", "two", "oneDecl", "twoDecl") {
- case "one":
- smith.line("case %v = <-%v:", smith.lvalueOrBlank(elem), ch)
- case "two":
- smith.line("case %v, %v = <-%v:", smith.lvalueOrBlank(elem), smith.lvalueOrBlank(smith.boolType), ch)
- case "oneDecl":
- vv := smith.newId("Var")
- smith.line("case %v := <-%v:", vv, ch)
- smith.defineVar(vv, elem)
- case "twoDecl":
- vv := smith.newId("Var")
- ok := smith.newId("Var")
- smith.line("case %v, %v := <-%v:", vv, ok, ch)
- smith.defineVar(vv, elem)
- smith.defineVar(ok, smith.boolType)
- default:
- panic("bad")
- }
- }
- smith.genBlock()
- smith.leaveBlock()
- }
- if smith.rndBool() {
- smith.enterBlock(true)
- smith.line("default:")
- smith.genBlock()
- smith.leaveBlock()
- }
- smith.line("}")
- smith.leaveBlock()
-}
-
-func (smith *Smith) stmtSwitchExpr() {
- var t *Type
- cond := ""
- if smith.rndBool() {
- t = smith.atype(TraitComparable)
- cond = smith.rvalue(t)
- } else {
- t = smith.boolType
- }
- smith.enterBlock(true)
- smith.enterBlock(true)
- smith.curBlock.isBreakable = true
- var vars []*Var
- if smith.rndBool() {
- smith.line("switch %v {", cond)
- } else {
- smith.line("switch %v; %v {", smith.stmtSimple(true, &vars), cond)
- }
- // TODO: we generate at most one case, because if we generate more,
- // we can generate two cases with equal constants.
- fallth := false
- if smith.rndBool() {
- smith.enterBlock(true)
- smith.line("case %v:", smith.rvalue(t))
- smith.genBlock()
- smith.leaveBlock()
- if smith.rndBool() {
- fallth = true
- smith.line("fallthrough")
- }
- }
- if fallth || len(vars) > 0 || smith.rndBool() {
- smith.enterBlock(true)
- smith.line("default:")
- smith.genBlock()
- for _, v := range vars {
- smith.line("_ = %v", v.id)
- v.used = true
- }
- smith.leaveBlock()
- }
- smith.leaveBlock()
- smith.line("}")
- smith.leaveBlock()
-}
-
-func (smith *Smith) stmtSwitchType() {
- cond := smith.lvalue(smith.atype(TraitAny))
- smith.enterBlock(true)
- smith.curBlock.isBreakable = true
- smith.line("switch COND := (interface{})(%v); COND.(type) {", cond)
- if smith.rndBool() {
- smith.enterBlock(true)
- smith.line("case %v:", smith.atype(TraitAny).id)
- smith.genBlock()
- smith.leaveBlock()
- }
- if smith.rndBool() {
- smith.enterBlock(true)
- smith.line("default:")
- smith.genBlock()
- smith.leaveBlock()
- }
- smith.line("}")
- smith.leaveBlock()
-}
-
-func (smith *Smith) stmtCall() {
- if smith.rndBool() {
- smith.stmtCallBuiltin()
- }
- t := smith.atype(ClassFunction)
- prefix := smith.choice("", "go", "defer")
- smith.line("%v %v(%v)", prefix, smith.rvalue(t), smith.fmtRvalueList(t.styp))
-}
-
-func (smith *Smith) stmtCallBuiltin() {
- prefix := smith.choice("", "go", "defer")
- switch fn := smith.choice("close", "copy", "delete", "panic", "print", "println", "recover"); fn {
- case "close":
- smith.line("%v %v(%v)", prefix, fn, smith.rvalue(smith.atype(ClassChan)))
- case "copy":
- smith.line("%v %v", prefix, smith.exprCopySlice())
- case "delete":
- t := smith.atype(ClassMap)
- smith.line("%v %v(%v, %v)", prefix, fn, smith.rvalue(t), smith.rvalue(t.ktyp))
- case "panic":
- smith.line("%v %v(%v)", prefix, fn, smith.rvalue(smith.atype(TraitAny)))
- case "print":
- fallthrough
- case "println":
- list := smith.atypeList(TraitPrintable)
- smith.line("%v %v(%v)", prefix, fn, smith.fmtRvalueList(list))
- case "recover":
- smith.line("%v %v()", prefix, fn)
- default:
- panic("bad")
- }
-}
-
-func (smith *Smith) stmtBreak() {
- if !smith.curBlock.isBreakable {
- return
- }
- smith.line("break")
-}
-
-func (smith *Smith) stmtContinue() {
- if !smith.curBlock.isContinuable {
- return
- }
- smith.line("continue")
-}
-
-func (smith *Smith) stmtGoto() {
- // TODO: suppport goto down
- id := smith.materializeGotoLabel()
- smith.line("goto %v", id)
-}
-
-func (smith *Smith) stmtSink() {
- // Makes var escape.
- smith.line("SINK = %v", smith.exprVar(smith.atype(TraitAny)))
-}