Concise way to do multiple interface conversions in Golang?

I am trying to parse function calls from code using a package go/ast

.

To do this, I first find all the function calls, for example:

ast.Inspect(f, func(n ast.Node) bool {
    switch x := n.(type) {
    case *ast.FuncDecl:
        processFunction(x)
    }
    return true
})

      

And then processFunction () looks like this:

func processFunction(e *ast.FuncDecl) {
    // Save wrapper function name
    f := e.Name.Name

    for _, expression := range e.Body.List {
        logrus.Printf("Current stmt: %#v", expression)
        pkg := expression.(*ast.ExprStmt).X.(*ast.CallExpr).Fun.(*ast.SelectorExpr).X.(*ast.Ident).Name
        fn := expression.(*ast.ExprStmt).X.(*ast.CallExpr).Fun.(*ast.SelectorExpr).Sel.Name
        fcall := fmt.Sprintf("%s.%s", pkg, fn)
        logrus.Printf("Yay. found my function call: ", fcall)
    }

}

      

The problem with this code is that if this particular hierarchy is not found in the AST, the program will panic. I know that we can do interface transformations with

x, ok := x.(type)

      

But, if I do every transformation like this, my code will be huge. Trying to use that in this, of course, fails.

    pkg, ok := expression.(*ast.ExprStmt).X.(*ast.CallExpr).Fun.(*ast.SelectorExpr).X.(*ast.Ident).Name
    if !ok {
        continue
    }

      

Mistake:

./parser.go:41: assignment count mismatch: 2 = 1

      

Is there a concise way to do this series of transformations and also gracefully gracefully if this hierarchy is not found?

+3


source to share


1 answer


I don't know what to say about chain statements. But you can simplify this particular example by extracting the duplicate code into your own function.

func fnSelExpr(s ast.Stmt) (*ast.SelectorExpr, bool) {
    if xs, ok := s.(*ast.ExprStmt); ok {
        if cx, ok := xs.X.(*ast.CallExpr); ok {
            return cx.Fun.(*ast.SelectorExpr)
        }
    }
    return nil, false
}

      



Then you can simplify yours processFunction

as follows.

func processFunction(e *ast.FuncDecl) {
    // Save wrapper function name
    f := e.Name.Name

    for _, expression := range e.Body.List {
        logrus.Printf("Current stmt: %#v", expression)

        sx, ok := fnSelExpr(expression)
        if !ok {
            continue
        }

        var pkg string
        if id, ok := sx.X.(*ast.Ident); ok {
            pkg = id.Name
        }
        fn := sx.Sel.Name

        fcall := fmt.Sprintf("%s.%s", pkg, fn)
        logrus.Printf("Yay. found my function call: ", fcall)
    }
}

      

+1


source







All Articles