Beispiel #1
0
func rewriteFnWithRecovers(body *ast.BlockStmt, fnType *ast.FuncType) (wrapped *ast.FuncLit) {
	// The formatting of the channel declaration is ugly, but it's presented this way here to show how it will look in the actual output.
	// As far as I know, I would need to set the token.Pos values for the left and right braces of the struct and interface type literals
	// in order to get them on one line, but I don't think I can do that without computing all of the other token.Pos values for everything
	// else I generate.
	// TODO: These identifiers will probably conflict if there is a nested function that also has unnamed outputs. Should probably make a better gensym.
	outputDecls, outputs := inputsOrOutputs(fnType.Results, idents.result)
	if len(outputs) > 0 {
		body.List = astPrintf(`%s = func() (%s) {%s}()`, outputs, fnType.Results, body.List)
	}
	body.List = astPrintf(`
		{{%s}}
		_r := make(chan chan interface {
		})
		recovers, panicChan := godebug.EnterFuncWithRecovers(_r, func(ctx *godebug.Context) {
			%s
		})
		for recoverChan := range recovers {
			recoverChan <- recover()
		}
		if panicVal, ok := <-panicChan; ok {
			panic(panicVal)
		}
		{{return %s}}`, outputDecls, body.List, outputs)
	body.Rbrace = token.NoPos // without this I was getting extra whitespace at the end of the function
	return wrapped
}
Beispiel #2
0
func (v *visitor) finalizeLoop(pos token.Pos, body *ast.BlockStmt) {
	if body == nil {
		return
	}
	line := pos2line(pos)
	if len(v.newIdents) == 0 {
		call := newCall(idents.godebug, "Line", ast.NewIdent(idents.ctx), ast.NewIdent(v.scopeVar), newInt(line))
		body.List = append(body.List, &ast.ExprStmt{X: call})
	} else {
		body.List = append([]ast.Stmt{
			astPrintf(`godebug.Line(ctx, scope, %s)`, strconv.Itoa(line))[0],
			newDeclareCall(idents.scope, v.newIdents),
		}, body.List...)
	}
}
Beispiel #3
0
func (p *parser) parseBlock(n *parse.Node, scope *ast.Scope) *ast.BlockStmt {
	block := ast.BlockStmt{
		Lbrace: token.Pos(n.Child(0).Pos()),
		Rbrace: token.Pos(n.LastChild().Pos()),
	}
	eachListItem(stmt, n.Child(1), func(item *parse.Node) {
		block.List = append(block.List, p.parseStmt(item))
	})
	return &block
}
Beispiel #4
0
// filterBlocks keeps the statements that are need to calculate MappedCells.
func filterBlock(blk *ast.BlockStmt, filterIDs map[string]bool,
	imports map[string]string) (*ast.BlockStmt, []dictKey) {

	dicts := dictionaries(blk, imports)

	usedDks := make(map[dictKey]bool)
	filtered := make([]ast.Stmt, 0, len(blk.List))
	for i := len(blk.List) - 1; i >= 0; i-- {
		switch s := blk.List[i].(type) {
		// TODO(soheil): Support switches.
		case *ast.SwitchStmt:
		// TODO(soheil): Add support for ifs.
		case *ast.IfStmt:
		default:
			// TODO(soheil): It's actually more complicated that. What about
			// functional calls, what about multiple return values, ...?
			dks, yes := accessesDict(s, dicts)
			if yes {
				for _, dk := range dks {
					filterIDs[dk.k] = true
					usedDks[dk] = true
				}
				continue
			}

			dirty := false
			rIDs, wIDs := ids(s)
			for _, id := range wIDs {
				if filterIDs[id] {
					dirty = true
					break
				}
			}

			if !dirty {
				continue
			}

			for _, id := range rIDs {
				filterIDs[id] = true
			}

			filtered = append([]ast.Stmt{s}, filtered...)
		}
	}

	blk.List = filtered

	keys := make([]dictKey, 0, len(usedDks))
	for dk, _ := range usedDks {
		keys = append(keys, dk)
	}
	return blk, keys
}
/*
 * Given a test func named TestDoesSomethingNeat, rewrites it as
 * It("does something neat", func() { __test_body_here__ }) and adds it
 * to the Describe's list of statements
 */
