This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch main
in repository ego.

View the commit online.

commit 9f8f18373ad2b4b5d23d57c8f2919549a01badbb
Author: [email protected] <[email protected]>
AuthorDate: Mon Mar 9 15:39:57 2026 -0600

    feat: add property, method, and event generation to class template
    
    The code generator now emits complete Go bindings for EFL classes:
    
    - Properties: Generates typed getter/setter methods that marshal values
      between Go and C, handling strings, booleans, pointers, and numeric types
    - Methods: Generates wrapper methods that call C functions with proper type
      conversion and return value handling for all parameter/return types
    - Events: Registers typed callbacks using efl.RegisterCallback with
      PayloadGoType handling for multiple data types
    
    Added template helper functions (stripPointerSuffix, isBoolType) and
    supporting code in typemap.go to power the type conversions. Updated
    test fixtures to verify extern declarations, callback registration,
    and return type assertions.
    
    This core feature enables the generator to produce fully usable Go APIs
    for any EFL class with properties, methods, and events.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 cmd/ego-gen/generator.go            |   1 +
 cmd/ego-gen/generator_test.go       |  22 ++++---
 cmd/ego-gen/templates/class.go.tmpl | 113 +++++++++++++++++++++++++++++++++++-
 cmd/ego-gen/typemap.go              |  10 ++++
 4 files changed, 134 insertions(+), 12 deletions(-)

diff --git a/cmd/ego-gen/generator.go b/cmd/ego-gen/generator.go
index c4604cc..634eee1 100644
--- a/cmd/ego-gen/generator.go
+++ b/cmd/ego-gen/generator.go
@@ -97,6 +97,7 @@ func NewGenerator(templateDir, outputDir string) (*Generator, error) {
 		"isPointerType":         IsPointerType,
 		"isBoolType":            IsBoolType,
 		"cTypeToCgo":            CTypeToCgo,
+		"stripPointerSuffix":    StripPointerSuffix,
 	}
 
 	pattern := filepath.Join(templateDir, "*.tmpl")
