- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 168
functions: Add support for functions #193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
          
     Draft
      
      
            tmc
  wants to merge
  32
  commits into
  progrium:main
  
    
      
        
          
  
    
      Choose a base branch
      
     
    
      
        
      
      
        
          
          
        
        
          
            
              
              
              
  
           
        
        
          
            
              
              
           
        
       
     
  
        
          
            
          
            
          
        
       
    
      
from
tmc:functions
  
      
      
   
  
    
  
  
  
 
  
      
    base: main
Could not load branches
            
              
  
    Branch not found: {{ refName }}
  
            
                
      Loading
              
            Could not load tags
            
            
              Nothing to show
            
              
  
            
                
      Loading
              
            Are you sure you want to change the base?
            Some commits from the old base branch may be removed from the timeline,
            and old review comments may become outdated.
          
          
  
     Draft
                    Changes from all commits
      Commits
    
    
            Show all changes
          
          
            32 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      72bc506
              
                generate: Add function support
              
              
                tmc 199c402
              
                generate: Add flagging to struct and function generation
              
              
                tmc 5abf36d
              
                generate: iterate on supporting functions
              
              
                tmc 402fa4a
              
                generate: iterate on function support
              
              
                tmc 89b648e
              
                generate: Progress on functions;
              
              
                tmc 1b3a438
              
                generate: add partial struct support
              
              
                tmc d805f17
              
                generate: remove panic on nil type
              
              
                tmc ea32ec1
              
                generate: Generate Ref aliases for structs
              
              
                tmc 2464bef
              
                coregraphics: Hand-assemble call
              
              
                tmc d19847f
              
                generate: Add CName to aid in translation to and from c
              
              
                tmc cb697cd
              
                codegen: cleanup
              
              
                tmc 789e606
              
                generate: Reflect darwinkit rename
              
              
                tmc 8f2666c
              
                generate: iterate on function support
              
              
                tmc 3dfa06c
              
                generate: Progress on functions
              
              
                tmc c28de5e
              
                generate: Further iteration on function support
              
              
                tmc 7058276
              
                generate: Further iteration on function support
              
              
                tmc e7c25fd
              
                generate: Further iteration on function support
              
              
                tmc f163b31
              
                generate: Populate deprecated flag
              
              
                tmc 11efdab
              
                generate: Further progress on function support, add basic cstring han…
              
              
                tmc bbaac76
              
                generate: Further progress on function and struct support
              
              
                tmc fcb0dd2
              
                codegen: Ad struct alias support
              
              
                tmc 6aadb23
              
                generate: Add handling of alias pointers
              
              
                tmc cad5b26
              
                generate: Clean up some cruft in function calling support
              
              
                tmc 79403a2
              
                generate: Clean up some cruft in function calling support
              
              
                tmc 008d2a4
              
                generate: Expand function support, enhance skip lists
              
              
                tmc c94bfaf
              
                generate: be a bit more specific about types and functions to skip
              
              
                tmc 30e3972
              
                generate: Iterate on function support
              
              
                tmc 0d9358c
              
                generate: place mpsgraph and mps earlier in the list to be found first
              
              
                tmc 9fafbd6
              
                generate: Add some basic improve support for protocol types
              
              
                tmc a0f1afa
              
                generate: improve support for protocol type handling
              
              
                tmc a35a378
              
                codegen: Handle a few more cases, populate some mps structs
              
              
                tmc bc8d39d
              
                codegen: drop explicit skips
              
              
                tmc File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,333 @@ | ||
