package main import ( "fmt" "go/ast" ) func parseStmt(loc string, s ast.Stmt) { switch s := s.(type) { case *ast.CaseClause: parseCaseClause(loc, s) case *ast.DeclStmt: parseDeclStmt(loc, s) case *ast.ExprStmt, *ast.AssignStmt, *ast.ReturnStmt, *ast.BranchStmt: // break, continue, fallthrough, goto, // fmt.Printf("%s/(%T)\n", loc, s) case *ast.IfStmt: parseIfStmt(loc, s) case *ast.RangeStmt: parseRangeStmt(loc, s) case *ast.TypeSwitchStmt: parseTypeSwitchStmt(loc, s) default: fmt.Printf("Unhandled type %T\n", s) } } func parseCaseClause(loc string, s *ast.CaseClause) { loc += "/case" if s.Body == nil { // fmt.Printf("%s/(nil case)\n", loc) return } for _, rs := range s.Body { parseStmt(loc, rs) } } func parseDeclStmt(loc string, s *ast.DeclStmt) { loc += "/decl" switch d := s.Decl.(type) { case *ast.GenDecl: parseGenDecl(loc, d) default: fmt.Printf("DeclStmt: %T\n", d) } } func parseIfStmt(loc string, s *ast.IfStmt) { loc += "/if" // fmt.Println(loc) if s.Body == nil { fmt.Printf("%s/(nil if)\n", loc) } else { thenLoc := loc + "/then" for _, rs := range s.Body.List { parseStmt(thenLoc, rs) } } if s.Else == nil { // fmt.Printf("%s/(nil else)\n", loc) return } else { elseLoc := loc + "/else" for _, rs := range s.Else.(*ast.BlockStmt).List { parseStmt(elseLoc, rs) } } } func parseRangeStmt(loc string, s *ast.RangeStmt) { loc += "/range" // fmt.Println(loc) if s.Body == nil { fmt.Printf("%s/(nil range)\n", loc) return } for _, rs := range s.Body.List { parseStmt(loc, rs) } } func parseTypeSwitchStmt(loc string, s *ast.TypeSwitchStmt) { loc += "/(type)" // fmt.Println(loc) if s.Body == nil { fmt.Printf("%s/(nil body)\n", loc) return } for _, clause := range s.Body.List { body := clause.(*ast.CaseClause).Body if body == nil { // fmt.Printf("%s/empty clause\n", loc) continue } for _, rs := range body { parseStmt(loc, rs) } } }