Subclasses can have new methods in addition to overriding existing

methods (first draft).
This commit is contained in:
Greg 2019-05-24 12:36:01 -04:00
parent 38c7856b89
commit 34fbcec965
3 changed files with 151 additions and 37 deletions

View File

@ -7,7 +7,8 @@ subclasses:
ClassThree:
ClassTwo:
- geti1
- (void)myMethod:int
- -(void)myMethod1:(int)a
- +(const NSObject* _Nonnull)myMethod2:(int)a:(NSDictionary<NSString*,NSObject*> *)options
imports: [ simple.h ]
frameworks: [ Foundation ]

View File

@ -32,6 +32,26 @@ func init() {
//TypeName = _TypeName
}
func MethodSignature(s string, n *Node) (string, *Node) {
return ChildOf(NewNode("MethodSignature"),Seq(
Parenthesized(TypeName),
Identifier,
Opt(MethodParameterList),
))(s,n)
}
func MethodParameterList(s string, n *Node) (string, *Node) {
return OneOrMore(MethodParameter)(s,n)
}
func MethodParameter(s string, n *Node) (string, *Node) {
return ChildOf(NewNode("MethodParameter"),Seq(
Lit(":"),
Parenthesized(TypeName),
Identifier,
))(s,n)
}
func _TypeName(s string, n *Node) (string, *Node) {
return ChildOf(NewNode("TypeName"),Seq(
SpecifierQualifierList,

View File

@ -23,7 +23,7 @@ type Wrapper struct {
NamedEnums map[string]*Enum
AnonEnums []*Enum
Delegates map[string]map[string][]string
Subclasses map[string]map[string][]string
Subclasses map[string]*Subclass
Protocols map[string]*Protocol
cgoFlags strings.Builder // put cGo directives here
@ -49,6 +49,7 @@ func NewWrapper(debug bool) *Wrapper {
NamedEnums: map[string]*Enum{},
AnonEnums: []*Enum{},
Protocols: map[string]*Protocol{},
Subclasses: map[string]*Subclass{},
ProcessedTypes: map[string]bool{},
ProcessedClassMethods: map[string]bool{},
Vaargs: 16,
@ -98,7 +99,39 @@ func (w *Wrapper) Delegate(ds map[string]map[string][]string) {
}
func (w *Wrapper) Subclass(ds map[string]map[string][]string) {
w.Subclasses = ds
for k,v := range ds {
sc := &Subclass{
Overrides: []string{},
NewMethods: []string{},
}
if len(ds) == 0 {
fmt.Printf("No superclass specified for subclass %s\n",k)
os.Exit(-1)
}
if len(ds) > 1 {
fmt.Printf("Multiple inheritance not permitted for subclass %s\n",k)
os.Exit(-1)
}
sc.Name = k
for x,y := range(v) {
sc.Super = x
for _,m := range y {
switch m[0] {
case '-','+':
sc.NewMethods = append(sc.NewMethods,m)
default:
sc.Overrides = append(sc.Overrides,m)
}
}
}
w.Subclasses[sc.Name] = sc
}
}
type Subclass struct {
Name,Super string
Overrides []string
NewMethods []string
}
type Property struct {
@ -752,13 +785,13 @@ func (w *Wrapper) _processMethod(m *Method,fun bool) {
return
}
w.processType(m.Type)
//w.processType(m.GoClass) //??
gname := m.Name
gname = strings.ReplaceAll(gname,"_"," ")
gname = strings.Title(gname)
gname = strings.ReplaceAll(gname," ","")
receiver := ""
cname := m.Name
fmt.Printf("Method %s (GoClass %s)\n",cname,m.GoClass)
switch {
case !m.ClassMethod:
if types.IsGoInterface(m.GoClass) {
@ -943,16 +976,63 @@ type %s %s
w.goConst.WriteString("\n")
}
func (w *Wrapper) ProcessSubclass(sname string, ps map[string][]string) {
w._ProcessDelSub(sname,ps,true)
func (w *Wrapper) MethodFromSig(sig,class string) *Method {
ret := &Method{ Parameters: []*Parameter{} }
if len(sig) == 0 {
return ret
}
if sig[0] == '+' {
ret.ClassMethod = true
}
sig = sig[1:]
rem,n := types.MethodSignature(sig,types.NewNode("AST"))
if len(rem) > 0 {
fmt.Printf("Failed to parse method signature %s (%s)\n",sig,rem)
os.Exit(-1)
}
for _,c := range n.Children {
switch c.Kind {
case "TypeName":
tp := types.NewType(c,class)
ret.Type = tp
case "Identifier":
ret.Name = c.Content
case "MethodParameter":
p := &Parameter{}
for _,d := range c.Children {
switch d.Kind {
case "TypeName":
tp := types.NewType(d,class)
p.Type = tp
case "Identifier":
p.Vname = d.Content
}
}
ret.Parameters = append(ret.Parameters,p)
}
}
return ret
}
func (w *Wrapper) ProcessSubclass(sname string, sc *Subclass) {
fmt.Printf("Wrapping %s\n",sname)
types.Wrap(sname)
types.SetSuper(sname,sc.Super)
ps := map[string][]string{}
ps[sc.Super] = sc.Overrides
nms := make([]*Method,len(sc.NewMethods))
for i,sig := range sc.NewMethods {
nms[i] = w.MethodFromSig(sig,sname)
}
w._ProcessDelSub(sname,ps,nms,true)
}
func (w *Wrapper) ProcessDelegate(dname string, ps map[string][]string) {
w._ProcessDelSub(dname,ps,false)
w._ProcessDelSub(dname,ps,nil,false)
}
//NOTE: The delegate wrapper does not support variadic callback functions.
func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool) {
func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string, nms []*Method, sub bool) {
//To create (per delegate):
//1. ObjC interface
//2. ObjC implementation
@ -972,6 +1052,7 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool)
//set up array of methods for this delegate
methods := []*Method{}
sms := 0 // the number of methods that have super-methods
gnames := []string{} // go names for methods
pnames := make([]string,len(ps))
var supr string
@ -998,14 +1079,14 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool)
if sup := types.Super(s); w.Interfaces[sup] != nil {
addmeths(sup)
}
fmt.Printf("Adding methods for %s\n",s)
//fmt.Printf("Adding methods for %s\n",s)
for k,v := range w.Interfaces[s].InstanceMethods {
ms[k] = v
}
}
//for subclasses, add all superclass methods, depth first
addmeths(interf.Name)
} else {
} else { // not a subclass
proto := w.Protocols[pname]
if proto == nil {
fmt.Printf("Failed to find protocol %s for delegate %s\n",pname,dname)
@ -1019,9 +1100,6 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool)
//note:we may have capitalized the first character to make a goname,
//but m.Name is not disambiguated for polymorphics...
if !matches(string(m.Name[0])+gname[1:],pats) {
if sub {
//Add newly defined methods that don't match anything...
}
continue
}
if m.Type.IsFunction() || m.Type.IsFunctionPtr() || m.hasFunctionParam() {
@ -1029,12 +1107,20 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool)
}
methods = append(methods,m)
gnames = append(gnames,gname)
if sub { sms = len(methods) }
}
}
//add new methods being defined for the subclass
if sub {
for _,m := range nms {
methods = append(methods,m)
gnames = append(gnames,strings.Title(m.Name))
}
}
methprotos := make([]string,len(methods)) // objc method prototypes
smethprotos := make([]string,len(methods)) // super method prototypes
sfunprotos := make([]string,len(methods)) // super method prototypes
smethprotos := make([]string,sms) // super method prototypes
sfunprotos := make([]string,sms) // super method prototypes
gname := strings.Title(dname) // go name for this Delegate
vnames := make([][]string,len(methods)) // objc variable names
vpnames := make([][]string,len(methods)) // objc parameter:variable names
@ -1046,11 +1132,10 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool)
//1. ObjC interface
if sub {
fmt.Printf("Subclass ")
fmt.Printf("Subclass %s <%s>: %d overrides, %d new methods\n",dname,strings.Join(pnames,", "),sms, len(nms))
} else {
fmt.Printf("Delegate ")
fmt.Printf("Delegate %s <%s>: %d methods\n",dname,strings.Join(pnames,", "),len(methods))
}
fmt.Printf("%s <%s>: %d methods\n",dname,strings.Join(pnames,", "),len(methods))
for i,m := range methods {
w.processType(m.Type)
vnames[i] = make([]string,len(m.Parameters)+1)
@ -1100,13 +1185,17 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool)
methprotos[i] = fmt.Sprintf(
`- (%s)%s%s;`,m.Type.Node.CType(),m.Name,parms)
ct := m.Type.Node.CType()
smethprotos[i] = fmt.Sprintf(
if i < sms {
smethprotos[i] = fmt.Sprintf(
`- (%s)super_%s%s;`,ct,m.Name,parms)
}
if ct == "instancetype" {
ct = gname + "*"
}
sfunprotos[i] = fmt.Sprintf(
if i < sms {
sfunprotos[i] = fmt.Sprintf(
`%s %s_super_%s(%s);`,ct,dname,m.Name,cparms)
}
if x := m.Type.GoType(); x == "Void" {
grtypes[i] = ""
} else {
@ -1150,8 +1239,11 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool)
sfundecls := make([]string,len(methods))
for i,mp := range methprotos {
mp := mp[:len(mp)-1]
smp := smethprotos[i][:len(smethprotos[i])-1]
sfp := sfunprotos[i][:len(sfunprotos[i])-1]
var smp, sfp string
if sub && i < sms {
smp = smethprotos[i][:len(smethprotos[i])-1]
sfp = sfunprotos[i][:len(sfunprotos[i])-1]
}
var ret string
if crtypes[i] != "void" {
ret = "return "
@ -1168,7 +1260,7 @@ func (w *Wrapper) _ProcessDelSub(dname string, ps map[string][]string,sub bool)
%s%s(%s);
}
`,mp,ret,gname + gnames[i],strings.Join(vnames[i],", "))
if sub {
if sub && i < sms {
smethdecls[i] = fmt.Sprintf(`
%s
{
@ -1207,10 +1299,8 @@ void*
//4. Go type
gotypes.WriteString(fmt.Sprintf(`
type %s struct { %s }
func (o %s) Ptr() unsafe.Pointer { return o.ptr }
`,gname,supr,gname))
gotypes.WriteString(
types.NewTypeFromString(gname,supr).GoInterfaceDecl())
//5. Go constructor
gocode.WriteString(fmt.Sprintf(`
@ -1223,14 +1313,14 @@ func %sAlloc() %s {
//6. Go dispatch database for callbacks
dispitems := make([]string,len(gnames))
sdispitems := make([]string,len(gnames))
sdispitems := make([]string,sms)
for i,n := range gnames {
if !sub {
gtypes[i] = gtypes[i][1:]
}
dispitems[i] = fmt.Sprintf(
` %s func(%s)%s`,n,strings.Join(gtypes[i],", "),grtypes[i])
if sub {
if sub && i < sms {
sdispitems[i] = fmt.Sprintf(
` %s func(%s)%s`,n,strings.Join(gtypes[i][1:],", "),grtypes[i])
}
@ -1259,7 +1349,7 @@ type %sSupermethods struct {
`,crtypes[i],gname,gnames[i],ctps))
//2. Go callback registration functions
gocode.WriteString(fmt.Sprintf(`
func (d *%s) %sCallback(f func(%s)%s) {
func (d %s) %sCallback(f func(%s)%s) {
dispatch := %sLookup[d.Ptr()]
dispatch.%s = f
%sLookup[d.Ptr()] = dispatch
@ -1304,16 +1394,19 @@ func (d *%s) %sCallback(f func(%s)%s) {
if cgtypes[i] == "unsafe.Pointer" {
retn = "return unsafe.Pointer("
crtype = " unsafe.Pointer"
if types.ShouldWrap(m.Type.GoType()) {
retnparen = ".Ptr()"
}
} else {
retn = "return (" + cgtypes[i] + ")("
crtype = " " + cgtypes[i]
}
retnparen = ")"
retnparen = retnparen + ")"
}
sdispentries := []string{}
for _,n := range gnames {
sdispentries = append(sdispentries,fmt.Sprintf(
` self.Super%s`,n))
sdispentries := make([]string,sms)
for i,_ := range sdispentries {
sdispentries[i] = fmt.Sprintf(
` self.Super%s`,gnames[i])
}
sper := ""
if sub && len(gnames) > 0 {
@ -1338,7 +1431,7 @@ func %s%s(%s)%s {
}
`,gname,gnames[i],gname,gnames[i],strings.Join(earglist,", "),crtype,retdecl,gname,gnames[i],retname,sper,strings.Join(gargconv,"\n"),retn,strings.Join(garglist,", "),retnparen))
//4. Go wrapper functions for superclass methods
if !sub { continue } // for subclasses only
if !sub || i >= sms { continue } // for subclasses only
grtype := m.Type.GoType()
if grtype == "Void" {
grtype = ""
@ -1351,7 +1444,7 @@ func %s%s(%s)%s {
}
if sub {
gocode.WriteString(fmt.Sprintf(`
func (o *%s) Super%s(%s) %s {
func (o %s) Super%s(%s) %s {
`,gname,gnames[i],strings.Join(earglist[1:],", "), grtype))
ns,tps,_ := w.gpntp(m)
lparm := len(tps)-1