Skip to content

Commit

Permalink
Variadic support (#190)
Browse files Browse the repository at this point in the history
* generate: support variadic methods. closes #181

* macos: regen foundation for variadic methods

* generate: add regen tool

* macos: regen appkit for variadic methods

* macos: regen coreimage for variadic methods

* macos: regen corespotlight for variadic methods
  • Loading branch information
progrium committed Aug 20, 2023
1 parent 426e9b3 commit 6de24e5
Show file tree
Hide file tree
Showing 26 changed files with 213 additions and 194 deletions.
6 changes: 6 additions & 0 deletions docs/generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,9 @@ Shell script that gives basic stats on generated frameworks.
Finds type symbol(s) in symbolsdb with the given type name. Can be used with `jq`.

`go run ./generate/tools/type.go NSWindow`

### regen [platform]

Re-generates frameworks that have been generated (have .gen.go files).

`./generate/tools/regen.sh macos`
6 changes: 6 additions & 0 deletions generate/codegen/gen_class.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ func (c *Class) writeGoStruct(w *CodeWriter) {
for _, p := range m.Params {
params = append(params, p.GoName())
}
if m.Variadic {
params = append(params, "args...")
}
alloc := ".Alloc()"
if im.ClassMethod {
alloc = ""
Expand Down Expand Up @@ -272,6 +275,9 @@ func (c *Class) writeGoStruct(w *CodeWriter) {
for _, p := range m.Params {
params = append(params, p.GoName())
}
if m.Variadic {
params = append(params, "args...")
}
returnKeyword := "return "
rt := typing.UnwrapAlias(m.ReturnType)
if _, ok := rt.(*typing.VoidType); ok {
Expand Down
28 changes: 20 additions & 8 deletions generate/codegen/gen_method.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Method struct {
Required bool // If this method is required. only for protocol method.
InitMethod bool // method that return instancetype
Suffix bool // GoName conflicts so add suffix to this method
Variadic bool
Description string
DocURL string

Expand Down Expand Up @@ -70,6 +71,7 @@ func (m *Method) NormalizeInstanceTypeMethod(returnType *typing.ClassType) *Meth
InitMethod: m.InitMethod,
goFuncName: m.goFuncName,
Suffix: m.Suffix,
Variadic: m.Variadic,
}
return nm
}
Expand Down Expand Up @@ -108,32 +110,35 @@ func (m *Method) WriteGoCallCode(currentModule *modules.Module, typeName string,
returnTypeStr = m.ReturnType.GoName(currentModule, true)
}
callCode := fmt.Sprintf("objc.Call[%s](%s, objc.Sel(\"%s\")", returnTypeStr, receiver, m.Selector())
var sb strings.Builder
var args []string
for idx, p := range m.Params {
sb.WriteString(", ")
switch tt := p.Type.(type) {
case *typing.ClassType:
sb.WriteString("objc.Ptr(" + p.GoName() + ")")
args = append(args, "objc.Ptr("+p.GoName()+")")
case *typing.ProtocolType:
pvar := fmt.Sprintf("po%d", idx)
cw.WriteLineF("%s := objc.WrapAsProtocol(\"%s\", %s)", pvar, tt.Name, p.GoName())
if m.WeakProperty { // weak property setter
cw.WriteLineF("objc.SetAssociatedObject(%s, objc.AssociationKey(\"%s\"), %s, objc.ASSOCIATION_RETAIN)",
receiver, m.GoName, pvar)
}
sb.WriteString(pvar)
args = append(args, pvar)
case *typing.PointerType:
switch tt.Type.(type) {
case *typing.ClassType: //object pointer convert to unsafe.Pointer, avoiding ffi treat it as PointerHolder
sb.WriteString(fmt.Sprintf("unsafe.Pointer(%s)", p.GoName()))
args = append(args, fmt.Sprintf("unsafe.Pointer(%s)", p.GoName()))
default:
sb.WriteString(p.GoName())
args = append(args, p.GoName())
}
default:
sb.WriteString(p.GoName())
args = append(args, p.GoName())
}
}
callCode += sb.String() + ")"
if m.Variadic {
callCode += fmt.Sprintf(", append([]any{%s}, args...)...)", strings.Join(args, ", "))
} else {
callCode += fmt.Sprintf(", %s)", strings.Join(args, ", "))
}

switch rt.(type) {
case *typing.VoidType:
Expand Down Expand Up @@ -169,6 +174,9 @@ func (m *Method) GoFuncDeclare(currentModule *modules.Module, goTypeName string)
for _, p := range m.Params {
paramStrs = append(paramStrs, p.GoDeclare(currentModule, false))
}
if m.Variadic {
paramStrs = append(paramStrs, "args ...any")
}

var returnType = m.ReturnType.GoName(currentModule, true)
return m.GoFuncName() + "(" + strings.Join(paramStrs, ", ") + ")" + " " + returnType
Expand Down Expand Up @@ -204,6 +212,9 @@ func (m *Method) ProtocolGoFuncFieldType(currentModule *modules.Module) string {
for _, p := range m.Params {
paramStrs = append(paramStrs, p.GoDeclare(currentModule, true))
}
if m.Variadic {
paramStrs = append(paramStrs, "args ...any")
}

return "(" + strings.Join(paramStrs, ", ") + ")" + " " + m.ReturnType.GoName(currentModule, false)
}
Expand Down Expand Up @@ -280,5 +291,6 @@ func (m *Method) ToProtocolParamAsObjectMethod() *Method {
Required: m.Required,
Description: m.Description,
DocURL: m.DocURL,
Variadic: m.Variadic,
}
}
1 change: 1 addition & 0 deletions generate/members.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ func (db *Generator) Members(fw string, sym Symbol, covariantTypes []string) (pr
Params: params,
ReturnType: rettyp,
ClassMethod: st.Method.TypeMethod,
Variadic: st.Method.Variadic,
Description: s.Description,
DocURL: s.DocURL(),
Deprecated: false, // todo: support deprecated
Expand Down
3 changes: 3 additions & 0 deletions generate/tools/regen.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

find ./$1 -type f -name "*.gen.go" -exec dirname {} \; | sort -u | xargs -I{} go generate {}
8 changes: 4 additions & 4 deletions macos/appkit/gradient.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,16 @@ func GradientFrom(ptr unsafe.Pointer) Gradient {
}
}

func (g_ Gradient) InitWithColorsAndLocations(firstColor IColor) Gradient {
rv := objc.Call[Gradient](g_, objc.Sel("initWithColorsAndLocations:"), objc.Ptr(firstColor))
func (g_ Gradient) InitWithColorsAndLocations(firstColor IColor, args ...any) Gradient {
rv := objc.Call[Gradient](g_, objc.Sel("initWithColorsAndLocations:"), append([]any{objc.Ptr(firstColor)}, args...)...)
return rv
}

// Initializes a newly allocated gradient object with a comma-separated list of arguments. [Full Topic]
//
// [Full Topic]: https://developer.apple.com/documentation/appkit/nsgradient/1555387-initwithcolorsandlocations?language=objc
func Gradient_InitWithColorsAndLocations(firstColor IColor) Gradient {
return GradientClass.Alloc().InitWithColorsAndLocations(firstColor)
func Gradient_InitWithColorsAndLocations(firstColor IColor, args ...any) Gradient {
return GradientClass.Alloc().InitWithColorsAndLocations(firstColor, args...)
}

func (g_ Gradient) InitWithStartingColorEndingColor(startingColor IColor, endingColor IColor) Gradient {
Expand Down
16 changes: 8 additions & 8 deletions macos/appkit/text_storage.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,16 @@ func TextStorage_InitWithHTMLOptionsDocumentAttributes(data []byte, options map[
return TextStorageClass.Alloc().InitWithHTMLOptionsDocumentAttributes(data, options, dict)
}

func (tc _TextStorageClass) LocalizedAttributedStringWithFormat(format foundation.IAttributedString) TextStorage {
rv := objc.Call[TextStorage](tc, objc.Sel("localizedAttributedStringWithFormat:"), objc.Ptr(format))
func (tc _TextStorageClass) LocalizedAttributedStringWithFormat(format foundation.IAttributedString, args ...any) TextStorage {
rv := objc.Call[TextStorage](tc, objc.Sel("localizedAttributedStringWithFormat:"), append([]any{objc.Ptr(format)}, args...)...)
return rv
}

// [Full Topic]
//
// [Full Topic]: https://developer.apple.com/documentation/foundation/nsattributedstring/3746877-localizedattributedstringwithfor?language=objc
func TextStorage_LocalizedAttributedStringWithFormat(format foundation.IAttributedString) TextStorage {
return TextStorageClass.LocalizedAttributedStringWithFormat(format)
func TextStorage_LocalizedAttributedStringWithFormat(format foundation.IAttributedString, args ...any) TextStorage {
return TextStorageClass.LocalizedAttributedStringWithFormat(format, args...)
}

func (t_ TextStorage) InitWithAttributedString(attrStr foundation.IAttributedString) TextStorage {
Expand All @@ -135,16 +135,16 @@ func TextStorage_InitWithContentsOfMarkdownFileAtURLOptionsBaseURLError(markdown
return TextStorageClass.Alloc().InitWithContentsOfMarkdownFileAtURLOptionsBaseURLError(markdownFile, options, baseURL, error)
}

func (t_ TextStorage) InitWithFormatOptionsLocale(format foundation.IAttributedString, options foundation.AttributedStringFormattingOptions, locale foundation.ILocale) TextStorage {
rv := objc.Call[TextStorage](t_, objc.Sel("initWithFormat:options:locale:"), objc.Ptr(format), options, objc.Ptr(locale))
func (t_ TextStorage) InitWithFormatOptionsLocale(format foundation.IAttributedString, options foundation.AttributedStringFormattingOptions, locale foundation.ILocale, args ...any) TextStorage {
rv := objc.Call[TextStorage](t_, objc.Sel("initWithFormat:options:locale:"), append([]any{objc.Ptr(format), options, objc.Ptr(locale)}, args...)...)
return rv
}

// [Full Topic]
//
// [Full Topic]: https://developer.apple.com/documentation/foundation/nsattributedstring/3746873-initwithformat?language=objc
func TextStorage_InitWithFormatOptionsLocale(format foundation.IAttributedString, options foundation.AttributedStringFormattingOptions, locale foundation.ILocale) TextStorage {
return TextStorageClass.Alloc().InitWithFormatOptionsLocale(format, options, locale)
func TextStorage_InitWithFormatOptionsLocale(format foundation.IAttributedString, options foundation.AttributedStringFormattingOptions, locale foundation.ILocale, args ...any) TextStorage {
return TextStorageClass.Alloc().InitWithFormatOptionsLocale(format, options, locale, args...)
}

func (t_ TextStorage) InitWithDataOptionsDocumentAttributesError(data []byte, options map[AttributedStringDocumentReadingOptionKey]objc.IObject, dict map[AttributedStringDocumentAttributeKey]objc.IObject, error foundation.IError) TextStorage {
Expand Down
14 changes: 7 additions & 7 deletions macos/coreimage/filter.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type IFilter interface {
objc.IObject
SetDefaults()
Name() string
Apply(k IKernel) Image
Apply(k IKernel, args ...any) Image
OutputKeys() []string
InputKeys() []string
IsEnabled() bool
Expand Down Expand Up @@ -2380,8 +2380,8 @@ func Filter_ThermalFilter() Filter {
// Produces a CIImage object by applying a kernel function. [Full Topic]
//
// [Full Topic]: https://developer.apple.com/documentation/coreimage/cifilter/1562058-apply?language=objc
func (f_ Filter) Apply(k IKernel) Image {
rv := objc.Call[Image](f_, objc.Sel("apply:"), objc.Ptr(k))
func (f_ Filter) Apply(k IKernel, args ...any) Image {
rv := objc.Call[Image](f_, objc.Sel("apply:"), append([]any{objc.Ptr(k)}, args...)...)
return rv
}

Expand Down Expand Up @@ -3543,16 +3543,16 @@ func Filter_ConvolutionRGB5X5Filter() Filter {
// Creates a CIFilter object for a specific kind of filter and initializes the input values with a nil-terminated list of arguments. [Full Topic]
//
// [Full Topic]: https://developer.apple.com/documentation/coreimage/cifilter/1562057-filterwithname?language=objc
func (fc _FilterClass) FilterWithNameKeysAndValues(name string, key0 objc.IObject) Filter {
rv := objc.Call[Filter](fc, objc.Sel("filterWithName:keysAndValues:"), name, key0)
func (fc _FilterClass) FilterWithNameKeysAndValues(name string, key0 objc.IObject, args ...any) Filter {
rv := objc.Call[Filter](fc, objc.Sel("filterWithName:keysAndValues:"), append([]any{name, key0}, args...)...)
return rv
}

// Creates a CIFilter object for a specific kind of filter and initializes the input values with a nil-terminated list of arguments. [Full Topic]
//
// [Full Topic]: https://developer.apple.com/documentation/coreimage/cifilter/1562057-filterwithname?language=objc
func Filter_FilterWithNameKeysAndValues(name string, key0 objc.IObject) Filter {
return FilterClass.FilterWithNameKeysAndValues(name, key0)
func Filter_FilterWithNameKeysAndValues(name string, key0 objc.IObject, args ...any) Filter {
return FilterClass.FilterWithNameKeysAndValues(name, key0, args...)
}

// Returns a convolution 3 x 3 filter. [Full Topic]
Expand Down
24 changes: 12 additions & 12 deletions macos/corespotlight/localized_string.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,16 @@ func LocalizedString_StringWithString(string_ string) LocalizedString {
return LocalizedStringClass.StringWithString(string_)
}

func (l_ LocalizedString) InitWithFormatLocale(format string, locale objc.IObject) LocalizedString {
rv := objc.Call[LocalizedString](l_, objc.Sel("initWithFormat:locale:"), format, locale)
func (l_ LocalizedString) InitWithFormatLocale(format string, locale objc.IObject, args ...any) LocalizedString {
rv := objc.Call[LocalizedString](l_, objc.Sel("initWithFormat:locale:"), append([]any{format, locale}, args...)...)
return rv
}

// Returns an NSString object initialized by using a given format string as a template into which the remaining argument values are substituted according to given locale. [Full Topic]
//
// [Full Topic]: https://developer.apple.com/documentation/foundation/nsstring/1497317-initwithformat?language=objc
func LocalizedString_InitWithFormatLocale(format string, locale objc.IObject) LocalizedString {
return LocalizedStringClass.Alloc().InitWithFormatLocale(format, locale)
func LocalizedString_InitWithFormatLocale(format string, locale objc.IObject, args ...any) LocalizedString {
return LocalizedStringClass.Alloc().InitWithFormatLocale(format, locale, args...)
}

func (l_ LocalizedString) InitWithDataEncoding(data []byte, encoding foundation.StringEncoding) LocalizedString {
Expand All @@ -119,16 +119,16 @@ func LocalizedString_InitWithDataEncoding(data []byte, encoding foundation.Strin
return LocalizedStringClass.Alloc().InitWithDataEncoding(data, encoding)
}

func (lc _LocalizedStringClass) StringWithFormat(format string) LocalizedString {
rv := objc.Call[LocalizedString](lc, objc.Sel("stringWithFormat:"), format)
func (lc _LocalizedStringClass) StringWithFormat(format string, args ...any) LocalizedString {
rv := objc.Call[LocalizedString](lc, objc.Sel("stringWithFormat:"), append([]any{format}, args...)...)
return rv
}

// Returns a string created by using a given format string as a template into which the remaining argument values are substituted. [Full Topic]
//
// [Full Topic]: https://developer.apple.com/documentation/foundation/nsstring/1497275-stringwithformat?language=objc
func LocalizedString_StringWithFormat(format string) LocalizedString {
return LocalizedStringClass.StringWithFormat(format)
func LocalizedString_StringWithFormat(format string, args ...any) LocalizedString {
return LocalizedStringClass.StringWithFormat(format, args...)
}

func (l_ LocalizedString) InitWithBytesNoCopyLengthEncodingDeallocator(bytes unsafe.Pointer, len uint, encoding foundation.StringEncoding, deallocator func(arg0 unsafe.Pointer, arg1 uint)) LocalizedString {
Expand Down Expand Up @@ -215,16 +215,16 @@ func LocalizedString_InitWithUTF8String(nullTerminatedCString *uint8) LocalizedS
return LocalizedStringClass.Alloc().InitWithUTF8String(nullTerminatedCString)
}

func (lc _LocalizedStringClass) LocalizedStringWithFormat(format string) LocalizedString {
rv := objc.Call[LocalizedString](lc, objc.Sel("localizedStringWithFormat:"), format)
func (lc _LocalizedStringClass) LocalizedStringWithFormat(format string, args ...any) LocalizedString {
rv := objc.Call[LocalizedString](lc, objc.Sel("localizedStringWithFormat:"), append([]any{format}, args...)...)
return rv
}

// Returns a string created by using a given format string as a template into which the remaining argument values are substituted according to the current locale. [Full Topic]
//
// [Full Topic]: https://developer.apple.com/documentation/foundation/nsstring/1497301-localizedstringwithformat?language=objc
func LocalizedString_LocalizedStringWithFormat(format string) LocalizedString {
return LocalizedStringClass.LocalizedStringWithFormat(format)
func LocalizedString_LocalizedStringWithFormat(format string, args ...any) LocalizedString {
return LocalizedStringClass.LocalizedStringWithFormat(format, args...)
}

func (lc _LocalizedStringClass) StringWithUTF8String(nullTerminatedCString *uint8) LocalizedString {
Expand Down
16 changes: 8 additions & 8 deletions macos/foundation/array.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,16 @@ func ArrayFrom(ptr unsafe.Pointer) Array {
}
}

func (a_ Array) InitWithObjects(firstObj objc.IObject) Array {
rv := objc.Call[Array](a_, objc.Sel("initWithObjects:"), objc.Ptr(firstObj))
func (a_ Array) InitWithObjects(firstObj objc.IObject, args ...any) Array {
rv := objc.Call[Array](a_, objc.Sel("initWithObjects:"), append([]any{objc.Ptr(firstObj)}, args...)...)
return rv
}

// Initializes a newly allocated array by placing in it the objects in the argument list. [Full Topic]
//
// [Full Topic]: https://developer.apple.com/documentation/foundation/nsarray/1460068-initwithobjects?language=objc
func Array_InitWithObjects(firstObj objc.IObject) Array {
return ArrayClass.Alloc().InitWithObjects(firstObj)
func Array_InitWithObjects(firstObj objc.IObject, args ...any) Array {
return ArrayClass.Alloc().InitWithObjects(firstObj, args...)
}

func (ac _ArrayClass) Array() Array {
Expand All @@ -105,16 +105,16 @@ func Array_Array() Array {
return ArrayClass.Array()
}

func (ac _ArrayClass) ArrayWithObjects(firstObj objc.IObject) Array {
rv := objc.Call[Array](ac, objc.Sel("arrayWithObjects:"), objc.Ptr(firstObj))
func (ac _ArrayClass) ArrayWithObjects(firstObj objc.IObject, args ...any) Array {
rv := objc.Call[Array](ac, objc.Sel("arrayWithObjects:"), append([]any{objc.Ptr(firstObj)}, args...)...)
return rv
}

// Creates and returns an array containing the objects in the argument list. [Full Topic]
//
// [Full Topic]: https://developer.apple.com/documentation/foundation/nsarray/1460145-arraywithobjects?language=objc
func Array_ArrayWithObjects(firstObj objc.IObject) Array {
return ArrayClass.ArrayWithObjects(firstObj)
func Array_ArrayWithObjects(firstObj objc.IObject, args ...any) Array {
return ArrayClass.ArrayWithObjects(firstObj, args...)
}

func (a_ Array) InitWithArray(array []objc.IObject) Array {
Expand Down
12 changes: 6 additions & 6 deletions macos/foundation/assertion_handler.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ type _AssertionHandlerClass struct {
// An interface definition for the [AssertionHandler] class.
type IAssertionHandler interface {
objc.IObject
HandleFailureInMethodObjectFileLineNumberDescription(selector objc.Selector, object objc.IObject, fileName string, line int, format string)
HandleFailureInFunctionFileLineNumberDescription(functionName string, fileName string, line int, format string)
HandleFailureInMethodObjectFileLineNumberDescription(selector objc.Selector, object objc.IObject, fileName string, line int, format string, args ...any)
HandleFailureInFunctionFileLineNumberDescription(functionName string, fileName string, line int, format string, args ...any)
}

// An object that logs an assertion to the console. [Full Topic]
Expand Down Expand Up @@ -62,15 +62,15 @@ func (a_ AssertionHandler) Init() AssertionHandler {
// Logs (using NSLog) an error message that includes the name of the method that failed, the class name of the object, the name of the source file, and the line number. [Full Topic]
//
// [Full Topic]: https://developer.apple.com/documentation/foundation/nsassertionhandler/1569513-handlefailureinmethod?language=objc
func (a_ AssertionHandler) HandleFailureInMethodObjectFileLineNumberDescription(selector objc.Selector, object objc.IObject, fileName string, line int, format string) {
objc.Call[objc.Void](a_, objc.Sel("handleFailureInMethod:object:file:lineNumber:description:"), selector, object, fileName, line, format)
func (a_ AssertionHandler) HandleFailureInMethodObjectFileLineNumberDescription(selector objc.Selector, object objc.IObject, fileName string, line int, format string, args ...any) {
objc.Call[objc.Void](a_, objc.Sel("handleFailureInMethod:object:file:lineNumber:description:"), append([]any{selector, object, fileName, line, format}, args...)...)
}

// Logs (using NSLog) an error message that includes the name of the function, the name of the file, and the line number. [Full Topic]
//
// [Full Topic]: https://developer.apple.com/documentation/foundation/nsassertionhandler/1569532-handlefailureinfunction?language=objc
func (a_ AssertionHandler) HandleFailureInFunctionFileLineNumberDescription(functionName string, fileName string, line int, format string) {
objc.Call[objc.Void](a_, objc.Sel("handleFailureInFunction:file:lineNumber:description:"), functionName, fileName, line, format)
func (a_ AssertionHandler) HandleFailureInFunctionFileLineNumberDescription(functionName string, fileName string, line int, format string, args ...any) {
objc.Call[objc.Void](a_, objc.Sel("handleFailureInFunction:file:lineNumber:description:"), append([]any{functionName, fileName, line, format}, args...)...)
}

// Returns the NSAssertionHandler object associated with the current thread. [Full Topic]
Expand Down
Loading

0 comments on commit 6de24e5

Please sign in to comment.