4 Large uncovered parts are:
6 - type assignability and identity
8 - interfaces, types implementing interfaces, type assertions
27 packages [NPackages]*Package
36 predefinedTypes []*Type
49 expressions []func(res *Type) string
67 NTotalExprCount = 1000
73 imports map[string]bool
114 func (smith *Smith) writeProgram(dir string) {
116 smith.initExpressions()
117 smith.initStatements()
119 for pi := range smith.packages {
122 smith.serializeProgram(dir)
125 func (smith *Smith) initProgram() {
126 smith.packages[0] = smith.newPackage("main")
127 smith.packages[0].undefFuncs = []*Func{
128 {name: "init", args: []*Type{}, rets: []*Type{}},
129 {name: "init", args: []*Type{}, rets: []*Type{}},
130 {name: "main", args: []*Type{}, rets: []*Type{}},
133 smith.packages[1] = smith.newPackage("a")
134 smith.packages[2] = smith.newPackage("b")
138 func (smith *Smith) newPackage(name string) *Package {
139 return &Package{name: name, imports: make(map[string]bool), top: &Block{extendable: true}}
142 func (smith *Smith) genPackage(pi int) {
147 smith.totalExprCount = 0
149 p := smith.packages[pi]
153 for len(p.undefFuncs) != 0 || len(p.undefVars) != 0 {
154 if len(p.undefFuncs) != 0 {
155 f := p.undefFuncs[len(p.undefFuncs)-1]
156 p.undefFuncs = p.undefFuncs[:len(p.undefFuncs)-1]
157 smith.genToplevFunction(pi, f)
159 if len(p.undefVars) != 0 {
160 v := p.undefVars[len(p.undefVars)-1]
161 p.undefVars = p.undefVars[:len(p.undefVars)-1]
162 smith.genToplevVar(pi, v)
167 func F(f string, args ...interface{}) string {
168 return fmt.Sprintf(f, args...)
171 func (smith *Smith) line(f string, args ...interface{}) {
173 b := &Block{parent: smith.curBlock, str: s}
174 if smith.curBlockPos+1 == len(smith.curBlock.sub) {
175 smith.curBlock.sub = append(smith.curBlock.sub, b)
177 smith.curBlock.sub = append(smith.curBlock.sub, nil)
178 copy(smith.curBlock.sub[smith.curBlockPos+2:], smith.curBlock.sub[smith.curBlockPos+1:])
179 smith.curBlock.sub[smith.curBlockPos+1] = b
184 func (smith *Smith) resetContext(pi int) {
185 smith.curPackage = pi
186 p := smith.packages[pi]
187 smith.curBlock = p.top
188 smith.curBlockPos = len(smith.curBlock.sub) - 1
192 func (smith *Smith) genToplevFunction(pi int, f *Func) {
193 smith.resetContext(pi)
195 smith.enterBlock(true)
196 smith.enterBlock(true)
197 argIds := make([]string, len(f.args))
199 for i, a := range f.args {
200 argIds[i] = smith.newId("Param")
204 argStr += argIds[i] + " " + a.id
206 smith.line("func %v(%v)%v {", f.name, argStr, fmtTypeList(f.rets, false))
207 for i, a := range f.args {
208 smith.defineVar(argIds[i], a)
210 smith.curBlock.funcBoundary = true
216 if f.name != "init" {
217 smith.packages[smith.curPackage].toplevFuncs = append(smith.packages[smith.curPackage].toplevFuncs, f)
221 func (smith *Smith) genToplevVar(pi int, v *Var) {
222 smith.resetContext(pi)
223 smith.enterBlock(true)
224 smith.line("var %v = %v", v.id, smith.rvalue(v.typ))
226 smith.packages[smith.curPackage].toplevVars = append(smith.packages[smith.curPackage].toplevVars, v)
229 func (smith *Smith) genBlock() {
230 smith.enterBlock(false)
231 for smith.rnd(10) != 0 {
237 func (smith *Smith) serializeProgram(dir string) {
238 for _, p := range smith.packages {
242 path := filepath.Join(dir, "src", p.name)
243 os.MkdirAll(path, os.ModePerm)
248 files := make([]*bufio.Writer, nf)
249 for i := range files {
250 fname := filepath.Join(path, fmt.Sprintf("%v.go", i))
251 f, err := os.Create(fname)
253 fmt.Fprintf(os.Stdout, "failed to create a file: %v\n", err)
256 w := bufio.NewWriter(bufio.NewWriter(f))
262 fmt.Fprintf(w, "package %s\n", p.name)
263 for imp := range p.imports {
264 fmt.Fprintf(w, "import \"%s\"\n", imp)
266 if i == 0 && p.name == "main" {
267 fmt.Fprintf(w, "import \"runtime\"\n")
268 fmt.Fprintf(w, "func init() {\n")
269 fmt.Fprintf(w, " go func() {\n")
270 fmt.Fprintf(w, " for {\n")
271 fmt.Fprintf(w, " runtime.GC()\n")
272 fmt.Fprintf(w, " runtime.Gosched()\n")
273 fmt.Fprintf(w, " }\n")
274 fmt.Fprintf(w, " }()\n")
275 fmt.Fprintf(w, "}\n")
277 for imp := range p.imports {
278 fmt.Fprintf(w, "var _ = %s.UsePackage\n", imp)
281 fmt.Fprintf(w, "var UsePackage = 0\n")
282 fmt.Fprintf(w, "var SINK interface{}\n")
285 for _, decl := range p.top.sub {
286 serializeBlock(files[smith.rnd(len(files))], decl, 0)
290 path := filepath.Join(dir, "src", "a")
291 os.MkdirAll(path, os.ModePerm)
292 fname := filepath.Join(path, "0_test.go")
293 f, err := os.Create(fname)
295 fmt.Fprintf(os.Stdout, "failed to create a file: %v\n", err)
298 f.Write([]byte("package a\n"))
302 func serializeBlock(w *bufio.Writer, b *Block, d int) {
309 w.WriteString("/*" + strings.Repeat("*", d) + "*/ ")
311 w.WriteString(F(" // ext=%v vars=%v types=%v", b.extendable, len(b.vars), len(b.types)))
314 for _, b1 := range b.sub {
315 serializeBlock(w, b1, d+1)
319 func (smith *Smith) vars() []*Var {
321 vars = append(vars, smith.packages[smith.curPackage].toplevVars...)
322 var f func(b *Block, pos int)
323 f = func(b *Block, pos int) {
324 for _, b1 := range b.sub[:pos+1] {
325 vars = append(vars, b1.vars...)
328 pos := len(b.parent.sub) - 1
329 if b.subBlock != nil {
331 for i, b1 := range b.parent.sub {
332 if b1 == b.subBlock {
344 f(smith.curBlock, smith.curBlockPos)
348 func (smith *Smith) types() []*Type {
350 types = append(types, smith.predefinedTypes...)
351 var f func(b *Block, pos int)
352 f = func(b *Block, pos int) {
353 for _, b1 := range b.sub[:pos+1] {
354 types = append(types, b1.types...)
357 pos := len(b.parent.sub) - 1
358 if b.subBlock != nil {
360 for i, b1 := range b.parent.sub {
361 if b1 == b.subBlock {
373 f(smith.curBlock, smith.curBlockPos)
377 func (smith *Smith) defineVar(id string, t *Type) {
378 v := &Var{id: id, typ: t, block: smith.curBlock}
379 b := smith.curBlock.sub[smith.curBlockPos]
380 b.vars = append(b.vars, v)
383 func (smith *Smith) defineType(t *Type) {
384 b := smith.curBlock.sub[smith.curBlockPos]
385 b.types = append(b.types, t)
388 func (smith *Smith) materializeVar(t *Type) string {
389 // TODO: generate var in another package
390 id := smith.newId("Var")
391 curBlock0 := smith.curBlock
392 curBlockPos0 := smith.curBlockPos
393 curBlockLen0 := len(smith.curBlock.sub)
394 exprDepth0 := smith.exprDepth
395 exprCount0 := smith.exprCount
399 if smith.curBlock == curBlock0 {
400 curBlockPos0 += len(smith.curBlock.sub) - curBlockLen0
402 smith.curBlock = curBlock0
403 smith.curBlockPos = curBlockPos0
404 smith.exprDepth = exprDepth0
405 smith.exprCount = exprCount0
409 if smith.curBlock.parent == nil {
412 if !smith.curBlock.extendable || smith.curBlockPos < 0 {
413 if smith.curBlock.subBlock == nil {
414 smith.curBlockPos = len(smith.curBlock.parent.sub) - 2
416 smith.curBlockPos = -2
417 for i, b1 := range smith.curBlock.parent.sub {
418 if b1 == smith.curBlock.subBlock {
419 smith.curBlockPos = i
423 if smith.curBlockPos == -2 {
427 smith.curBlock = smith.curBlock.parent
430 if smith.rnd(3) == 0 {
433 if smith.curBlockPos >= 0 {
434 b := smith.curBlock.sub[smith.curBlockPos]
435 for _, t1 := range b.types {
436 if dependsOn(t, t1) {
443 if smith.curBlock.parent == nil {
444 for i := smith.curPackage; i < NPackages; i++ {
445 if smith.rndBool() || i == NPackages-1 || *singlepkg {
446 if i == smith.curPackage {
447 // emit global var into the current package
448 smith.enterBlock(true)
449 smith.line("var %v = %v", id, smith.rvalue(t))
450 smith.packages[smith.curPackage].toplevVars = append(smith.packages[smith.curPackage].toplevVars, &Var{id: id, typ: t})
453 // emit global var into another package
454 smith.packages[i].undefVars = append(smith.packages[i].undefVars, &Var{id: id, typ: t})
455 smith.packages[smith.curPackage].imports[smith.packages[i].name] = true
456 id = smith.packages[i].name + "." + id
463 smith.line("%v := %v", id, smith.rvalue(t))
464 smith.defineVar(id, t)
469 func (smith *Smith) materializeFunc(rets []*Type) *Func {
470 f := &Func{name: smith.newId("Func"), args: smith.atypeList(TraitGlobal), rets: rets}
472 curBlock0 := smith.curBlock
473 curBlockPos0 := smith.curBlockPos
474 curFunc0 := smith.curFunc
475 exprDepth0 := smith.exprDepth
476 exprCount0 := smith.exprCount
480 smith.curBlock = curBlock0
481 smith.curBlockPos = curBlockPos0
482 smith.curFunc = curFunc0
483 smith.exprDepth = exprDepth0
484 smith.exprCount = exprCount0
487 if smith.rndBool() && !*singlepkg && smith.curPackage != NPackages-1 {
488 for _, r1 := range rets {
489 if dependsOn(r1, nil) {
493 for _, t := range f.args {
494 if dependsOn(t, nil) {
498 // emit global var into another package
501 smith.packages[smith.curPackage+1].undefFuncs = append(smith.packages[smith.curPackage+1].undefFuncs, newF)
502 smith.packages[smith.curPackage].imports[smith.packages[smith.curPackage+1].name] = true
503 f.name = smith.packages[smith.curPackage+1].name + "." + f.name
507 smith.genToplevFunction(smith.curPackage, f)
511 func (smith *Smith) materializeGotoLabel() string {
512 // TODO: move lavel up
513 id := smith.newId("Label")
515 curBlock0 := smith.curBlock
516 curBlockPos0 := smith.curBlockPos
517 curBlockLen0 := len(smith.curBlock.sub)
519 if smith.curBlock == curBlock0 {
520 curBlockPos0 += len(smith.curBlock.sub) - curBlockLen0
522 smith.curBlock = curBlock0
523 smith.curBlockPos = curBlockPos0
527 if smith.curBlock.parent.funcBoundary && smith.curBlockPos <= 0 {
530 if !smith.curBlock.extendable || smith.curBlockPos < 0 {
531 if smith.curBlock.subBlock != nil {
532 // we should have been stopped at func boundary
535 smith.curBlock = smith.curBlock.parent
536 smith.curBlockPos = len(smith.curBlock.sub) - 2
539 if smith.rnd(3) == 0 {
545 smith.line("%v:", id)
549 func (smith *Smith) rnd(n int) int {
550 return smith.rng.Intn(n)
553 func (smith *Smith) rndBool() bool {
554 return smith.rnd(2) == 0
557 func (smith *Smith) choice(ch ...string) string {
558 return ch[smith.rnd(len(ch))]
561 func (smith *Smith) newId(prefix string) string {
562 if prefix[0] < 'A' || prefix[0] > 'Z' {
563 panic("unexported id")
566 return fmt.Sprintf("%v%v", prefix, smith.idSeq)
569 func (smith *Smith) enterBlock(nonextendable bool) {
570 b := &Block{parent: smith.curBlock, extendable: !nonextendable}
571 b.isBreakable = smith.curBlock.isBreakable
572 b.isContinuable = smith.curBlock.isContinuable
573 smith.curBlock.sub = append(smith.curBlock.sub, b)
575 smith.curBlockPos = -1
578 func (smith *Smith) leaveBlock() {
579 for _, b := range smith.curBlock.sub {
580 for _, v := range b.vars {
582 smith.line("_ = %v", v.id)
587 smith.curBlock = smith.curBlock.parent
588 smith.curBlockPos = len(smith.curBlock.sub) - 1