func grindFunc(ctxt *grinder.Context, pkg *grinder.Package, edit *grinder.EditBuffer, fn *ast.FuncDecl) { if fn.Body == nil { return } blocks := block.Build(pkg.FileSet, fn.Body) ast.Inspect(fn.Body, func(x ast.Node) bool { var list []ast.Stmt switch x := x.(type) { default: return true case *ast.BlockStmt: list = x.List case *ast.CommClause: list = x.Body case *ast.CaseClause: list = x.Body } for i := 0; i < len(list); i++ { x := list[i] if grinder.IsTerminatingStmt(blocks, x) { end := i + 1 for end < len(list) && !isGotoTarget(blocks, list[end]) { end++ } if end > i+1 { edit.Delete(edit.End(x), edit.End(list[end-1])) i = end - 1 // after i++, next iteration starts at end } } } return true }) }
func placeInit(edit *grinder.EditBuffer, start token.Pos, obj *ast.Object, decl *ast.DeclStmt, list []ast.Stmt) ast.Node { declPos := -1 i := 0 for i < len(list) && edit.End(list[i]) < start { if unlabel(list[i]) == decl { declPos = i } i++ } if i >= len(list) { panic(fmt.Sprintf("unexpected start position")) } switch x := unlabel(list[i]).(type) { case *ast.AssignStmt: if canDeclare(x, obj) { return x } } if declPos >= 0 && allSimple(list[declPos:i]) { return decl } for j := i + 1; j < len(list); j++ { if unlabel(list[j]) == decl { if allSimple(list[i:j]) { return decl } break } } x := list[i] for { xx, ok := x.(*ast.LabeledStmt) if !ok || xx.Stmt.Pos() > start { break } x = xx.Stmt } return &ast.EmptyStmt{ Semicolon: x.Pos(), } }
func findTargetBlock(pkg *grinder.Package, edit *grinder.EditBuffer, fn *ast.FuncDecl, blocks *block.Graph, labelname string) (target targetBlock, ok bool) { if debug { println("FINDTARGET", labelname) } lstmt := blocks.Label[labelname] if lstmt == nil { return } list := grinder.BlockList(blocks.Map[lstmt].Root) if list == nil { return } ulstmt := grinder.Unlabel(lstmt) for i := 0; i < len(list); i++ { if grinder.Unlabel(list[i]) == ulstmt { // Found statement. Find extent of block. if debug { println("FOUND") } end := i for ; ; end++ { if end >= len(list) { if debug { println("EARLY END") } // List ended without terminating statement. // Unless this is the top-most block, we can't hoist this code. if blocks.Map[lstmt].Root != fn.Body { return } // Top-most block. Implicit return at end of list. target.needReturn = true break } if end > i && grinder.IsGotoTarget(blocks, list[end]) { if debug { println("FOUND TARGET") } target.needGoto = list[end].(*ast.LabeledStmt).Label.Name break } if grinder.IsTerminatingStmt(blocks, list[end]) { if debug { println("TERMINATING") } end++ break } } if end <= i { if debug { println("NOTHING") } return } if debug { println("OK") } target.dead = i > 0 && grinder.IsTerminatingStmt(blocks, list[i-1]) target.start = lstmt.Pos() target.comment = edit.BeforeComments(target.start) target.endLabel = lstmt.Colon + 1 target.end = edit.End(list[end-1]) target.code = strings.TrimSpace(edit.TextAt(lstmt.Colon+1, target.end)) target.short = end == i+1 && (isReturn(grinder.Unlabel(list[i])) || isEmpty(grinder.Unlabel(list[i])) && target.needReturn) target.objs = gatherObjs(pkg, fn, lstmt.Pos(), list[i:end]) return target, true } } return }