package service import ( "fmt" "go/ast" "strings" ) var ( inFunctionDepth = 0 ) func incInFunctionDepth() { inFunctionDepth++ } func decInFunctionDepth() { inFunctionDepth-- if inFunctionDepth < 0 { panic(fmt.Sprintf("inFunctionDepth: %v", inFunctionDepth)) } } func IsInFunction() bool { return inFunctionDepth > 0 } func handleFuncDecl(decl ast.Decl) string { incInFunctionDepth() defer decInFunctionDepth() fd := decl.(*ast.FuncDecl) if fd.Recv != nil { return handleMethodDeclaration(fd) } return handleFunctionDeclaration(fd) } func handleFunctionDeclaration(fd *ast.FuncDecl) string { if shouldSkipFunction(fd.Type) { return "" } code := "" name := "" ft := handleFuncDeclType(fd.Type) code += ft code += " " name = handleFuncDeclName(fd.Name) if name == "NewController" { return "" } code += name code += "(" fp := handleFuncDeclParams(fd.Type) code += fp addFunctionDeclaration(ft + " " + name + "(" + fp + ");") code += ") {\n" code += handleBlockStmt(fd.Body) code += "}\n" return code } func shouldSkipFunction(t *ast.FuncType) (res bool) { r := t.Results if r == nil { return } l := r.List if len(l) != 1 { return } p := l[0] if p == nil { return } pt := p.Type if pt == nil { return } i, ok := pt.(*ast.Ident) if !ok { return } if i.Name == "ShouldBeSkipped" { return true } return } func handleFuncDeclType(t *ast.FuncType) string { code := "" if t.Results == nil { return "void" } fl := t.Results if fl.NumFields() == 0 { panic("handleFuncDeclType: fl.NumFields() == 0") } switch ft := fl.List[0].Type.(type) { case *ast.Ident: code += handleIdentExpr(ft) case *ast.StarExpr: code += handleStarExpr(ft) code += "*" } return code } func handleFuncDeclName(ident *ast.Ident) (code string) { if ident == nil { return } code += ident.Name if val, ok := mapping[code]; ok { code = val } return } func handleFuncDeclParams(t *ast.FuncType) string { code := "" if t.Params == nil || t.Params.List == nil { return code } values := make([]string, 0) for _, field := range t.Params.List { ftype := "" star := false switch ft := field.Type.(type) { case *ast.Ident: ftype = handleIdentExpr(ft) case *ast.StarExpr: ftype = handleStarExpr(ft) star = true } for _, names := range field.Names { n := ftype if star { n += "*" } n += " " n += names.Name values = append(values, n) } } code += strings.Join(values, ",") return code } func addFunctionDeclaration(f string) { dlock.Lock() defer dlock.Unlock() funcDeclarations = append(funcDeclarations, f) }