diff --git a/cmd/ego-gen/generator_test.go b/cmd/ego-gen/generator_test.go
index d3c9969..bd893c6 100644
--- a/cmd/ego-gen/generator_test.go
+++ b/cmd/ego-gen/generator_test.go
@@ -35,13 +35,14 @@ func TestGenerateClass(t *testing.T) {
 	g, outDir := newTestGenerator(t)
 
 	data := ClassData{
-		PackageName:  "ui",
-		GoName:       "Button",
-		EolianName:   "Efl.Ui.Button",
-		CClassName:   "efl_ui_button_class_get()",
-		CPrefix:      "efl_ui_button",
-		ParentGoType: "Widget",
-		ParentPkg:    "ui",
+		PackageName:   "ui",
+		GoName:        "Button",
+		EolianName:    "Efl.Ui.Button",
+		CClassName:    "efl_ui_button_class_get()",
+		CClassGetFunc: "efl_ui_button_class_get",
+		CPrefix:       "efl_ui_button",
+		ParentGoType:  "Widget",
+		ParentPkg:     "ui",
 		IsAbstract:   false,
 		IsMixin:      false,
 		IsInterface:  false,
@@ -67,7 +68,7 @@ func TestGenerateClass(t *testing.T) {
 		Events: []EventData{
 			{
 				GoName:     "OnClicked",
-				CEventName: "clicked",
+				CEventName: "EFL_UI_BUTTON_EVENT_CLICKED",
 			},
 		},
 	}
@@ -89,7 +90,7 @@ func TestGenerateClass(t *testing.T) {
 		"package ui",
 		"#cgo pkg-config: elementary",
 		"#include <Elementary.h>",
-		"_ego_efl_ui_button_class_get",
+		"_ego_efl_ui_button_add",
 		"efl_ui_button_class_get()",
 		"type Button struct",
 		"func wrapButton(",
@@ -98,6 +99,9 @@ func TestGenerateClass(t *testing.T) {
 		"func (o *Button) SetText(",
 		"func (o *Button) Click()",
 		"func (o *Button) OnClicked(",
+		"extern const Efl_Event_Description EFL_UI_BUTTON_EVENT_CLICKED",
+		"efl.RegisterCallback(",
+		"efl.Handle",
 	}
 
 	for _, want := range mustContain {
diff --git a/cmd/ego-gen/templates/class.go.tmpl b/cmd/ego-gen/templates/class.go.tmpl
index 34cab9e..346e6df 100644
--- a/cmd/ego-gen/templates/class.go.tmpl
+++ b/cmd/ego-gen/templates/class.go.tmpl
@@ -18,6 +18,24 @@ static Eo *_ego_{{.CPrefix}}_add(Eo *parent) {
     return efl_add_ref({{.CClassGetFunc}}(), parent, 0);
 }
 {{end}}{{end}}{{end -}}
+{{- range .Properties}}
+{{- if .HasGet}}
+extern {{.CType}} {{.CGetName}}(const Eo *obj);
+{{- end}}
+{{- if .HasSet}}
+extern void {{.CSetName}}(Eo *obj, {{.CType}} val);
+{{- end}}
+{{- end}}
+{{- range .Methods}}
+{{- if .ReturnCType}}
+extern {{.ReturnCType}} {{.CName}}(Eo *obj{{range .Params}}, {{.CType}} {{.GoName}}{{end}});
+{{- else}}
+extern void {{.CName}}(Eo *obj{{range .Params}}, {{.CType}} {{.GoName}}{{end}});
+{{- end}}
+{{- end}}
+{{- range .Events}}
+extern const Efl_Event_Description {{.CEventName}};
+{{- end}}
 */
 import "C"
 
@@ -49,8 +67,8 @@ type {{.GoName}} struct {
 {{- end}}
 }
 
-// Wrap{{.GoName}} wraps an existing Eo pointer as a {{.GoName}}.
-func Wrap{{.GoName}}(ptr unsafe.Pointer) *{{.GoName}} {
+// wrap{{.GoName}} wraps an existing Eo pointer as a {{.GoName}}.
+func wrap{{.GoName}}(ptr unsafe.Pointer) *{{.GoName}} {
     o := &{{.GoName}}{}
     o.SetEo(ptr)
     return o
@@ -67,6 +85,95 @@ func New{{.GoName}}(parent efl.Objecter) *{{.GoName}} {
     if obj == nil {
         return nil
     }
-    return Wrap{{.GoName}}(unsafe.Pointer(obj))
+    return wrap{{.GoName}}(unsafe.Pointer(obj))
 }
 {{end}}{{end}}{{end}}
+{{- range .Properties}}
+{{- if .HasGet}}
+
+// {{.GoGetter}} returns the {{.GoGetter}} property of the {{$.GoName}}.
+func (o *{{$.GoName}}) {{.GoGetter}}() {{.GoType}} {
+{{- if needsStringConversion .CType}}
+    cResult := C.{{.CGetName}}((*C.Eo)(o.Eo()))
+    return C.GoString(cResult)
+{{- else if isBoolType .CType}}
+    return C.{{.CGetName}}((*C.Eo)(o.Eo())) != 0
+{{- else if isPointerType .GoType}}
+    return unsafe.Pointer(C.{{.CGetName}}((*C.Eo)(o.Eo())))
+{{- else}}
+    return {{.GoType}}(C.{{.CGetName}}((*C.Eo)(o.Eo())))
+{{- end}}
+}
+{{- end}}
+{{- if .HasSet}}
+
+// {{.GoSetter}} sets the {{.GoGetter}} property of the {{$.GoName}}.
+func (o *{{$.GoName}}) {{.GoSetter}}(val {{.GoType}}) {
+{{- if needsStringConversion .CType}}
+    cVal := C.CString(val)
+    defer C.free(unsafe.Pointer(cVal))
+    C.{{.CSetName}}((*C.Eo)(o.Eo()), cVal)
+{{- else if isBoolType .CType}}
+    var cVal C.{{cTypeToCgo .CType}}
+    if val { cVal = 1 }
+    C.{{.CSetName}}((*C.Eo)(o.Eo()), cVal)
+{{- else if isPointerType .GoType}}
+    C.{{.CSetName}}((*C.Eo)(o.Eo()), (*C.{{stripPointerSuffix .CType}})(val))
+{{- else}}
+    C.{{.CSetName}}((*C.Eo)(o.Eo()), C.{{cTypeToCgo .CType}}(val))
+{{- end}}
+}
+{{- end}}
+{{- end}}
+{{- range .Methods}}
+
+// {{.GoName}} calls the {{.CName}} method on {{$.GoName}}.
+func (o *{{$.GoName}}) {{.GoName}}({{range $i, $p := .Params}}{{if $i}}, {{end}}{{$p.GoName}} {{$p.GoType}}{{end}}) {{if .ReturnType}}{{.ReturnType}}{{end}} {
+{{- range .Params}}
+{{- if needsStringConversion .CType}}
+    c{{.GoName}} := C.CString({{.GoName}})
+    defer C.free(unsafe.Pointer(c{{.GoName}}))
+{{- else if isBoolType .CType}}
+    var c{{.GoName}} C.{{cTypeToCgo .CType}}
+    if {{.GoName}} { c{{.GoName}} = 1 }
+{{- end}}
+{{- end}}
+{{- if .ReturnType}}
+{{- if needsStringConversion .ReturnCType}}
+    cResult := C.{{.CName}}((*C.Eo)(o.Eo()){{range .Params}}, {{if or (needsStringConversion .CType) (isBoolType .CType)}}c{{.GoName}}{{else if isPointerType .GoType}}(*C.{{stripPointerSuffix .CType}})({{.GoName}}){{else}}C.{{cTypeToCgo .CType}}({{.GoName}}){{end}}{{end}})
+    return C.GoString(cResult)
+{{- else if isBoolType .ReturnCType}}
+    return C.{{.CName}}((*C.Eo)(o.Eo()){{range .Params}}, {{if or (needsStringConversion .CType) (isBoolType .CType)}}c{{.GoName}}{{else if isPointerType .GoType}}(*C.{{stripPointerSuffix .CType}})({{.GoName}}){{else}}C.{{cTypeToCgo .CType}}({{.GoName}}){{end}}{{end}}) != 0
+{{- else if isPointerType .ReturnType}}
+    return unsafe.Pointer(C.{{.CName}}((*C.Eo)(o.Eo()){{range .Params}}, {{if or (needsStringConversion .CType) (isBoolType .CType)}}c{{.GoName}}{{else if isPointerType .GoType}}(*C.{{stripPointerSuffix .CType}})({{.GoName}}){{else}}C.{{cTypeToCgo .CType}}({{.GoName}}){{end}}{{end}}))
+{{- else}}
+    return {{.ReturnType}}(C.{{.CName}}((*C.Eo)(o.Eo()){{range .Params}}, {{if or (needsStringConversion .CType) (isBoolType .CType)}}c{{.GoName}}{{else if isPointerType .GoType}}(*C.{{stripPointerSuffix .CType}})({{.GoName}}){{else}}C.{{cTypeToCgo .CType}}({{.GoName}}){{end}}{{end}}))
+{{- end}}
+{{- else}}
+    C.{{.CName}}((*C.Eo)(o.Eo()){{range .Params}}, {{if or (needsStringConversion .CType) (isBoolType .CType)}}c{{.GoName}}{{else if isPointerType .GoType}}(*C.{{stripPointerSuffix .CType}})({{.GoName}}){{else}}C.{{cTypeToCgo .CType}}({{.GoName}}){{end}}{{end}})
+{{- end}}
+}
+{{- end}}
+{{- range .Events}}
+
+// {{.GoName}} registers fn as a callback for the {{.CEventName}} event on {{$.GoName}}.
+func (o *{{$.GoName}}) {{.GoName}}(fn func({{if .PayloadGoType}}value {{.PayloadGoType}}{{end}})) efl.Handle {
+    return efl.RegisterCallback(o.Eo(),
+        unsafe.Pointer(&C.{{.CEventName}}),
+        func(info unsafe.Pointer) {
+{{- if .PayloadGoType}}
+{{- if needsStringConversion .PayloadCType}}
+            fn(C.GoString((*C.char)(info)))
+{{- else if isBoolType .PayloadCType}}
+            fn(*(*C.{{cTypeToCgo .PayloadCType}})(info) != 0)
+{{- else if isPointerType .PayloadGoType}}
+            fn(info)
+{{- else}}
+            fn({{.PayloadGoType}}(*(*C.{{cTypeToCgo .PayloadCType}})(info)))
+{{- end}}
+{{- else}}
+            fn()
+{{- end}}
+        })
+}
+{{- end}}
diff --git a/cmd/ego-gen/typemap.go b/cmd/ego-gen/typemap.go
index 94f990b..3542fe4 100644
--- a/cmd/ego-gen/typemap.go
+++ b/cmd/ego-gen/typemap.go
@@ -78,6 +78,16 @@ func IsPointerType(goType string) bool {
 	return goType == "unsafe.Pointer"
 }
 
+// StripPointerSuffix removes the trailing " *" or "*" from a C type name.
+// Returns the input unchanged if it is not a pointer type.
+func StripPointerSuffix(ctype string) string {
+	ctype = strings.TrimSpace(ctype)
+	if strings.HasSuffix(ctype, " *") {
+		return strings.TrimSuffix(ctype, " *")
+	}
+	return strings.TrimSuffix(ctype, "*")
+}
+
 // CTypeToCgo maps a C type to a valid cgo type identifier that can be used in
 // expressions like C.<type>(value). Multi-word C types like "unsigned int" are
 // mapped to their single-word cgo equivalents ("C.uint").

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to