Skip to content

Instantly share code, notes, and snippets.

@paralin
Last active February 15, 2023 09:59
Show Gist options
  • Select an option

  • Save paralin/5fda551c7740592869dc0f0b54c18d6f to your computer and use it in GitHub Desktop.

Select an option

Save paralin/5fda551c7740592869dc0f0b54c18d6f to your computer and use it in GitHub Desktop.
ChatGPT is kind of crazy
// Written by ChatGPT w/ prompts from @paralin
package main
import (
"bytes"
"flag"
"fmt"
"go/ast"
"go/format"
"go/parser"
"go/token"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
)
func main() {
// Define command-line flags
dirFlag := flag.String("dir", ".", "Directory containing the Git repository")
flag.Parse()
// Get the list of tracked files within the repository
cmd := exec.Command("git", "ls-files")
cmd.Dir = *dirFlag
output, err := cmd.Output()
if err != nil {
log.Fatal(err)
}
trackedFiles := strings.Split(string(output), "\n")
// Filter only the .go files
goFiles := make([]string, 0)
for _, file := range trackedFiles {
if filepath.Ext(file) == ".go" {
goFiles = append(goFiles, filepath.Join(*dirFlag, file))
}
}
// Process each Go file
for _, file := range goFiles {
if strings.HasSuffix(file, ".pb.go") || strings.HasSuffix(file, ".srpc.go") {
continue
}
fmt.Printf("Processing file: %s\n", file)
if err := refactorFile(file); err != nil {
log.Printf("Failed to refactor file %s: %v", file, err)
}
}
}
func refactorFile(filename string) error {
// Parse the Go file
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
if err != nil {
return err
}
// Process each function declaration in the file
for _, decl := range f.Decls {
funcDecl, ok := decl.(*ast.FuncDecl)
if !ok {
continue
}
if funcDecl.Recv != nil ||
funcDecl.Type == nil ||
funcDecl.Type.Params == nil ||
funcDecl.Type.Results == nil ||
len(funcDecl.Type.Params.List) != 1 ||
len(funcDecl.Type.Results.List) != 2 {
// Not a valid UnmarshalFoo function declaration
continue
}
if _, ok := funcDecl.Type.Params.List[0].Type.(*ast.StarExpr); !ok {
continue
}
// Get the type name from the function name
funcName := funcDecl.Name.Name
if !strings.HasPrefix(funcName, "Unmarshal") {
continue
}
typeName := funcName[len("Unmarshal"):]
// Check if the function already exists
newFuncName := "New" + typeName + "Block"
newFuncExists := false
for _, decl := range f.Decls {
if funcDecl, ok := decl.(*ast.FuncDecl); ok {
if funcDecl.Name.Name == newFuncName {
newFuncExists = true
break
}
}
}
// Generate the new code
var buf bytes.Buffer
buf.WriteString("package gen\n\n")
buf.WriteString(fmt.Sprintf("func %s(bcs *block.Cursor) (*%s, error) {\n", funcName, typeName))
buf.WriteString(fmt.Sprintf("\treturn block.UnmarshalBlock[*%s](bcs, %s)\n", typeName, newFuncName))
buf.WriteString("}\n")
if !newFuncExists {
buf.WriteString(fmt.Sprintf("func %s() block.Block {\n", newFuncName))
buf.WriteString(fmt.Sprintf("\treturn &%s{}\n", typeName))
buf.WriteString("}\n\n")
}
// Replace the old code with the new code
funcDecl.Body.List = nil
funcDecl.Body.Rbrace = 0
stmt, err := parser.ParseFile(fset, "", &buf, parser.ParseComments)
if err != nil {
return err
}
newFuncDecl := stmt.Decls[0].(*ast.FuncDecl)
funcDecl.Body.List = newFuncDecl.Body.List
if !newFuncExists {
f.Decls = append(f.Decls, stmt.Decls[1])
}
}
// Write the modified Go file
fh, err := os.Create(filename)
if err != nil {
return err
}
defer fh.Close()
if err := format.Node(fh, fset, f); err != nil {
return err
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment