Skip to content

Commit

Permalink
Merge pull request #391 from gucio321/codegen-refactor
Browse files Browse the repository at this point in the history
Codegen refactor and cleanup
  • Loading branch information
gucio321 authored Nov 14, 2024
2 parents 086586f + 06da78f commit ba35a47
Show file tree
Hide file tree
Showing 10 changed files with 890 additions and 1,160 deletions.
9 changes: 6 additions & 3 deletions cmd/codegen/arguments_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,15 +165,18 @@ func getArgWrapper(
pureType = TrimSuffix(pureType, "*")
isPointer = true
}

_, isRefTypedef := context.refTypedefs[pureType]
_, isEnum := context.enumNames[pureType]
_, isRefEnum := context.refEnumNames[pureType]

if goEnumName := pureType; IsEnum(goEnumName, context.enumNames) {
if isEnum || isRefEnum {
srcPkg := context.flags.packageName
if isRefTypedef {
srcPkg = context.flags.refPackageName
}

goType := prefixGoPackage(goEnumName.renameGoIdentifier(context), GoIdentifier(srcPkg), context)
goType := prefixGoPackage(pureType.renameGoIdentifier(context), GoIdentifier(srcPkg), context)

if isPointer {
argDeclaration = fmt.Sprintf("%s *%s", a.Name, goType)
Expand Down Expand Up @@ -298,7 +301,7 @@ for i, %[1]sV := range %[1]sArg {
}

_, shouldSkipRefTypedef := context.preset.SkipTypedefs[pureType]
if context.structNames[pureType] || context.typedefsNames[pureType] || (isRefTypedef && !shouldSkipRefTypedef) {
if context.typedefsNames[pureType] || (isRefTypedef && !shouldSkipRefTypedef) {
srcPkg := context.flags.packageName
if isRefTypedef {
srcPkg = context.flags.refPackageName
Expand Down
7 changes: 1 addition & 6 deletions cmd/codegen/gengo.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,7 @@ func IsCallbackTypedef(s string) bool {
}

func IsStructName(name CIdentifier, ctx *Context) bool {
_, ok := ctx.structNames[name]
return ok
}

func IsEnum(name CIdentifier, enums map[CIdentifier]bool) bool {
_, ok := enums[name]
_, ok := ctx.typedefsNames[name]
return ok
}

Expand Down
10 changes: 5 additions & 5 deletions cmd/codegen/gengo_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func GenerateGoFuncs(
) error {
generator := &goFuncsGenerator{
prefix: context.prefix,
structNames: context.typedefsNames,
typedefsNames: context.typedefsNames,
enumNames: context.enumNames,
refTypedefs: context.refTypedefs,
context: context,
Expand Down Expand Up @@ -101,7 +101,7 @@ func GenerateGoFuncs(
// goFuncsGenerator is an internal state of GO funcs' generator
type goFuncsGenerator struct {
prefix string
structNames map[CIdentifier]bool
typedefsNames map[CIdentifier]bool
enumNames map[CIdentifier]bool
refTypedefs map[CIdentifier]bool

Expand Down Expand Up @@ -150,9 +150,9 @@ func (g *goFuncsGenerator) GenerateFunction(f FuncDef, args []GoIdentifier, argW
} else {
returnTypeType = returnTypeVoid
}
} else if HasSuffix(f.Ret, "*") && (g.structNames[TrimSuffix(f.Ret, "*")] || g.structNames[TrimSuffix(TrimPrefix(f.Ret, "const "), "*")]) {
} else if HasSuffix(f.Ret, "*") && (g.typedefsNames[TrimSuffix(f.Ret, "*")] || g.typedefsNames[TrimSuffix(TrimPrefix(f.Ret, "const "), "*")]) {
returnTypeType = returnTypeStructPtr
} else if f.StructGetter && g.structNames[f.Ret] {
} else if f.StructGetter && g.typedefsNames[f.Ret] {
returnTypeType = returnTypeStruct
} else if f.Constructor {
returnTypeType = returnTypeConstructor
Expand Down Expand Up @@ -366,7 +366,7 @@ func (g *goFuncsGenerator) generateFuncArgs(f FuncDef) (args []GoIdentifier, arg
decl, wrapper, err := getArgWrapper(
&a,
i == 0 && f.StructSetter,
f.StructGetter && g.structNames[a.Type],
f.StructGetter && g.typedefsNames[a.Type],
g.context,
)
if err != nil {
Expand Down
4 changes: 3 additions & 1 deletion cmd/codegen/gengo_typedefs.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ func GenerateTypedefs(
continue
}

if IsEnum(k, ctx.enumNames) /*|| IsStructName(k, structs)*/ {
_, isEnum := ctx.enumNames[k]
_, isRefEnum := ctx.refEnumNames[k]
if isEnum || isRefEnum {
if ctx.flags.showGenerated {
glg.Infof("typedef %s has extended deffinition in structs_and_enums.json. Will generate later", k)
}
Expand Down
24 changes: 14 additions & 10 deletions cmd/codegen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const (
)

// this cextracts enums and structs names from json file.
func getEnumAndStructNames(enumJsonBytes []byte, context *Context) (enumNames []EnumIdentifier, structNames []CIdentifier, err error) {
func getEnumAndStructNames(enumJsonBytes []byte, context *Context) (enumNames []EnumIdentifier, typedefsNames []CIdentifier, err error) {
enums, err := getEnumDefs(enumJsonBytes)
if err != nil {
return nil, nil, fmt.Errorf("cannot get enum definitions: %w", err)
Expand All @@ -34,7 +34,7 @@ func getEnumAndStructNames(enumJsonBytes []byte, context *Context) (enumNames []

for _, s := range structs {
if shouldSkipStruct := context.preset.SkipStructs[s.Name]; !shouldSkipStruct {
structNames = append(structNames, s.Name)
typedefsNames = append(typedefsNames, s.Name)
}
}

Expand Down Expand Up @@ -116,20 +116,24 @@ func loadData(f *flags) (*jsonData, error) {

// this will store json data processed by appropiate pre-rocessors
type Context struct {
// prefix for generated files (prefix_fileType.go)
prefix string

// plain idata loaded from json
funcs []FuncDef
structs []StructDef
enums []EnumDef
typedefs *Typedefs

prefix string

funcNames map[CIdentifier]bool
// ghese fields are filled by parser while it generates code.
enumNames map[CIdentifier]bool
structNames map[CIdentifier]bool
typedefsNames map[CIdentifier]bool

// contains helper C functions to get/set struct fields
// of array types
arrayIndexGetters map[CIdentifier]CIdentifier

// contains identifiers from other package (usually imgui).
refStructNames map[CIdentifier]bool
refEnumNames map[CIdentifier]bool
refTypedefs map[CIdentifier]bool
Expand Down Expand Up @@ -184,7 +188,7 @@ func parseJson(jsonData *jsonData) (*Context, error) {
}

_, structs, err := getEnumAndStructNames(jsonData.structAndEnums, result)
result.structNames = SliceToMap(structs)
result.typedefsNames = SliceToMap(structs)
if err != nil {
return nil, fmt.Errorf("cannot get reference struct and enums names: %w", err)
}
Expand Down Expand Up @@ -232,15 +236,15 @@ func main() {
glg.Fatalf("Generating enum names: %v", err)
}

context.enumNames = MergeMaps(SliceToMap(enumNames), context.refEnumNames)
context.enumNames = SliceToMap(enumNames)

// 1.2. Generate Go typedefs
callbacks, err := GenerateTypedefs(context.typedefs, context.structs, context)
typedefsNames, err := GenerateTypedefs(context.typedefs, context.structs, context)
if err != nil {
log.Panic(err)
}

context.structNames = SliceToMap(callbacks)
context.typedefsNames = SliceToMap(typedefsNames)

// 1.3. Generate C wrapper
validFuncs, err := generateCppWrapper(flags.prefix, flags.include, context.funcs, context)
Expand Down
39 changes: 21 additions & 18 deletions cmd/codegen/return_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,16 @@ func getReturnWrapper(
"void*": simpleR("unsafe.Pointer", "unsafe.Pointer"),
}

isPointer := HasSuffix(t, "*")
pureType := TrimPrefix(TrimSuffix(t, "*"), "const ")
// check if pureType is a declared type (struct or something else from typedefs)
_, isRefStruct := context.refStructNames[pureType]
_, isRefTypedef := context.refTypedefs[pureType]
_, isEnum := context.enumNames[pureType]
_, isRefEnum := context.refEnumNames[pureType]
_, shouldSkipRefTypedef := context.preset.SkipTypedefs[pureType]
_, isStruct := context.structNames[pureType]
isStruct = isStruct || ((isRefStruct || (isRefTypedef && !IsEnum(pureType, context.refEnumNames))) && !shouldSkipRefTypedef)
_, isStruct := context.typedefsNames[pureType]
isStruct = isStruct || ((isRefStruct || (isRefTypedef && !isRefEnum)) && !shouldSkipRefTypedef)
w, known := returnWrapperMap[t]
// check if is array (match regex)
isArray, err := regexp.Match(".*\\[\\d+\\]", []byte(t))
Expand All @@ -96,25 +99,32 @@ func getReturnWrapper(

_, shouldSkipStruct := context.preset.SkipStructs[pureType]

pureType = TrimPrefix(t, "const ")
switch {
case known:
return w, nil
// case (context.structNames[t] || context.refStructNames[t]) && !shouldSkipStruct(t):
case !HasSuffix(t, "*") && isStruct && !shouldSkipStruct:
// case (context.typedefsNames[t] || context.refStructNames[t]) && !shouldSkipStruct(t):
case !isPointer && isStruct && !shouldSkipStruct:
return returnWrapper{
returnType: prefixGoPackage(pureType.renameGoIdentifier(context), srcPackage, context),
// this is a small trick as using prefixGoPackage isn't in fact intended to be used in such a way, but it should treat the whole string as a "type" and prefix it correctly
returnStmt: string(prefixGoPackage(GoIdentifier(fmt.Sprintf("*New%sFromC(func() *C.%s {result := %%s; return &result}())", pureType.renameGoIdentifier(context), pureType)), srcPackage, context)),
CType: GoIdentifier(fmt.Sprintf("C.%s", pureType)),
}, nil
case IsEnum(t, context.enumNames):
case isEnum || isRefEnum:
goType := prefixGoPackage(pureType.renameGoIdentifier(context), srcPackage, context)
return returnWrapper{
returnType: goType,
returnStmt: fmt.Sprintf("%s(%%s)", goType),
CType: GoIdentifier(fmt.Sprintf("C.%s", pureType)),
}, nil
if isPointer {
return returnWrapper{
returnType: "*" + goType,
returnStmt: fmt.Sprintf("(*%s)(%%s)", goType),
CType: GoIdentifier(fmt.Sprintf("*C.%s", TrimSuffix(pureType, "*"))),
}, nil
} else {
return returnWrapper{
returnType: goType,
returnStmt: fmt.Sprintf("%s(%%s)", goType),
CType: GoIdentifier(fmt.Sprintf("C.%s", pureType)),
}, nil
}
case HasPrefix(t, "ImVector_") &&
!(HasSuffix(t, "*") || HasSuffix(t, "]")):
pureType := CIdentifier(TrimPrefix(t, "ImVector_") + "*")
Expand All @@ -133,13 +143,6 @@ func getReturnWrapper(
returnStmt: fmt.Sprintf("vectors.NewVectorFromC(%%[1]s.Size, %%[1]s.Capacity, %s)", fmt.Sprintf(rw.returnStmt, "%[1]s.Data")),
CType: GoIdentifier(fmt.Sprintf("*C.%s", pureType)),
}, nil
case HasSuffix(t, "*") && IsEnum(TrimSuffix(t, "*"), context.enumNames):
goType := prefixGoPackage("*"+TrimSuffix(pureType, "*").renameGoIdentifier(context), srcPackage, context)
return returnWrapper{
returnType: goType,
returnStmt: fmt.Sprintf("(%s)(%%s)", goType),
CType: GoIdentifier(fmt.Sprintf("*C.%s", TrimSuffix(pureType, "*"))),
}, nil
case HasSuffix(t, "*") && isStruct && !shouldSkipStruct:
goType := prefixGoPackage("*"+TrimSuffix(pureType, "*").renameGoIdentifier(context), srcPackage, context)
return returnWrapper{
Expand Down
Loading

0 comments on commit ba35a47

Please sign in to comment.