Skip to content

Commit b8d925b

Browse files
committed
generate: Further progress on function support, add basic cstring handling
1 parent 30f794a commit b8d925b

File tree

8 files changed

+178
-32
lines changed

8 files changed

+178
-32
lines changed

generate/codegen/gen_function.go

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package codegen
22

33
import (
44
"fmt"
5-
"log"
65
"strings"
76

87
"github.com/progrium/macdriver/internal/set"
@@ -44,16 +43,18 @@ var typeMap = map[string]string{
4443
"*kernel.UniChar": "*uint16",
4544
"kernel.Boolean_t": "int",
4645
"kernel.Pid_t": "int32",
46+
"CGFloat": "float64",
47+
"uint8_t": "byte",
4748
}
4849

4950
// GoArgs return go function args
5051
func (f *Function) GoArgs(currentModule *modules.Module) string {
51-
log.Println("rendering function", f.Name)
52+
// log.Println("rendering function", f.Name)
5253
var args []string
5354
var blankArgCounter = 0
5455
for _, p := range f.Parameters {
55-
log.Println("rendering function", f.Name, p.Name, p.Type)
56-
log.Printf("rendering function ptype: %T", p.Type)
56+
// log.Println("rendering function", f.Name, p.Name, p.Type)
57+
// log.Printf("rendering function ptype: %T", p.Type)
5758
// if is reserved word, add _ suffix
5859
if p.Name == "" {
5960
p.Name = fmt.Sprintf("arg%d", blankArgCounter)
@@ -146,7 +147,7 @@ func (f *Function) WriteGoCallCode(currentModule *modules.Module, cw *CodeWriter
146147
cw.WriteLine("func " + funcDeclare + " {")
147148
cw.Indent()
148149

149-
returnTypeStr := f.GoReturn(currentModule)
150+
f.writeGoCallParameterPrep(currentModule, cw)
150151

151152
callCode := fmt.Sprintf("C.%s(\n", f.GoName)
152153
var sb strings.Builder
@@ -164,6 +165,8 @@ func (f *Function) WriteGoCallCode(currentModule *modules.Module, cw *CodeWriter
164165
} else {
165166
sb.WriteString(cw.IndentStr + fmt.Sprintf("(C.%s)(%s)", tt.CName(), p.GoName()))
166167
}
168+
case *typing.CStringType:
169+
sb.WriteString(cw.IndentStr + fmt.Sprintf(" %vVal", p.GoName()))
167170
case *typing.RefType:
168171
sb.WriteString(cw.IndentStr + fmt.Sprintf(" unsafe.Pointer(%s)", p.GoName()))
169172
case *typing.StructType:
@@ -179,6 +182,7 @@ func (f *Function) WriteGoCallCode(currentModule *modules.Module, cw *CodeWriter
179182
}
180183
callCode += sb.String() + cw.IndentStr + ")"
181184

185+
returnTypeStr := f.GoReturn(currentModule)
182186
if returnTypeStr == "" {
183187
cw.WriteLine(callCode)
184188
} else {
@@ -196,6 +200,19 @@ func (f *Function) WriteGoCallCode(currentModule *modules.Module, cw *CodeWriter
196200
cw.WriteLine("}")
197201
}
198202

203+
// writeGoCallParameterPrep generate go code to prepare parameters for c function call
204+
func (f *Function) writeGoCallParameterPrep(currentModule *modules.Module, cw *CodeWriter) {
205+
for _, p := range f.Parameters {
206+
switch p.Type.(type) {
207+
default:
208+
continue
209+
case *typing.CStringType:
210+
cw.WriteLineF("%sVal := C.CString(%v)", p.GoName(), p.GoName())
211+
cw.WriteLineF("defer C.free(unsafe.Pointer(%sVal))", p.GoName())
212+
}
213+
}
214+
}
215+
199216
func hasBlockParam(params []*Param) bool {
200217
for _, p := range params {
201218
if _, ok := p.Type.(*typing.BlockType); ok {
@@ -211,6 +228,7 @@ func hasBlockParam(params []*Param) bool {
211228
return false
212229
}
213230

231+
// WriteObjcWrapper generate objc wrapper code that maps between C and ObjC.
214232
func (f *Function) WriteObjcWrapper(currentModule *modules.Module, cw *CodeWriter) {
215233
if f.Deprecated {
216234
return
@@ -226,11 +244,29 @@ func (f *Function) WriteObjcWrapper(currentModule *modules.Module, cw *CodeWrite
226244
}
227245
cw.WriteLineF("%v %v(%v) {", returnTypeStr, f.GoName, f.CArgs(currentModule))
228246
cw.Indent()
229-
var args []string
230-
for _, p := range f.Parameters {
231-
args = append(args, p.Name)
247+
cw.WriteLineF("return (%v)%v(", returnTypeStr, f.Type.Name)
248+
cw.Indent()
249+
250+
for idx, p := range f.Parameters {
251+
cw.WriteLineF("// %T", p.Type)
252+
253+
var conv string
254+
switch tt := p.Type.(type) {
255+
case *typing.PointerType:
256+
conv = tt.ObjcName()
257+
default:
258+
conv = tt.ObjcName()
259+
}
260+
// get conversion to C type
261+
arg := fmt.Sprintf("(%v)%v", conv, p.Name)
262+
if idx < len(f.Parameters)-1 {
263+
arg += ","
264+
}
265+
cw.WriteLineF("%v", arg)
232266
}
233-
cw.WriteLineF("return %v(%v);", f.Type.Name, strings.Join(args, ", "))
267+
//cw.WriteLineF("return (%v)%v(%v);", returnTypeStr, f.Type.Name, strings.Join(args, ", "))
268+
cw.UnIndent()
269+
cw.WriteLine(");")
234270
cw.UnIndent()
235271
cw.WriteLine("}")
236272
}

generate/declparse/declparse_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,4 +1153,35 @@ var tests = []struct {
11531153
},
11541154
},
11551155
},
1156+
{
1157+
ParseOnly: true,
1158+
s: "bool CGPDFDocumentUnlockWithPassword(CGPDFDocumentRef document, const char *password);",
1159+
Hint: HintFunction,
1160+
n: &Statement{
1161+
Function: &FunctionDecl{
1162+
ReturnType: TypeInfo{
1163+
Name: "bool",
1164+
},
1165+
Name: "CGPDFDocumentUnlockWithPassword",
1166+
Args: FuncArgs{
1167+
ArgInfo{
1168+
Name: "document",
1169+
Type: TypeInfo{
1170+
Name: "CGPDFDocumentRef",
1171+
},
1172+
},
1173+
ArgInfo{
1174+
Name: "password",
1175+
Type: TypeInfo{
1176+
Name: "char",
1177+
IsPtr: true,
1178+
Annots: map[TypeAnnotation]bool{
1179+
TypeAnnotConst: true,
1180+
},
1181+
},
1182+
},
1183+
},
1184+
},
1185+
},
1186+
},
11561187
}

generate/function.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,12 @@ func (db *Generator) ToFunction(fw string, sym Symbol) *codegen.Function {
242242
"OBEXSessionSetServerCallback": true,
243243
"CFSocketCopyRegisteredValue": true,
244244
}
245+
if _, ok := map[string]bool{
246+
//"CGColorSpaceCreateCalibratedGray": true,
247+
"CGPDFDocumentUnlockWithPassword": true,
248+
}[sym.Name]; !ok {
249+
return nil
250+
}
245251
if knownIssues[sym.Name] {
246252
_, err := sym.Parse()
247253
log.Printf("skipping function %s %s because of known issue: decl='%s' err='%v'\n", fw, sym.Name, sym.Declaration, err)
@@ -260,9 +266,19 @@ func (db *Generator) ToFunction(fw string, sym Symbol) *codegen.Function {
260266
DocURL: sym.DocURL(),
261267
Type: fntyp,
262268
}
269+
// temporary skip for things deprecated in 14.0
270+
// check if macOS platform is DeprecatedAt 14.0
271+
for _, p := range sym.Platforms {
272+
if p.Name == "macOS" && p.Deprecated {
273+
fn.Deprecated = true
274+
}
275+
}
276+
263277
// populate params:
264-
log.Printf("decl: %s\n", sym.Declaration)
265-
log.Printf("params: %+v\n", fntyp.Parameters)
278+
log.Printf("decl: %v %s\n", sym.Name, sym.Declaration)
279+
for i, p := range fntyp.Parameters {
280+
log.Printf(" param %#v: %v %+v\n", i, p.Name, p.Type.ObjcName())
281+
}
266282
for _, p := range fntyp.Parameters {
267283
if p.Type == nil {
268284
fmt.Printf("skipping %s: %s because of nil type\n", sym.Name, p.Name)

generate/types.go

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package generate
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"log"
67
"strings"
@@ -141,6 +142,7 @@ func (db *Generator) TypeFromSymbol(sym Symbol) typing.Type {
141142

142143
}
143144

145+
// ParseType parses a type from a declparse.TypeInfo.
144146
func (db *Generator) ParseType(ti declparse.TypeInfo) (typ typing.Type) {
145147
defer func() {
146148
if r := recover(); r != nil {
@@ -152,18 +154,6 @@ func (db *Generator) ParseType(ti declparse.TypeInfo) (typ typing.Type) {
152154
}
153155
}
154156
}()
155-
if ti.Name == "CFURLRef" {
156-
log.Printf("ParseType: %s\n", ti.Name)
157-
log.Printf("info: %v\n", ti)
158-
log.Printf("info fn: %v\n", ti.Func)
159-
defer func() {
160-
log.Printf("info typ: %T %+v\n", typ, typ)
161-
if pt, ok := typ.(*typing.PointerType); ok {
162-
log.Printf("info typ: %T %+v\n", pt.Type, pt.Type)
163-
}
164-
165-
}()
166-
}
167157
if ti.Func != nil {
168158
var blockParams []typing.BlockParam
169159
for _, arg := range ti.Func.Args {
@@ -206,8 +196,27 @@ func (db *Generator) ParseType(ti declparse.TypeInfo) (typ typing.Type) {
206196
case "Class":
207197
// objc type
208198
typ = typing.Class
209-
case "CGFloat", "Float64":
199+
case "off_t":
200+
j, _ := json.Marshal(ti)
201+
fmt.Println(string(j))
202+
203+
// to kernel type
204+
typ = typing.Int
205+
case "float", "CGFloat", "Float64":
210206
typ = typing.Float
207+
case "char":
208+
j, _ := json.Marshal(ti)
209+
fmt.Println(string(j))
210+
211+
cTyp := "char"
212+
if ti.IsPtr {
213+
typ = &typing.CStringType{}
214+
} else {
215+
typ = &typing.PrimitiveType{
216+
GoName_: "byte",
217+
ObjcName_: cTyp,
218+
}
219+
}
211220
case "NSString":
212221
typ = &typing.StringType{}
213222
ref = true
@@ -243,15 +252,15 @@ func (db *Generator) ParseType(ti declparse.TypeInfo) (typ typing.Type) {
243252
default:
244253
var ok bool
245254
typ, ok = typing.GetPrimitiveType(ti.Name)
246-
log.Println("primitive", ti.Name, ok)
255+
// log.Println("primitive", ti.Name, ok)
247256
if !ok {
248257
typ, ok = typing.GetDispatchType(ti.Name)
249258
}
250-
log.Println("dispatch", ti.Name, ok)
259+
// log.Println("dispatch", ti.Name, ok)
251260
if !ok {
252261
typ, ok = typing.GetKernelType(ti.Name)
253262
}
254-
log.Println("kernel", ti.Name, ok)
263+
// log.Println("kernel", ti.Name, ok)
255264
if !ok {
256265
typ = db.TypeFromSymbolName(ti.Name)
257266
log.Println("symbol", ti.Name, typ, ok)
@@ -266,6 +275,10 @@ func (db *Generator) ParseType(ti declparse.TypeInfo) (typ typing.Type) {
266275
}
267276
}
268277

278+
if _, ok := typ.(*typing.CStringType); ok {
279+
return typ
280+
}
281+
269282
if ti.IsPtr && !ref {
270283
if _, ok := typ.(*typing.VoidType); ok {
271284
typ = &typing.VoidPointerType{}
@@ -274,7 +287,8 @@ func (db *Generator) ParseType(ti declparse.TypeInfo) (typ typing.Type) {
274287
panic("nil type")
275288
}
276289
typ = &typing.PointerType{
277-
Type: typ,
290+
Type: typ,
291+
IsConst: ti.Annots[declparse.TypeAnnotConst],
278292
}
279293
}
280294
}

generate/typing/cstring_type.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package typing
2+
3+
import (
4+
"github.com/progrium/macdriver/generate/modules"
5+
"github.com/progrium/macdriver/internal/set"
6+
)
7+
8+
var _ Type = (*CStringType)(nil)
9+
10+
// CStringType string
11+
type CStringType struct {
12+
IsConst bool
13+
}
14+
15+
func (s *CStringType) GoImports() set.Set[string] {
16+
return nil
17+
}
18+
19+
func (s *CStringType) GoName(currentModule *modules.Module, receiveFromObjc bool) string {
20+
return "string"
21+
}
22+
23+
func (s *CStringType) ObjcName() string {
24+
return "char*"
25+
}
26+
27+
func (s *CStringType) CName() string {
28+
return "char*"
29+
}
30+
31+
func (c *CStringType) CSignature() string {
32+
t := c.CName()
33+
if c.IsConst {
34+
t = "const " + t
35+
}
36+
return t
37+
}
38+
39+
func (s *CStringType) DeclareModule() *modules.Module {
40+
return nil
41+
}

generate/typing/pointer_type.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ var _ Type = (*PointerType)(nil)
99

1010
// PointerType is c pointer type
1111
type PointerType struct {
12-
Type Type
12+
Type Type
13+
IsConst bool
1314
}
1415

1516
func (c *PointerType) GoImports() set.Set[string] {
@@ -30,6 +31,8 @@ func (c *PointerType) GoName(currentModule *modules.Module, receiveFromObjc bool
3031
return "*" + (&ClassType{Name: "NSArray", GName: "Array", Module: modules.Get("foundation")}).GoName(currentModule, true)
3132
case *DictType:
3233
return "*" + (&ClassType{Name: "NSDictionary", GName: "Dictionary", Module: modules.Get("foundation")}).GoName(currentModule, true)
34+
case *PointerType:
35+
return "*" + c.Type.GoName(currentModule, receiveFromObjc)
3336
default:
3437
panic("not supported pointer to: " + c.Type.ObjcName())
3538
}
@@ -45,7 +48,11 @@ func (c *PointerType) CName() string {
4548
}
4649

4750
func (c *PointerType) CSignature() string {
48-
return c.Type.ObjcName() + "*"
51+
t := c.Type.ObjcName() + "*"
52+
if c.IsConst {
53+
t = "const " + t
54+
}
55+
return t
4956
}
5057

5158
func (c *PointerType) DeclareModule() *modules.Module {

generate/typing/primitive_type.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ var Bool = &PrimitiveType{GoName_: "bool", ObjcName_: "BOOL"}
1010
var Int = &PrimitiveType{GoName_: "int", ObjcName_: "NSInteger"}
1111
var UInt = &PrimitiveType{GoName_: "uint", ObjcName_: "NSUInteger"}
1212

13-
var Float = &PrimitiveType{GoName_: "float64", ObjcName_: "float"}
13+
var Float = &PrimitiveType{GoName_: "float64", ObjcName_: "CGFloat"}
1414
var Double = &PrimitiveType{GoName_: "float64", ObjcName_: "double"}
1515

1616
var Int8 = &PrimitiveType{GoName_: "int8", ObjcName_: "int8_t"}
1717
var UInt8 = &PrimitiveType{GoName_: "uint8", ObjcName_: "uint8_t"}
1818
var Byte = &PrimitiveType{GoName_: "byte", ObjcName_: "char"}
19+
var OffT = &PrimitiveType{GoName_: "float64", ObjcName_: "off_t"}
1920

2021
var Int16 = &PrimitiveType{GoName_: "int16", ObjcName_: "int16_t"}
2122
var UInt16 = &PrimitiveType{GoName_: "uint16", ObjcName_: "uint16_t"}

generate/typing/string_type.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ var _ Type = (*StringType)(nil)
99

1010
// StringType string
1111
type StringType struct {
12-
NeedNil bool // string type need nil value.If set to true, will use foundation.String instread string for generated go code.
12+
NeedNil bool // string type need nil value.If set to true, will use foundation.String instead string for generated go code.
1313
}
1414

1515
func (s *StringType) GoImports() set.Set[string] {

0 commit comments

Comments
 (0)