Skip to content

Instantly share code, notes, and snippets.

@josharian
Created January 26, 2018 23:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save josharian/2e8e8ba23a99317820291b30b47a64fb to your computer and use it in GitHub Desktop.
Save josharian/2e8e8ba23a99317820291b30b47a64fb to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"flag"
"fmt"
"os"
"strings"
"github.com/go-clang/v3.9/clang"
)
var fname = flag.String("fname", "", "the file to analyze")
func main() {
flag.Parse()
if *fname == "" {
flag.Usage()
fmt.Printf("please provide a file name to analyze\n")
os.Exit(1)
}
idx := clang.NewIndex(0, 1)
defer idx.Dispose()
tu := idx.ParseTranslationUnit(*fname, []string{"-DDOCURIUM=1"}, nil, 0)
defer tu.Dispose()
diagnostics := tu.Diagnostics()
for _, d := range diagnostics {
fmt.Println("PROBLEM:", d.Spelling())
}
if len(diagnostics) > 0 {
os.Exit(1)
}
cursor := tu.TranslationUnitCursor()
var enums []string
var comments [][]string
cursor.Visit(func(cursor, parent clang.Cursor) clang.ChildVisitResult {
if cursor.IsNull() {
return clang.ChildVisit_Continue
}
file, _, _, _ := cursor.Location().FileLocation()
if file.Name() != *fname {
return clang.ChildVisit_Continue
}
switch cursor.Kind() {
case clang.Cursor_EnumDecl:
cursor.Visit(func(innercursor, innerparent clang.Cursor) clang.ChildVisitResult {
if innercursor.Kind() != clang.Cursor_EnumConstantDecl {
return clang.ChildVisit_Continue
}
enums = append(enums, innercursor.Spelling())
pc := innercursor.ParsedComment()
var lines []string
for i := uint32(0); i < pc.NumChildren(); i++ {
c := pc.Child(i)
if c.Kind() != clang.Comment_Paragraph {
panic("unexpected comment kind")
}
for j := uint32(0); j < c.NumChildren(); j++ {
line := c.Child(j)
if line.Kind() != clang.Comment_Text {
panic(fmt.Sprintf("unexpected inner comment kind %v", line.Kind().Spelling()))
}
lines = append(lines, line.TextComment_getText())
}
lines = append(lines, "\n")
}
if len(lines) > 0 && lines[len(lines)-1] == "\n" {
lines = lines[:len(lines)-1]
}
comments = append(comments, lines)
return clang.ChildVisit_Recurse
})
case clang.Cursor_TypedefDecl:
if len(enums) > 0 {
ctyp := cursor.Spelling()
special, isspecial := ctype2go[ctyp] // handle exceptions
var typ string
if isspecial {
typ = special.gotype
} else {
typ = ctyp
typ = strings.TrimPrefix(typ, "git_")
typ = strings.TrimSuffix(typ, "_t")
typ = toCamel(typ)
}
fmt.Printf("const (\n")
for i := range enums {
for _, line := range comments[i] {
fmt.Printf("\t//%s\n", line)
}
enum := toCamel(strings.TrimPrefix(enums[i], "GIT_"))
if isspecial {
enum = special.addPrefix + strings.TrimPrefix(enum, special.stripPrefix)
}
fmt.Printf("\t%s %s = C.%s\n", enum, typ, enums[i])
if i != len(enums)-1 {
fmt.Println()
}
}
fmt.Printf(")\n\n\n")
}
enums = nil
comments = nil
}
return clang.ChildVisit_Continue
})
if len(diagnostics) > 0 {
fmt.Println("NOTE: There were problems while analyzing the given file")
os.Exit(1)
}
}
var ctype2go = map[string]struct {
gotype string
stripPrefix string
addPrefix string
}{
"git_merge_flag_t": {"MergeTreeFlag", "Merge", "MergeTree"},
}
func toCamel(s string) string {
words := strings.Split(s, "_")
var camel [][]byte
for _, word := range words {
if len(word) == 0 {
camel = append(camel, []byte(""))
}
w := []byte(word)
w = bytes.ToLower(w)
w[0] = bytes.ToUpper(w[:1])[0]
camel = append(camel, w)
}
return string(bytes.Join(camel, nil))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment