Skip to content

Instantly share code, notes, and snippets.

@josharian
Created January 26, 2018 23:47
Show Gist options
  • Save josharian/54b2268af5792ff0e62f06437f28a8c9 to your computer and use it in GitHub Desktop.
Save josharian/54b2268af5792ff0e62f06437f28a8c9 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("type %s int\n\n", 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"},
}
var caseCleanup = strings.NewReplacer("Fastforward", "FastForward")
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)
}
s = string(bytes.Join(camel, nil))
return caseCleanup.Replace(s)
}
$ go run gen_git2go_enum.go -fname vendor/libgit2/include/git2/merge.h
type MergeTreeFlag int
const (
// Detect renames that occur between the common ancestor and the "ours"
// side or the common ancestor and the "theirs" side. This will enable
// the ability to merge between a modified and renamed file.
MergeTreeFindRenames MergeTreeFlag = C.GIT_MERGE_FIND_RENAMES
// If a conflict occurs, exit immediately instead of attempting to
// continue resolving conflicts. The merge operation will fail with
// GIT_EMERGECONFLICT and no index will be returned.
MergeTreeFailOnConflict MergeTreeFlag = C.GIT_MERGE_FAIL_ON_CONFLICT
// Do not write the REUC extension on the generated index
MergeTreeSkipReuc MergeTreeFlag = C.GIT_MERGE_SKIP_REUC
// If the commits being merged have multiple merge bases, do not build
// a recursive merge base (by merging the multiple merge bases),
// instead simply use the first base. This flag provides a similar
// merge base to `git-merge-resolve`.
MergeTreeNoRecursive MergeTreeFlag = C.GIT_MERGE_NO_RECURSIVE
)
type MergeFileFavor int
const (
// When a region of a file is changed in both branches, a conflict
// will be recorded in the index so that `git_checkout` can produce
// a merge file with conflict markers in the working directory.
// This is the default.
MergeFileFavorNormal MergeFileFavor = C.GIT_MERGE_FILE_FAVOR_NORMAL
// When a region of a file is changed in both branches, the file
// created in the index will contain the "ours" side of any conflicting
// region. The index will not record a conflict.
MergeFileFavorOurs MergeFileFavor = C.GIT_MERGE_FILE_FAVOR_OURS
// When a region of a file is changed in both branches, the file
// created in the index will contain the "theirs" side of any conflicting
// region. The index will not record a conflict.
MergeFileFavorTheirs MergeFileFavor = C.GIT_MERGE_FILE_FAVOR_THEIRS
// When a region of a file is changed in both branches, the file
// created in the index will contain each unique line from each side,
// which has the result of combining both files. The index will not
// record a conflict.
MergeFileFavorUnion MergeFileFavor = C.GIT_MERGE_FILE_FAVOR_UNION
)
type MergeFileFlag int
const (
// Defaults
MergeFileDefault MergeFileFlag = C.GIT_MERGE_FILE_DEFAULT
// Create standard conflicted merge files
MergeFileStyleMerge MergeFileFlag = C.GIT_MERGE_FILE_STYLE_MERGE
// Create diff3-style files
MergeFileStyleDiff3 MergeFileFlag = C.GIT_MERGE_FILE_STYLE_DIFF3
// Condense non-alphanumeric regions for simplified diff file
MergeFileSimplifyAlnum MergeFileFlag = C.GIT_MERGE_FILE_SIMPLIFY_ALNUM
// Ignore all whitespace
MergeFileIgnoreWhitespace MergeFileFlag = C.GIT_MERGE_FILE_IGNORE_WHITESPACE
// Ignore changes in amount of whitespace
MergeFileIgnoreWhitespaceChange MergeFileFlag = C.GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE
// Ignore whitespace at end of line
MergeFileIgnoreWhitespaceEol MergeFileFlag = C.GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL
// Use the "patience diff" algorithm
MergeFileDiffPatience MergeFileFlag = C.GIT_MERGE_FILE_DIFF_PATIENCE
// Take extra time to find minimal diff
MergeFileDiffMinimal MergeFileFlag = C.GIT_MERGE_FILE_DIFF_MINIMAL
)
type MergeAnalysis int
const (
// No merge is possible. (Unused.)
MergeAnalysisNone MergeAnalysis = C.GIT_MERGE_ANALYSIS_NONE
// A "normal" merge; both HEAD and the given merge input have diverged
// from their common ancestor. The divergent commits must be merged.
MergeAnalysisNormal MergeAnalysis = C.GIT_MERGE_ANALYSIS_NORMAL
// All given merge inputs are reachable from HEAD, meaning the
// repository is up-to-date and no merge needs to be performed.
MergeAnalysisUpToDate MergeAnalysis = C.GIT_MERGE_ANALYSIS_UP_TO_DATE
// The given merge input is a fast-forward from HEAD and no merge
// needs to be performed. Instead, the client can check out the
// given merge input.
MergeAnalysisFastForward MergeAnalysis = C.GIT_MERGE_ANALYSIS_FASTFORWARD
// The HEAD of the current repository is "unborn" and does not point to
// a valid commit. No merge can be performed, but the caller may wish
// to simply set HEAD to the target commit(s).
MergeAnalysisUnborn MergeAnalysis = C.GIT_MERGE_ANALYSIS_UNBORN
)
type MergePreference int
const (
// No configuration was found that suggests a preferred behavior for
// merge.
MergePreferenceNone MergePreference = C.GIT_MERGE_PREFERENCE_NONE
// There is a `merge.ff=false` configuration setting, suggesting that
// the user does not want to allow a fast-forward merge.
MergePreferenceNoFastForward MergePreference = C.GIT_MERGE_PREFERENCE_NO_FASTFORWARD
// There is a `merge.ff=only` configuration setting, suggesting that
// the user only wants fast-forward merges.
MergePreferenceFastForwardOnly MergePreference = C.GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment