Example #1
0
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
	})
}
Example #2
0
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(),
	}
}
Example #3
0
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
}