Switch from toml to yaml for configuration files. Begin scaffolding
for Protocols and Delegates.
This commit is contained in:
parent
cccbfbbc00
commit
b00ecd4ac0
|
@ -210,6 +210,8 @@ func Parse(fullline string) Node {
|
|||
return parseObjCObjectPointerType(line)
|
||||
case "ObjCProtocol":
|
||||
return parseObjCProtocol(line)
|
||||
case "ObjCProtocolDecl":
|
||||
return parseObjCProtocolDecl(line)
|
||||
case "ObjCPropertyDecl":
|
||||
return parseObjCPropertyDecl(line)
|
||||
case "ObjCTypeParamDecl":
|
||||
|
|
55
ast/objc_protocol_decl.go
Normal file
55
ast/objc_protocol_decl.go
Normal file
|
@ -0,0 +1,55 @@
|
|||
package ast
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ObjCProtocolDecl is node represents an Objective-C property declaration
|
||||
type ObjCProtocolDecl struct {
|
||||
Addr Address
|
||||
Pos Position
|
||||
Position2 string
|
||||
Name string
|
||||
ChildNodes []Node
|
||||
}
|
||||
|
||||
func parseObjCProtocolDecl(line string) *ObjCProtocolDecl {
|
||||
groups := groupsFromRegex(
|
||||
`(?:prev (?P<prev>0x[0-9a-f]+) )?
|
||||
<(?P<position>.*<scratch space>.*?|.*<built-in>.*?|.*<invalid sloc>|.*?)>
|
||||
(?P<position2> <invalid sloc>| col:\d+| line:\d+:\d+)?
|
||||
(?P<name>.*?)`,
|
||||
line,
|
||||
)
|
||||
|
||||
return &ObjCProtocolDecl{
|
||||
Addr: ParseAddress(groups["address"]),
|
||||
Pos: NewPositionFromString(groups["position"]),
|
||||
Position2: strings.TrimSpace(groups["position2"]),
|
||||
Name: strings.TrimSpace(groups["name"]),
|
||||
ChildNodes: []Node{},
|
||||
}
|
||||
}
|
||||
|
||||
// AddChild adds a new child node. Child nodes can then be accessed with the
|
||||
// Children attribute.
|
||||
func (n *ObjCProtocolDecl) AddChild(node Node) {
|
||||
n.ChildNodes = append(n.ChildNodes, node)
|
||||
}
|
||||
|
||||
// Address returns the numeric address of the node. See the documentation for
|
||||
// the Address type for more information.
|
||||
func (n *ObjCProtocolDecl) Address() Address {
|
||||
return n.Addr
|
||||
}
|
||||
|
||||
// Children returns the child nodes. If this node does not have any children or
|
||||
// this node does not support children it will always return an empty slice.
|
||||
func (n *ObjCProtocolDecl) Children() []Node {
|
||||
return n.ChildNodes
|
||||
}
|
||||
|
||||
// Position returns the position in the original source code.
|
||||
func (n *ObjCProtocolDecl) Position() Position {
|
||||
return n.Pos
|
||||
}
|
|
@ -2,13 +2,14 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"gopkg.in/yaml.v2"
|
||||
"gitlab.wow.st/gmp/nswrap/ast"
|
||||
"gitlab.wow.st/gmp/nswrap/types"
|
||||
"gitlab.wow.st/gmp/nswrap/wrap"
|
||||
|
@ -18,15 +19,16 @@ var Debug = false
|
|||
|
||||
type conf struct {
|
||||
Package string
|
||||
InputFiles []string
|
||||
Inputfiles []string
|
||||
Classes []string
|
||||
Functions []string
|
||||
Enums []string
|
||||
Delegates map[string][]string
|
||||
Frameworks []string
|
||||
Imports []string
|
||||
SysImports []string
|
||||
Sysimports []string
|
||||
Pragma []string
|
||||
VaArgs int
|
||||
Vaargs int
|
||||
}
|
||||
|
||||
var Config conf
|
||||
|
@ -149,7 +151,7 @@ func matches(x string, rs []string) bool {
|
|||
|
||||
// Start begins transpiling an input file.
|
||||
func Start() (err error) {
|
||||
for _, in := range Config.InputFiles {
|
||||
for _, in := range Config.Inputfiles {
|
||||
_, err := os.Stat(in)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Input file %s is not found", in)
|
||||
|
@ -161,7 +163,7 @@ func Start() (err error) {
|
|||
// 3. Generate AST
|
||||
cargs := []string{"-xobjective-c", "-Xclang", "-ast-dump",
|
||||
"-fsyntax-only","-fno-color-diagnostics"}
|
||||
cargs = append(cargs,Config.InputFiles...)
|
||||
cargs = append(cargs,Config.Inputfiles...)
|
||||
fmt.Printf("Generating AST\n")
|
||||
astPP, err := exec.Command("clang",cargs...).Output()
|
||||
if err != nil {
|
||||
|
@ -192,12 +194,12 @@ func Start() (err error) {
|
|||
w.Package = Config.Package
|
||||
w.Frameworks(Config.Frameworks)
|
||||
w.Import(Config.Imports)
|
||||
w.SysImport(Config.SysImports)
|
||||
w.SysImport(Config.Sysimports)
|
||||
w.Pragma(Config.Pragma)
|
||||
if Config.VaArgs == 0 {
|
||||
Config.VaArgs = 16
|
||||
if Config.Vaargs == 0 {
|
||||
Config.Vaargs = 16
|
||||
}
|
||||
w.VaArgs = Config.VaArgs
|
||||
w.Vaargs = Config.Vaargs
|
||||
for _, u := range tree {
|
||||
fmt.Printf("--processing translation unit\n")
|
||||
for _, n := range(u.Children()) {
|
||||
|
@ -212,6 +214,15 @@ func Start() (err error) {
|
|||
if matches(x.Name,Config.Functions) {
|
||||
w.AddFunction(x)
|
||||
}
|
||||
case *ast.ObjCProtocolDecl:
|
||||
DELEGATES:
|
||||
for _,ps := range Config.Delegates {
|
||||
_ = ps
|
||||
//if matches(x.Name,ps) {
|
||||
// w.AddProtocol(x)
|
||||
break DELEGATES
|
||||
//}
|
||||
}
|
||||
case *ast.EnumDecl:
|
||||
w.AddEnum(x,Config.Enums)
|
||||
}
|
||||
|
@ -222,8 +233,13 @@ func Start() (err error) {
|
|||
}
|
||||
|
||||
func main() {
|
||||
if _, err := toml.DecodeFile("nswrap.toml",&Config); err != nil {
|
||||
fmt.Printf("Cannot open config file nswrap.toml.\n")
|
||||
confbytes, err := ioutil.ReadFile("nswrap.yaml")
|
||||
if err != nil {
|
||||
fmt.Printf("Cannot open config file nswrap.yaml. %s\n",err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
if err = yaml.Unmarshal(confbytes,&Config); err != nil {
|
||||
fmt.Printf("Cannot decode config file nswrap.yaml. %s\n",err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
if err := Start(); err != nil {
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
InputFiles = [
|
||||
"/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h",
|
||||
"/System/Library/Frameworks/AppKit.framework/Headers/AppKit.h",
|
||||
]
|
||||
Classes = [
|
||||
"NSArray",
|
||||
"NSMutableArray",
|
||||
"NSDictionary",
|
||||
"NSEnumerator",
|
||||
"NSSet",
|
||||
"NSDate",
|
||||
"NSTimeZone",
|
||||
"NSCalendar",
|
||||
"NSLocale",
|
||||
"NSCharacterSet",
|
||||
"NSString",
|
||||
"NSScanner",
|
||||
"NSFileManager",
|
||||
"NSApplication",
|
||||
"NSBundle",
|
||||
"NSApp",
|
||||
"NSMenu",
|
||||
"NSMenuItem",
|
||||
"NSWindow",
|
||||
"NSView",
|
||||
"NSScreen",
|
||||
"NSButton",
|
||||
"NSEvent",
|
||||
"NSResponder",
|
||||
"NSRunLoop",
|
||||
]
|
||||
Functions = [
|
||||
"NSMake.*",
|
||||
]
|
||||
Enums = [
|
||||
"CF.*",
|
||||
"NSApplication.*",
|
||||
"NSBackingStore.*",
|
||||
"NSWindowStyleMask.*",
|
||||
"NSWindowButton",
|
||||
"NSWindowOrderingMode",
|
||||
]
|
||||
Frameworks = [ "Foundation", "AppKit", "CoreGraphics" ]
|
||||
Pragma = [ 'clang diagnostic ignored "-Wformat-security"' ]
|
||||
VaArgs = 32
|
49
examples/app/nswrap.yaml
Normal file
49
examples/app/nswrap.yaml
Normal file
|
@ -0,0 +1,49 @@
|
|||
inputfiles:
|
||||
- /System/Library/Frameworks/Foundation.framework/Headers/Foundation.h
|
||||
- /System/Library/Frameworks/AppKit.framework/Headers/AppKit.h
|
||||
|
||||
classes:
|
||||
- NSArray"
|
||||
- NSMutableArray
|
||||
- NSDictionary
|
||||
- NSEnumerator
|
||||
- NSSet
|
||||
- NSDate
|
||||
- NSTimeZone
|
||||
- NSCalendar
|
||||
- NSLocale
|
||||
- NSCharacterSet
|
||||
- NSString
|
||||
- NSScanner
|
||||
- NSFileManager
|
||||
- NSApplication
|
||||
- NSBundle
|
||||
- NSApp
|
||||
- NSMenu
|
||||
- NSMenuItem
|
||||
- NSWindow
|
||||
- NSView
|
||||
- NSScreen
|
||||
- NSButton
|
||||
- NSEvent
|
||||
- NSResponder
|
||||
- NSRunLoop
|
||||
|
||||
functions: [NSMake.*]
|
||||
|
||||
enums:
|
||||
- CF.*
|
||||
- NSApplication.*
|
||||
- NSBackingStore.*
|
||||
- NSWindowStyleMask.*
|
||||
- NSWindowButton
|
||||
- NSWindowOrderingMode
|
||||
|
||||
delegates:
|
||||
AppDelegate: [NSApplicationDelegate]
|
||||
|
||||
frameworks: [ Foundation, AppKit, CoreGraphics ]
|
||||
pragma: [ clang diagnostic ignored "-Wformat-security" ]
|
||||
vaargs: 32
|
||||
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
Package = "ble"
|
||||
InputFiles = [
|
||||
"/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h",
|
||||
"/System/Library/Frameworks/CoreBluetooth.framework/Headers/CoreBluetooth.h",
|
||||
"ble/ble_delegate.h",
|
||||
]
|
||||
Classes = [
|
||||
"ble_delegate",
|
||||
"CBCentralManager",
|
||||
"CBPeripheralManager",
|
||||
"CBPeripheral",
|
||||
"CBCentral",
|
||||
"CBService",
|
||||
"CBCharacteristic",
|
||||
"CBDescriptor",
|
||||
"CBError",
|
||||
"CBUUID",
|
||||
"CBAdvertisementData",
|
||||
"CBATTRequest",
|
||||
"NSArray",
|
||||
"NSMutableArray",
|
||||
"NSDictionary",
|
||||
"NSEnumerator",
|
||||
"NSSet",
|
||||
"NSDate",
|
||||
"NSTimeZone",
|
||||
"NSString",
|
||||
]
|
||||
Functions = [
|
||||
"NSMakeRange",
|
||||
]
|
||||
Enums = [
|
||||
"CB.*",
|
||||
]
|
||||
Frameworks = [
|
||||
"Foundation",
|
||||
"CoreBluetooth",
|
||||
]
|
||||
Imports = [
|
||||
"ble_delegate.h",
|
||||
]
|
||||
|
||||
Pragma = [ 'clang diagnostic ignored "-Wformat-security"' ]
|
||||
VaArgs = 32
|
35
examples/bluetooth/nswrap.yaml
Normal file
35
examples/bluetooth/nswrap.yaml
Normal file
|
@ -0,0 +1,35 @@
|
|||
package: ble
|
||||
inputfiles:
|
||||
- /System/Library/Frameworks/Foundation.framework/Headers/Foundation.h
|
||||
- /System/Library/Frameworks/CoreBluetooth.framework/Headers/CoreBluetooth.h
|
||||
- ble/ble_delegate.h
|
||||
|
||||
classes:
|
||||
- ble_delegate
|
||||
- CBCentralManager
|
||||
- CBPeripheralManager
|
||||
- CBPeripheral
|
||||
- CBCentral
|
||||
- CBService
|
||||
- CBCharacteristic
|
||||
- CBDescriptor
|
||||
- CBError
|
||||
- CBUUID
|
||||
- CBAdvertisementData
|
||||
- CBATTRequest
|
||||
- NSArray
|
||||
- NSMutableArray
|
||||
- NSDictionary
|
||||
- NSEnumerator
|
||||
- NSSet
|
||||
- NSDate
|
||||
- NSTimeZone
|
||||
- NSString
|
||||
|
||||
functions: [ NSMakeRange ]
|
||||
enums: [ CB.* ]
|
||||
frameworks: [ Foundation, CoreBluetooth ]
|
||||
imports: [ ble_delegate.h ]
|
||||
|
||||
pragma: [ clang diagnostic ignored "-Wformat-security" ]
|
||||
vaargs: 32
|
|
@ -1,28 +0,0 @@
|
|||
InputFiles = [
|
||||
"/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h",
|
||||
]
|
||||
Classes = [
|
||||
"NSArray",
|
||||
"NSMutableArray",
|
||||
"NSDictionary",
|
||||
"NSEnumerator",
|
||||
"NSSet",
|
||||
"NSDate",
|
||||
"NSTimeZone",
|
||||
"NSCalendar",
|
||||
"NSLocale",
|
||||
"NSCharacterSet",
|
||||
"NSString",
|
||||
"NSScanner",
|
||||
"NSFileManager",
|
||||
]
|
||||
Functions = [
|
||||
"NSMakeRange",
|
||||
]
|
||||
Enums = [
|
||||
"P_ALL",
|
||||
"CF.*",
|
||||
]
|
||||
Frameworks = [ "Foundation" ]
|
||||
Pragma = [ 'clang diagnostic ignored "-Wformat-security"' ]
|
||||
VaArgs = 32
|
21
examples/foundation/nswrap.yaml
Normal file
21
examples/foundation/nswrap.yaml
Normal file
|
@ -0,0 +1,21 @@
|
|||
inputfiles:
|
||||
- /System/Library/Frameworks/Foundation.framework/Headers/Foundation.h
|
||||
classes:
|
||||
- NSArray
|
||||
- NSMutableArray
|
||||
- NSDictionary
|
||||
- NSEnumerator
|
||||
- NSSet
|
||||
- NSDate
|
||||
- NSTimeZone
|
||||
- NSCalendar
|
||||
- NSLocale
|
||||
- NSCharacterSet
|
||||
- NSString
|
||||
- NSScanner
|
||||
- NSFileManager
|
||||
functions: [ NSMakeRange ]
|
||||
enums: [ P_ALL, CF.* ]
|
||||
frameworks: [ Foundation ]
|
||||
pragma: [ clang diagnostic ignored "-Wformat-security" ]
|
||||
vaargs: 32
|
|
@ -1,5 +0,0 @@
|
|||
Package = "ClassOne"
|
||||
InputFiles = [ "ClassOne/simple.h" ]
|
||||
Classes = [ "ClassOne","ClassTwo" ]
|
||||
Imports = [ "simple.h" ]
|
||||
Frameworks = [ "Foundation" ]
|
7
examples/simple/nswrap.yaml
Normal file
7
examples/simple/nswrap.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
package: ClassOne
|
||||
inputfiles: [ ClassOne/simple.h ]
|
||||
classes:
|
||||
- ClassOne
|
||||
- ClassTwo
|
||||
imports: [ simple.h ]
|
||||
frameworks: [ Foundation ]
|
105
wrap/main.go
105
wrap/main.go
|
@ -22,15 +22,17 @@ type Wrapper struct {
|
|||
Functions map[string]*Method
|
||||
NamedEnums map[string]*Enum
|
||||
AnonEnums []*Enum
|
||||
Protocols []*Protocol
|
||||
|
||||
cgoFlags strings.Builder // put cGo directives here
|
||||
cCode strings.Builder // put cGo code here
|
||||
goTypes strings.Builder // put Go type declarations here
|
||||
goConst strings.Builder // put Go constants (from C enums) here
|
||||
goCode strings.Builder // put Go code here
|
||||
goExports strings.Builder // put exported Go functions here
|
||||
goHelpers strings.Builder // put Go helper functions here
|
||||
Processed map[string]bool
|
||||
VaArgs int
|
||||
Vaargs int
|
||||
}
|
||||
|
||||
func NewWrapper(debug bool) *Wrapper {
|
||||
|
@ -41,8 +43,9 @@ func NewWrapper(debug bool) *Wrapper {
|
|||
Functions: map[string]*Method{},
|
||||
NamedEnums: map[string]*Enum{},
|
||||
AnonEnums: []*Enum{},
|
||||
Protocols: []*Protocol{},
|
||||
Processed: map[string]bool{},
|
||||
VaArgs: 16,
|
||||
Vaargs: 16,
|
||||
}
|
||||
ret.cgoFlags.WriteString(fmt.Sprintf(`/*
|
||||
#cgo CFLAGS: -x objective-c
|
||||
|
@ -105,6 +108,12 @@ type Enum struct {
|
|||
Constants []string
|
||||
}
|
||||
|
||||
type Protocol struct {
|
||||
Name, GoName string
|
||||
Methods []*Method
|
||||
Polymorphic map[string]bool
|
||||
}
|
||||
|
||||
//isVoid() returns true if the method has no return value.
|
||||
func (m Method) isVoid() bool {
|
||||
return m.Type.CType() == "void"
|
||||
|
@ -152,7 +161,7 @@ func (w Wrapper) objcparamlist(m *Method) string {
|
|||
} else {
|
||||
if p.Type.Variadic {
|
||||
str := []string{m.Name + ":arr[0]"}
|
||||
for i := 1; i < w.VaArgs; i++ {
|
||||
for i := 1; i < w.Vaargs; i++ {
|
||||
str = append(str,"arr["+strconv.Itoa(i)+"]")
|
||||
}
|
||||
str = append(str,"nil")
|
||||
|
@ -268,6 +277,40 @@ func (w *Wrapper) AddFunction(n *ast.FunctionDecl) {
|
|||
w.Functions[n.Name] = m
|
||||
}
|
||||
|
||||
func (w *Wrapper) AddProtocol(n *ast.ObjCProtocolDecl) {
|
||||
p := &Protocol{
|
||||
Name: n.Name,
|
||||
GoName: types.NewTypeFromString(n.Name,n.Name).GoType(),
|
||||
Methods: []*Method{},
|
||||
Polymorphic: map[string]bool{},
|
||||
}
|
||||
seen := make(map[string]bool)
|
||||
fmt.Printf("Adding protocol %s\n",n.Name)
|
||||
for _,c := range n.Children() {
|
||||
switch x := c.(type) {
|
||||
case *ast.ObjCMethodDecl:
|
||||
m := &Method{
|
||||
Name: x.Name,
|
||||
Type: types.NewTypeFromString(x.Type,p.Name),
|
||||
Class: p.Name,
|
||||
GoClass: p.GoName,
|
||||
ClassMethod: x.ClassMethod,
|
||||
}
|
||||
var avail bool
|
||||
m.Parameters, avail = w.GetParms(x,p.Name)
|
||||
if avail {
|
||||
fmt.Printf(" method %s\n",m.Name)
|
||||
p.Methods = append(p.Methods,m)
|
||||
if seen[m.Name] {
|
||||
p.Polymorphic[m.Name] = true
|
||||
}
|
||||
seen[m.Name] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
w.Protocols = append(w.Protocols,p)
|
||||
}
|
||||
|
||||
//FIXME: copied from nswrap/main.go, should put this in a utils package
|
||||
func matches(x string, rs []string) bool {
|
||||
for _,r := range rs {
|
||||
|
@ -680,7 +723,7 @@ func %s%s(%s) %s {
|
|||
for i,o := range %ss {
|
||||
%s[i] = o.Ptr()
|
||||
}
|
||||
`,vn,w.VaArgs,vn,vn))
|
||||
`,vn,w.Vaargs,vn,vn))
|
||||
}
|
||||
w.goCode.WriteString(` ` +
|
||||
types.GoToC(cname,ns,m.Type,tps) + "\n}\n")
|
||||
|
@ -781,6 +824,57 @@ const %s %s= C.%s
|
|||
}
|
||||
}
|
||||
|
||||
//FIXME: need to disambiguate polymorphic method names. Something like:
|
||||
//func Disambiguate([]*Method) []*Method {} ...
|
||||
//Can allow user to decide on a disambiguation strategy
|
||||
func (w *Wrapper) ProcessProtocol(p *Protocol) {
|
||||
fmt.Printf("Processing protocol (%s)\n",p.Name)
|
||||
//To create (per protocol):
|
||||
//1. ObjC protocol interface
|
||||
//2. ObjC protocol implementation
|
||||
//3. Go type
|
||||
//4. Go constructor
|
||||
//5. Go dispatch database for callbacks
|
||||
//To create (per method):
|
||||
//1. ObjC function prototypes for go exports
|
||||
//2. ObjC constructor function
|
||||
//3. Go exported callback function wrappers
|
||||
|
||||
var ccode, gocode, goexports strings.Builder
|
||||
//1. ObjC protocol interface
|
||||
ccode.WriteString(fmt.Sprintf(`
|
||||
@interface %s : %s
|
||||
`,p.Name,p.Name))
|
||||
//2. ObjC protocol implementation
|
||||
ccode.WriteString(fmt.Sprintf(`
|
||||
`))
|
||||
//3. Go type
|
||||
gocode.WriteString(fmt.Sprintf(`
|
||||
`))
|
||||
//4. Go constructor
|
||||
gocode.WriteString(fmt.Sprintf(`
|
||||
`))
|
||||
//5. Go dispatch database for callbacks
|
||||
gocode.WriteString(fmt.Sprintf(`
|
||||
`))
|
||||
//6. Go callback registration function
|
||||
gocode.WriteString(fmt.Sprintf(`
|
||||
`))
|
||||
//To create (per method):
|
||||
for _,m := range p.Methods {
|
||||
_ = m
|
||||
//1. ObjC function prototypes for go exports
|
||||
ccode.WriteString(fmt.Sprintf(`
|
||||
`))
|
||||
//2. ObjC constructor function
|
||||
ccode.WriteString(fmt.Sprintf(`
|
||||
`))
|
||||
//3. Go exported callback function wrappers
|
||||
goexports.WriteString(fmt.Sprintf(`
|
||||
`))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Wrapper) Wrap(toproc []string) {
|
||||
if w.Package == "" { w.Package = "ns" }
|
||||
err := os.MkdirAll(w.Package,0755)
|
||||
|
@ -851,6 +945,9 @@ void*
|
|||
for _,e := range w.AnonEnums {
|
||||
w.ProcessEnum(e)
|
||||
}
|
||||
for _,p := range w.Protocols {
|
||||
w.ProcessProtocol(p)
|
||||
}
|
||||
fmt.Printf("%d functions\n", len(w.Functions))
|
||||
fmt.Printf("%d enums\n", len(w.NamedEnums) + len(w.AnonEnums))
|
||||
of.WriteString("package " + w.Package + "\n\n")
|
||||
|
|
Loading…
Reference in New Issue
Block a user