| package codegen | ||
|  | ||
| import ( | ||
| "fmt" | ||
| "strings" | ||
|  | ||
| "github.com/progrium/darwinkit/internal/set" | ||
|  | ||
| "github.com/progrium/darwinkit/generate/modules" | ||
| "github.com/progrium/darwinkit/generate/typing" | ||
| ) | ||
|  | ||
| // Function is code generator for objective-c (and c) functions. | ||
| type Function struct { | ||
| Type *typing.FunctionType | ||
| Name string // the first part of objc function name | ||
| GoName string | ||
| Parameters []*Param | ||
| ReturnType typing.Type | ||
| Deprecated bool // if has been deprecated | ||
| Suffix bool // GoName conflicts so add suffix to this function | ||
| Description string | ||
| DocURL string | ||
|  | ||
| goFuncName string | ||
| identifier string | ||
| } | ||
|  | ||
| var reservedWords = map[string]bool{ | ||
| "func": true, | ||
| "map": true, | ||
| "new": true, | ||
| "var": true, | ||
| "len": true, | ||
| "copy": true, | ||
| "range": true, | ||
| "type": true, | ||
| "string": true, | ||
| } | ||
|  | ||
| // list of fixups for types that are not properly mapped | ||
| // ideally we shorten this list over time | ||
| var goTypeFixupMap = map[string]string{ | ||
| "*kernel.Boolean_t": "*int", | ||
| "*kernel.Mode_t": "*int", | ||
| "*kernel.Uid_t": "*int", | ||
| "*kernel.Gid_t": "*int", | ||
| "*kernel.UniChar": "*uint16", | ||
| "CGFloat": "float64", | ||
| "kernel.Boolean_t": "int", | ||
| "kernel.Cpu_type_t": "int", | ||
| "kernel.Gid_t": "int", | ||
| "kernel.Mode_t": "int", | ||
| "kernel.Pid_t": "int32", | ||
| "kernel.Uid_t": "int", | ||
| "kernel.UniChar": "uint16", | ||
| "uint8_t": "byte", | ||
| } | ||
|  | ||
| // GoArgs return go function args | ||
| func (f *Function) GoArgs(currentModule *modules.Module) string { | ||
| var args []string | ||
| var blankArgCounter = 0 | ||
| for _, p := range f.Parameters { | ||
| // if is reserved word, add _ suffix | ||
| if p.Name == "" { | ||
| p.Name = fmt.Sprintf("arg%d", blankArgCounter) | ||
| blankArgCounter++ | ||
| } | ||
| if _, ok := reservedWords[p.Name]; ok { | ||
| p.Name = p.Name + "_" | ||
| } | ||
| typ := p.Type.GoName(currentModule, true) | ||
| if v, ok := goTypeFixupMap[typ]; ok { | ||
| typ = v | ||
| } | ||
| args = append(args, fmt.Sprintf("%s %s", p.Name, typ)) | ||
| } | ||
| return strings.Join(args, ", ") | ||
| } | ||
|  | ||
| // GoReturn return go function return | ||
| func (f *Function) GoReturn(currentModule *modules.Module) string { | ||
| if f.ReturnType == nil { | ||
| return "" | ||
| } | ||
| typ := f.ReturnType.GoName(currentModule, true) | ||
| if v, ok := goTypeFixupMap[typ]; ok { | ||
| typ = v | ||
| } | ||
| return typ | ||
| } | ||
|  | ||
| // CArgs return go function args | ||
| func (f *Function) CArgs(currentModule *modules.Module) string { | ||
| var args []string | ||
| for _, p := range f.Parameters { | ||
| typ := p.Type.CName() | ||
| if cs, ok := p.Type.(hasCSignature); ok { | ||
| typ = cs.CSignature() | ||
| } | ||
| // check reserved words | ||
| if _, ok := reservedWords[p.Name]; ok { | ||
| p.Name = p.Name + "_" | ||
| } | ||
| args = append(args, fmt.Sprintf("%s %s", typ, p.Name)) | ||
|  | ||
| } | ||
| return strings.Join(args, ", ") | ||
| } | ||
|  | ||
| // Selector return full Objc function name | ||
| func (f *Function) Selector() string { | ||
| if f.identifier == "" { | ||
| var sb strings.Builder | ||
| sb.WriteString(f.Name) | ||
| for idx, p := range f.Parameters { | ||
| if idx > 0 { | ||
| sb.WriteString(p.FieldName) | ||
| } | ||
| sb.WriteString(":") | ||
| } | ||
| f.identifier = sb.String() | ||
| } | ||
| return f.identifier | ||
| } | ||
|  | ||
| func (f *Function) String() string { | ||
| return f.Selector() | ||
| } | ||
|  | ||
| // WriteGoCallCode generate go function code to call c wrapper code | ||
| func (f *Function) WriteGoCallCode(currentModule *modules.Module, cw *CodeWriter) { | ||
| funcDeclare := f.GoFuncDeclare(currentModule) | ||
|  | ||
| if f.Deprecated { | ||
| cw.WriteLine("// deprecated") | ||
| return | ||
| } | ||
|  | ||
| if hasBlockParam(f.Parameters) { | ||
| cw.WriteLineF("// // TODO: %v not implemented (missing block param support)", f.Name) | ||
| return | ||
| } | ||
|  | ||
| if f.DocURL != "" { | ||
| cw.WriteLine(fmt.Sprintf("// %s [Full Topic]", f.Description)) | ||
| cw.WriteLine(fmt.Sprintf("//\n// [Full Topic]: %s", f.DocURL)) | ||
| } | ||
|  | ||
| cw.WriteLine("func " + funcDeclare + " {") | ||
| cw.Indent() | ||
|  | ||
| f.writeGoCallParameterPrep(currentModule, cw) | ||
|  | ||
| callCode := fmt.Sprintf("C.%s(\n", f.GoName) | ||
| var sb strings.Builder | ||
| for _, p := range f.Parameters { | ||
| // cast to C type | ||
| sb.WriteString(fmt.Sprintf(cw.IndentStr+" // %T\n", p.Type)) | ||
| typ := p.Type | ||
| switch tt := typ.(type) { | ||
| case *typing.AliasType: | ||
| sb.WriteString(fmt.Sprintf(cw.IndentStr+" // %T\n", tt.Type)) | ||
| sb.WriteString(cw.IndentStr + fmt.Sprintf("(C.%s)(%s)", tt.CName(), p.GoName())) | ||
| case *typing.CStringType: | ||
| sb.WriteString(cw.IndentStr + fmt.Sprintf(" %vVal", p.GoName())) | ||
| case *typing.RefType: | ||
| sb.WriteString(cw.IndentStr + fmt.Sprintf(" unsafe.Pointer(%s)", p.GoName())) | ||
| case *typing.StructType: | ||
| sb.WriteString(cw.IndentStr + fmt.Sprintf(" *(*C.%s)(unsafe.Pointer(&%s))", tt.CName(), p.GoName())) | ||
| case *typing.PrimitiveType: | ||
| sb.WriteString(cw.IndentStr + fmt.Sprintf(" C.%s(%s)", tt.CName(), p.GoName())) | ||
| case *typing.PointerType: | ||
| sb.WriteString(cw.IndentStr + fmt.Sprintf(" (*C.%s)(unsafe.Pointer(&%s))", tt.CName(), p.GoName())) | ||
| case *typing.DispatchType: | ||
| sb.WriteString(cw.IndentStr + fmt.Sprintf(" (*C.%s)(unsafe.Pointer(&%s))", tt.CName(), p.GoName())) | ||
| case *typing.IDType: | ||
| sb.WriteString(cw.IndentStr + fmt.Sprintf(" %s.Ptr()", p.GoName())) | ||
| case *typing.ClassType, *typing.ProtocolType: | ||
| sb.WriteString(cw.IndentStr + fmt.Sprintf(" unsafe.Pointer(&%s)", p.GoName())) | ||
| default: | ||
| sb.WriteString(cw.IndentStr + p.GoName()) | ||
| } | ||
| sb.WriteString(",\n") | ||
| } | ||
| callCode += sb.String() + cw.IndentStr + ")" | ||
|  | ||
| returnTypeStr := f.GoReturn(currentModule) | ||
| if returnTypeStr == "" { | ||
| cw.WriteLine(callCode) | ||
| } else { | ||
| var resultName = "rv" | ||
| cw.WriteLine(resultName + " := " + callCode) | ||
| cw.WriteLineF("// %T", f.ReturnType) | ||
| switch tt := f.ReturnType.(type) { | ||
| case *typing.StructType, *typing.PointerType: | ||
| cw.WriteLineF("return *(*%s)(unsafe.Pointer(&%s))", tt.GoName(currentModule, true), resultName) | ||
| case *typing.CStringType: | ||
| cw.WriteLineF("return C.GoString(%s)", resultName) | ||
| case *typing.ProtocolType: | ||
| cw.WriteLineF("return %s{objc.ObjectFrom(%s)}", returnTypeStr, resultName) | ||
| case *typing.AliasType: | ||
| cw.WriteLineF("return *(*%s)(unsafe.Pointer(&%s))", returnTypeStr, resultName) | ||
| default: | ||
| cw.WriteLineF("return %s(%s)", returnTypeStr, resultName) | ||
| } | ||
| } | ||
| cw.UnIndent() | ||
| cw.WriteLine("}") | ||
| } | ||
|  | ||
| // writeGoCallParameterPrep generate go code to prepare parameters for c function call | ||
| func (f *Function) writeGoCallParameterPrep(currentModule *modules.Module, cw *CodeWriter) { | ||
| for _, p := range f.Parameters { | ||
| switch p.Type.(type) { | ||
| default: | ||
| continue | ||
| case *typing.CStringType: | ||
| cw.WriteLineF("%sVal := C.CString(%v)", p.GoName(), p.GoName()) | ||
| cw.WriteLineF("defer C.free(unsafe.Pointer(%sVal))", p.GoName()) | ||
| } | ||
| } | ||
| } | ||
|  | ||
| func hasBlockParam(params []*Param) bool { | ||
| for _, p := range params { | ||
| if _, ok := p.Type.(*typing.BlockType); ok { | ||
| return true | ||
| } | ||
| if pt, ok := p.Type.(*typing.AliasType); ok { | ||
| t := typing.UnwrapAlias(pt.Type) | ||
| if _, ok := t.(*typing.BlockType); ok { | ||
| return true | ||
| } | ||
| } | ||
| } | ||
| return false | ||
| } | ||
|  | ||
| // WriteObjcWrapper generate objc wrapper code that maps between C and ObjC. | ||
| func (f *Function) WriteObjcWrapper(currentModule *modules.Module, cw *CodeWriter) { | ||
| if f.Deprecated { | ||
| return | ||
| cw.WriteLine("// deprecated") | ||
| } | ||
| if hasBlockParam(f.Parameters) { | ||
| cw.WriteLineF("// // TODO: %v not implemented (missing block param support)", f.Name) | ||
| return | ||
| } | ||
| returnTypeStr := f.Type.ReturnType.CName() | ||
| if cs, ok := f.Type.ReturnType.(hasCSignature); ok { | ||
| returnTypeStr = cs.CSignature() | ||
| } | ||
| cw.WriteLineF("%v %v(%v) {", returnTypeStr, f.GoName, f.CArgs(currentModule)) | ||
| cw.Indent() | ||
| cw.WriteLineF("return (%v)%v(", returnTypeStr, f.Type.Name) | ||
| cw.Indent() | ||
|  | ||
| for idx, p := range f.Parameters { | ||
| cw.WriteLineF("// %T", p.Type) | ||
|  | ||
| var conv string | ||
| switch tt := p.Type.(type) { | ||
| case *typing.PointerType: | ||
| cw.WriteLineF("// -> %T", tt.Type) | ||
| conv = tt.ObjcName() | ||
| // case *typing.AliasType: | ||
| // conv = tt.ObjcName() + "*" | ||
| default: | ||
| conv = tt.ObjcName() | ||
| } | ||
| // get conversion to C type | ||
| arg := fmt.Sprintf("(%v)%v", conv, p.Name) | ||
| if idx < len(f.Parameters)-1 { | ||
| arg += "," | ||
| } | ||
| cw.WriteLineF("%v", arg) | ||
| } | ||
| //cw.WriteLineF("return (%v)%v(%v);", returnTypeStr, f.Type.Name, strings.Join(args, ", ")) | ||
| cw.UnIndent() | ||
| cw.WriteLine(");") | ||
| cw.UnIndent() | ||
| cw.WriteLine("}") | ||
| } | ||
|  | ||
| type hasCSignature interface { | ||
| CSignature() string | ||
| } | ||
|  | ||
| func (f *Function) WriteCSignature(currentModule *modules.Module, cw *CodeWriter) { | ||
| var returnTypeStr string | ||
| rt := f.Type.ReturnType | ||
| returnTypeStr = rt.CName() | ||
| // check for CSignature: | ||
| if cs, ok := rt.(hasCSignature); ok { | ||
| returnTypeStr = cs.CSignature() | ||
| } | ||
|  | ||
| if hasBlockParam(f.Parameters) { | ||
| cw.WriteLineF("// // TODO: %v not implemented (missing block param support)", f.Name) | ||
| return | ||
| } | ||
| cw.WriteLineF("// %v %v(%v); ", returnTypeStr, f.GoName, f.CArgs(currentModule)) | ||
| } | ||
|  | ||
| // WriteGoInterfaceCode generate go interface function signature code | ||
| func (f *Function) WriteGoInterfaceCode(currentModule *modules.Module, classType *typing.ClassType, w *CodeWriter) { | ||
| if f.Deprecated { | ||
| return | ||
| w.WriteLine("// deprecated") | ||
| } | ||
| funcDeclare := f.GoFuncDeclare(currentModule) | ||
| w.WriteLine(funcDeclare) | ||
| } | ||
|  | ||
| // GoFuncDeclare generate go function declaration | ||
| func (f *Function) GoFuncDeclare(currentModule *modules.Module) string { | ||
| var returnType = f.GoReturn(currentModule) | ||
| return f.Type.GoName(currentModule, true) + "(" + f.GoArgs(currentModule) + ") " + returnType | ||
| } | ||
|  | ||
| // GoImports return all imports for go file | ||
| func (f *Function) GoImports() set.Set[string] { | ||
| var imports = set.New("github.com/progrium/darwinkit/objc") | ||
| for _, param := range f.Parameters { | ||
| imports.AddSet(param.Type.GoImports()) | ||
| } | ||
| if f.ReturnType != nil { | ||
| imports.AddSet(f.ReturnType.GoImports()) | ||
| } | ||
| return imports | ||
| } | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package codegen | ||
|  | ||
| import ( | ||
| "github.com/progrium/darwinkit/generate/typing" | ||
| ) | ||
|  | ||
| // Struct is code generator for objective-c struct | ||
| type Struct struct { | ||
| Type typing.Type | ||
| Name string // the first part of objc function name | ||
| GoName string | ||
| Deprecated bool // if has been deprecated | ||
| Suffix bool // GoName conflicts so add suffix to this function | ||
| Description string | ||
| DocURL string | ||
|  | ||
| goFuncName string | ||
| identifier string | ||
| } | ||
      
      Oops, something went wrong.
        
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think since you originally submitted this i added a struct generator and we should be generating all of them for the frameworks we have: https://github.com/progrium/darwinkit/blob/main/generate/tools/structs.go
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh great, thanks, happy to cull this.