func rewriteTestFuncAsItStatement(testFunc *ast.FuncDecl, rootNode *ast.File, describe *ast.CallExpr) {
	var funcIndex int = -1
	for index, child := range rootNode.Decls {
		if child == testFunc {
			funcIndex = index
			break
		}
	}

	if funcIndex < 0 {
		panic(fmt.Sprintf("Assert failed: Error finding index for test node %s\n", testFunc.Name.Name))
	}

	var block *ast.BlockStmt = blockStatementFromDescribe(describe)
	block.List = append(block.List, createItStatementForTestFunc(testFunc))
	replaceTestingTsWithGinkgoT(block, namedTestingTArg(testFunc))

	// remove the old test func from the root node's declarations
	rootNode.Decls = append(rootNode.Decls[:funcIndex], rootNode.Decls[funcIndex+1:]...)
	return
}
Beispiel #6
0
func rewriteStructLiteralAsIdentifierAtTopOfBlock(newFile *ast.File, literalToReplace *ast.CompositeLit, name string) {
	var (
		foundStmtNode           ast.Stmt
		blocksSeen              []*ast.BlockStmt
		stmtsSeen               []ast.Stmt
		deleteOriginalStatement bool
		newAssignStmtToken      = token.DEFINE
	)

	ast.Inspect(newFile, func(node ast.Node) bool {
		switch node := node.(type) {
		case *ast.BlockStmt:
			if foundStmtNode == nil {
				blocksSeen = append(blocksSeen, node)
			}

		case ast.Stmt:
			stmtsSeen = append(stmtsSeen, node)
		}
		return true
	})

	var block *ast.BlockStmt
	var insertionIndex int

	for i := len(blocksSeen) - 1; i >= 0; i-- {
		b := blocksSeen[i]
		for j, stmt := range b.List {
			ast.Inspect(stmt, func(parentNode ast.Node) bool {
				switch parentNode := parentNode.(type) {
				case *ast.CompositeLit:
					if parentNode == literalToReplace {
						block = b
						insertionIndex = j
						return false
					}
				}
				return true
			})
		}
	}

	for i := len(stmtsSeen) - 1; i >= 0; i-- {
		s := stmtsSeen[i]
		ast.Inspect(s, func(node ast.Node) bool {
			switch node := node.(type) {
			case *ast.CompositeLit:
				if node == literalToReplace {
					foundStmtNode = s
					return false
				}
			}
			return true
		})
	}

	switch foundStmtNode := foundStmtNode.(type) {
	case *ast.AssignStmt:
		expr := foundStmtNode.Rhs[0]
		if expr == literalToReplace {
			deleteOriginalStatement = true

			switch ident := foundStmtNode.Lhs[0].(type) {
			case *ast.Ident:
				name = ident.Name
			}

			if foundStmtNode.Tok == token.ASSIGN {
				newAssignStmtToken = token.ASSIGN
			}
		}
	}

	lhsExpr := []ast.Expr{ast.NewIdent(name)}
	rhsExpr := []ast.Expr{&ast.CompositeLit{Type: literalToReplace.Type}}

	block.List = insert(block.List, insertionIndex, ast.AssignStmt{
		Lhs: lhsExpr,
		Rhs: rhsExpr,
		Tok: newAssignStmtToken,
	})
	insertionIndex++

	for _, elt := range literalToReplace.Elts {
		keyVal := elt.(*ast.KeyValueExpr)
		fieldName := keyVal.Key.(*ast.Ident)

		selector := &ast.SelectorExpr{
			X:   ast.NewIdent(name),
			Sel: ast.NewIdent(fieldName.Name),
		}
		innerLhs := []ast.Expr{selector}
		innerRhs := []ast.Expr{keyVal.Value}

		block.List = insert(block.List, insertionIndex, ast.AssignStmt{
			Lhs: innerLhs,
			Rhs: innerRhs,
			Tok: token.ASSIGN,
		})

		insertionIndex++
	}

	if deleteOriginalStatement {
		copy(block.List[insertionIndex:], block.List[insertionIndex+1:])
		block.List[len(block.List)-1] = &ast.EmptyStmt{}
		block.List = block.List[:len(block.List)-1]
	} else {
		replaceStructLiteralWithIdentifier(foundStmtNode, literalToReplace, name)
	}
}