11package extgen
22
33import (
4+ "bytes"
5+ _ "embed"
46 "fmt"
57 "path/filepath"
68 "strings"
9+ "text/template"
10+
11+ "github.com/Masterminds/sprig/v3"
712)
813
14+ //go:embed templates/extension.go.tpl
15+ var goFileContent string
16+
917type GoFileGenerator struct {
1018 generator * Generator
1119}
1220
21+ type goTemplateData struct {
22+ PackageName string
23+ BaseName string
24+ Imports []string
25+ Constants []phpConstant
26+ InternalFunctions []string
27+ Functions []phpFunction
28+ Classes []phpClass
29+ }
30+
1331func (gg * GoFileGenerator ) generate () error {
1432 filename := filepath .Join (gg .generator .BuildDir , gg .generator .BaseName + ".go" )
1533 content , err := gg .buildContent ()
@@ -27,104 +45,47 @@ func (gg *GoFileGenerator) buildContent() (string, error) {
2745 return "" , fmt .Errorf ("analyzing source file: %w" , err )
2846 }
2947
30- var builder strings.Builder
31-
32- cleanPackageName := SanitizePackageName (gg .generator .BaseName )
33- builder .WriteString (fmt .Sprintf (`package %s
34-
35- /*
36- #include <stdlib.h>
37- #include "%s.h"
38- */
39- import "C"
40- import "runtime/cgo"
41- ` , cleanPackageName , gg .generator .BaseName ))
42-
48+ filteredImports := make ([]string , 0 , len (imports ))
4349 for _ , imp := range imports {
44- if imp = = `"C"` {
45- continue
50+ if imp ! = `"C"` {
51+ filteredImports = append ( filteredImports , imp )
4652 }
47-
48- builder .WriteString (fmt .Sprintf ("import %s\n " , imp ))
4953 }
5054
51- builder .WriteString (`
52- func init() {
53- frankenphp.RegisterExtension(unsafe.Pointer(&C.ext_module_entry))
54- }
55- ` )
56-
57- for _ , constant := range gg .generator .Constants {
58- builder .WriteString (fmt .Sprintf ("const %s = %s\n " , constant .Name , constant .Value ))
59- }
60-
61- if len (gg .generator .Constants ) > 0 {
62- builder .WriteString ("\n " )
63- }
64-
65- for _ , internalFunc := range internalFunctions {
66- builder .WriteString (internalFunc + "\n \n " )
67- }
68-
69- for _ , fn := range gg .generator .Functions {
70- builder .WriteString (fmt .Sprintf ("//export %s\n %s\n " , fn .Name , fn .goFunction ))
71- }
72-
73- for _ , class := range gg .generator .Classes {
74- builder .WriteString (fmt .Sprintf ("type %s struct {\n " , class .GoStruct ))
75- for _ , prop := range class .Properties {
76- builder .WriteString (fmt .Sprintf (" %s %s\n " , prop .Name , prop .goType ))
55+ classes := make ([]phpClass , len (gg .generator .Classes ))
56+ copy (classes , gg .generator .Classes )
57+ for i , class := range classes {
58+ for j , method := range class .Methods {
59+ classes [i ].Methods [j ].Wrapper = gg .generateMethodWrapper (method , class )
7760 }
78- builder .WriteString ("}\n \n " )
7961 }
8062
81- if len (gg .generator .Classes ) > 0 {
82- builder .WriteString (`
83- //export registerGoObject
84- func registerGoObject(obj interface{}) C.uintptr_t {
85- handle := cgo.NewHandle(obj)
86- return C.uintptr_t(handle)
87- }
88-
89- //export getGoObject
90- func getGoObject(handle C.uintptr_t) interface{} {
91- h := cgo.Handle(handle)
92- return h.value()
93- }
94-
95- //export removeGoObject
96- func removeGoObject(handle C.uintptr_t) {
97- h := cgo.Handle(handle)
98- h.Delete()
99- }
63+ templateContent , err := gg .getTemplateContent (goTemplateData {
64+ PackageName : SanitizePackageName (gg .generator .BaseName ),
65+ BaseName : gg .generator .BaseName ,
66+ Imports : filteredImports ,
67+ Constants : gg .generator .Constants ,
68+ InternalFunctions : internalFunctions ,
69+ Functions : gg .generator .Functions ,
70+ Classes : classes ,
71+ })
10072
101- ` )
73+ if err != nil {
74+ return "" , fmt .Errorf ("executing template: %w" , err )
10275 }
10376
104- for _ , class := range gg .generator .Classes {
105- builder .WriteString (fmt .Sprintf (`//export create_%s_object
106- func create_%s_object() C.uintptr_t {
107- obj := &%s{}
108- return registerGoObject(obj)
77+ return templateContent , nil
10978}
11079
111- ` , class .GoStruct , class .GoStruct , class .GoStruct ))
80+ func (gg * GoFileGenerator ) getTemplateContent (data goTemplateData ) (string , error ) {
81+ tmpl := template .Must (template .New ("gofile" ).Funcs (sprig .FuncMap ()).Parse (goFileContent ))
11282
113- for _ , method := range class .Methods {
114- if method .goFunction != "" {
115- builder .WriteString (method .goFunction )
116- builder .WriteString ("\n \n " )
117- }
118- }
119-
120- for _ , method := range class .Methods {
121- builder .WriteString (fmt .Sprintf ("//export %s_wrapper\n " , method .Name ))
122- builder .WriteString (gg .generateMethodWrapper (method , class ))
123- builder .WriteString ("\n " )
124- }
83+ var buf bytes.Buffer
84+ if err := tmpl .Execute (& buf , data ); err != nil {
85+ return "" , err
12586 }
12687
127- return builder .String (), nil
88+ return buf .String (), nil
12889}
12990
13091func (gg * GoFileGenerator ) generateMethodWrapper (method phpClassMethod , class phpClass ) string {
0 commit comments